Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion DESCRIPTION
Original file line number Diff line number Diff line change
Expand Up @@ -35,5 +35,5 @@ License: GPL (>= 3)
URL: https://rcppcore.github.io/RcppParallel/, https://github.com/RcppCore/RcppParallel
BugReports: https://github.com/RcppCore/RcppParallel/issues
Biarch: TRUE
RoxygenNote: 7.3.2
RoxygenNote: 7.3.3
Encoding: UTF-8
1 change: 1 addition & 0 deletions NAMESPACE
Original file line number Diff line number Diff line change
Expand Up @@ -5,5 +5,6 @@ export(LdFlags)
export(RcppParallel.package.skeleton)
export(RcppParallelLibs)
export(defaultNumThreads)
export(isForkedChild)
export(setThreadOptions)
export(tbbLibraryPath)
7 changes: 7 additions & 0 deletions NEWS.md
Original file line number Diff line number Diff line change
@@ -1,6 +1,13 @@

## RcppParallel 6.0.0 (UNRELEASED)

* RcppParallel now provides `isForkedChild()` (R) and
`RcppParallel::isForkedChild()` (C++), which return `TRUE` when the current
process is a `fork()` of the process in which RcppParallel was loaded.
Packages dispatching parallel work from within `parallel::mclapply()` (or
similar) should consult this and fall back to a serial path, as TBB does
not support use after fork. (#243)

* RcppParallel no longer includes tbb headers as part of the RcppParallel/TBB.h
header, and instead only exposes its TBB-specific APIs for parallel work.

Expand Down
26 changes: 26 additions & 0 deletions R/fork.R
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
#' Is the Current Process a Forked Child?
#'
#' Returns `TRUE` if the current process is a `fork()` of the process in which
#' RcppParallel was originally loaded.
#'
#' Intel TBB — the parallel backend used by `parallelFor()` and
#' `parallelReduce()` — does not support being used in a child process after
#' `fork()`. Packages that may be invoked from within `parallel::mclapply()`
#' or similar fork-based parallelism should call `isForkedChild()` and fall
#' back to a serial code path when it returns `TRUE`.
#'
#' On Windows, which has no `fork()`, this always returns `FALSE`.
#'
#' @return A length-one logical.
#'
#' @examples
#' \dontrun{
#' library(RcppParallel)
#' isForkedChild()
#' parallel::mclapply(1:2, function(i) RcppParallel::isForkedChild())
#' }
#'
#' @export
isForkedChild <- function() {
.Call("isForkedChild", PACKAGE = "RcppParallel")
}
1 change: 1 addition & 0 deletions inst/include/RcppParallel.h
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@
#endif

#include "RcppParallel/Backend.h"
#include "RcppParallel/Fork.h"
#include "RcppParallel/RVector.h"
#include "RcppParallel/RMatrix.h"

Expand Down
17 changes: 17 additions & 0 deletions inst/include/RcppParallel/Fork.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
#ifndef __RCPP_PARALLEL_FORK__
#define __RCPP_PARALLEL_FORK__

namespace RcppParallel {

// Returns true if the current process is a fork() of the process in which
// RcppParallel was originally loaded. Always returns false on Windows, which
// has no fork().
//
// Intel TBB does not support being used after fork(). Code paths reachable
// from fork()'d children (for example, via parallel::mclapply) should call
// this and fall back to a serial implementation when it returns true.
bool isForkedChild();

} // namespace RcppParallel

#endif // __RCPP_PARALLEL_FORK__
32 changes: 32 additions & 0 deletions man/isForkedChild.Rd

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

35 changes: 34 additions & 1 deletion src/init.cpp
Original file line number Diff line number Diff line change
@@ -1,19 +1,52 @@

#include <R.h>
#include <Rinternals.h>
#include <stdlib.h> // for NULL
#include <R_ext/Rdynload.h>

#ifndef _WIN32
# include <sys/types.h>
# include <unistd.h>
#endif

namespace RcppParallel {

#ifndef _WIN32
static pid_t s_loadPid = 0;

bool isForkedChild()
{
return getpid() != s_loadPid;
}
#else
bool isForkedChild()
{
return false;
}
#endif

} // namespace RcppParallel

/* .Call calls */
extern "C" SEXP defaultNumThreads();

extern "C" SEXP isForkedChild()
{
int forked = RcppParallel::isForkedChild() ? TRUE : FALSE;
return Rf_ScalarLogical(forked);
}

static const R_CallMethodDef CallEntries[] = {
{"defaultNumThreads", (DL_FUNC) &defaultNumThreads, 0},
{"isForkedChild", (DL_FUNC) &isForkedChild, 0},
{NULL, NULL, 0}
};

extern "C" void R_init_RcppParallel(DllInfo *dll)
{
#ifndef _WIN32
RcppParallel::s_loadPid = getpid();
#endif

R_registerRoutines(dll, NULL, CallEntries, NULL, NULL);
R_useDynamicSymbols(dll, FALSE);
}
Loading