Skip to content

Commit dad89c9

Browse files
committed
include stub library on Windows
1 parent a6e97f4 commit dad89c9

File tree

7 files changed

+173
-5
lines changed

7 files changed

+173
-5
lines changed

R/tbb.R

+8
Original file line numberDiff line numberDiff line change
@@ -37,9 +37,17 @@ tbbLibraryPath <- function(name = NULL) {
3737
# find the request library (if any)
3838
libNames <- tbbLibNames[[sysname]]
3939
for (libName in libNames) {
40+
4041
tbbName <- file.path(tbbRoot, libName)
4142
if (file.exists(tbbName))
4243
return(tbbName)
44+
45+
arch <- if (nzchar(.Platform$r_arch)) .Platform$r_arch
46+
suffix <- paste(c("lib", arch, libName), collapse = "/")
47+
tbbName <- system.file(suffix, package = "RcppParallel")
48+
if (file.exists(tbbName))
49+
return(tbbName)
50+
4351
}
4452

4553
}

R/zzz.R

+8-1
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,11 @@ loadTbbLibrary <- function(name) {
2727

2828
.onLoad <- function(libname, pkgname) {
2929

30+
# on Windows, load RcppParallel first
31+
if (.Platform$OS.type == "windows") {
32+
.dllInfo <<- library.dynam("RcppParallel", pkgname, libname)
33+
}
34+
3035
# load tbb, tbbmalloc
3136
.tbbDllInfo <<- loadTbbLibrary("tbb")
3237
.tbbMallocDllInfo <<- loadTbbLibrary("tbbmalloc")
@@ -37,7 +42,9 @@ loadTbbLibrary <- function(name) {
3742
.tbbMallocProxyDllInfo <<- loadTbbLibrary("tbbmalloc_proxy")
3843

3944
# load RcppParallel library if available
40-
.dllInfo <<- library.dynam("RcppParallel", pkgname, libname)
45+
if (.Platform$OS.type != "windows") {
46+
.dllInfo <<- library.dynam("RcppParallel", pkgname, libname)
47+
}
4148

4249
}
4350

RcppParallel.Rproj

+1
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@ RnwWeave: Sweave
1414
LaTeX: pdfLaTeX
1515

1616
BuildType: Package
17+
PackageCleanBeforeInstall: No
1718
PackageInstallArgs: --with-keep.source --clean
1819
PackageCheckArgs: --as-cran
1920
PackageRoxygenize: rd,collate,namespace

src/install.libs.R

+15-2
Original file line numberDiff line numberDiff line change
@@ -57,7 +57,7 @@
5757
tbbLibs <- tbbLibs[!nzchar(Sys.readlink(tbbLibs))]
5858

5959
# copy / link the libraries
60-
useSymlinks <- Sys.getenv("TBB_USE_SYMLINKS", unset = "TRUE")
60+
useSymlinks <- Sys.getenv("TBB_USE_SYMLINKS", unset = .Platform$OS.type != "windows")
6161
if (useSymlinks) {
6262
file.symlink(tbbLibs, tbbDest)
6363
} else {
@@ -68,6 +68,19 @@
6868

6969
}
7070

71+
# on Windows, we create a stub library that links to us so that
72+
# older binaries (like rstan) can still load
73+
if (.Platform$OS.type == "windows") {
74+
tbbDll <- file.path(tbbDest, "tbb.dll")
75+
if (!file.exists(tbbDll)) {
76+
writeLines("** creating tbb stub library")
77+
status <- system("R CMD SHLIB tbb-compat/tbb-compat.cpp")
78+
if (status != 0)
79+
stop("error build tbb stub library")
80+
file.rename("tbb-compat/tbb-compat.dll", file.path(tbbDest, "tbb.dll"))
81+
}
82+
}
83+
7184
}
7285

7386
useTbbPreamble <- function(tbbInc) {
@@ -81,7 +94,7 @@ useTbbPreamble <- function(tbbInc) {
8194
}
8295

8396
useSystemTbb <- function(tbbLib, tbbInc) {
84-
useTbbPreamble(tbbInc)
97+
writeLines("** using system-provided tbb installation")
8598
}
8699

87100
useBundledTbb <- function() {

src/tbb-compat/tbb-compat.cpp

+137
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,137 @@
1+
2+
#include <atomic>
3+
4+
#include "../tbb/include/oneapi/tbb/detail/_namespace_injection.h"
5+
#include "../tbb/include/oneapi/tbb/task_arena.h"
6+
7+
#include "../tbb/src/tbb/observer_proxy.h"
8+
#include "../tbb/src/tbb/main.h"
9+
#include "../tbb/src/tbb/thread_data.h"
10+
11+
namespace tbb {
12+
13+
namespace interface6 {
14+
class task_scheduler_observer;
15+
}
16+
17+
namespace internal {
18+
19+
class task_scheduler_observer_v3 {
20+
friend class tbb::detail::r1::observer_proxy;
21+
friend class tbb::detail::r1::observer_list;
22+
friend class interface6::task_scheduler_observer;
23+
24+
//! Pointer to the proxy holding this observer.
25+
/** Observers are proxied by the scheduler to maintain persistent lists of them. **/
26+
tbb::detail::r1::observer_proxy* my_proxy;
27+
28+
//! Counter preventing the observer from being destroyed while in use by the scheduler.
29+
/** Valid only when observation is on. **/
30+
std::atomic<intptr_t> my_busy_count;
31+
32+
public:
33+
//! Enable or disable observation
34+
/** For local observers the method can be used only when the current thread
35+
has the task scheduler initialized or is attached to an arena.
36+
Repeated calls with the same state are no-ops. **/
37+
void __TBB_EXPORTED_METHOD observe( bool state=true );
38+
39+
//! Returns true if observation is enabled, false otherwise.
40+
bool is_observing() const {return my_proxy!=NULL;}
41+
42+
//! Construct observer with observation disabled.
43+
task_scheduler_observer_v3() : my_proxy(NULL) { my_busy_count.store(0); }
44+
45+
//! Entry notification
46+
/** Invoked from inside observe(true) call and whenever a worker enters the arena
47+
this observer is associated with. If a thread is already in the arena when
48+
the observer is activated, the entry notification is called before it
49+
executes the first stolen task.
50+
Obsolete semantics. For global observers it is called by a thread before
51+
the first steal since observation became enabled. **/
52+
virtual void on_scheduler_entry( bool /*is_worker*/ ) {}
53+
54+
//! Exit notification
55+
/** Invoked from inside observe(false) call and whenever a worker leaves the
56+
arena this observer is associated with.
57+
Obsolete semantics. For global observers it is called by a thread before
58+
the first steal since observation became enabled. **/
59+
virtual void on_scheduler_exit( bool /*is_worker*/ ) {}
60+
61+
//! Destructor automatically switches observation off if it is enabled.
62+
virtual ~task_scheduler_observer_v3() { if(my_proxy) observe(false);}
63+
};
64+
65+
} // namespace internal
66+
67+
namespace interface6 {
68+
69+
class task_scheduler_observer : public internal::task_scheduler_observer_v3 {
70+
friend class internal::task_scheduler_observer_v3;
71+
friend class tbb::detail::r1::observer_proxy;
72+
friend class tbb::detail::r1::observer_list;
73+
74+
/** Negative numbers with the largest absolute value to minimize probability
75+
of coincidence in case of a bug in busy count usage. **/
76+
// TODO: take more high bits for version number
77+
static const intptr_t v6_trait = (intptr_t)((~(uintptr_t)0 >> 1) + 1);
78+
79+
//! contains task_arena pointer or tag indicating local or global semantics of the observer
80+
intptr_t my_context_tag;
81+
enum { global_tag = 0, implicit_tag = 1 };
82+
83+
public:
84+
//! Construct local or global observer in inactive state (observation disabled).
85+
/** For a local observer entry/exit notifications are invoked whenever a worker
86+
thread joins/leaves the arena of the observer's owner thread. If a thread is
87+
already in the arena when the observer is activated, the entry notification is
88+
called before it executes the first stolen task. **/
89+
/** TODO: Obsolete.
90+
Global observer semantics is obsolete as it violates master thread isolation
91+
guarantees and is not composable. Thus the current default behavior of the
92+
constructor is obsolete too and will be changed in one of the future versions
93+
of the library. **/
94+
explicit task_scheduler_observer( bool local = false ) {
95+
my_context_tag = local? implicit_tag : global_tag;
96+
}
97+
98+
//! Construct local observer for a given arena in inactive state (observation disabled).
99+
/** entry/exit notifications are invoked whenever a thread joins/leaves arena.
100+
If a thread is already in the arena when the observer is activated, the entry notification
101+
is called before it executes the first stolen task. **/
102+
explicit task_scheduler_observer( task_arena & a) {
103+
my_context_tag = (intptr_t)&a;
104+
}
105+
106+
/** Destructor protects instance of the observer from concurrent notification.
107+
It is recommended to disable observation before destructor of a derived class starts,
108+
otherwise it can lead to concurrent notification callback on partly destroyed object **/
109+
virtual ~task_scheduler_observer() { if(my_proxy) observe(false); }
110+
111+
//! Enable or disable observation
112+
/** Warning: concurrent invocations of this method are not safe.
113+
Repeated calls with the same state are no-ops. **/
114+
void observe( bool state=true ) {
115+
if( state && !my_proxy ) {
116+
__TBB_ASSERT( !my_busy_count, "Inconsistent state of task_scheduler_observer instance");
117+
my_busy_count.store(v6_trait);
118+
}
119+
internal::task_scheduler_observer_v3::observe(state);
120+
}
121+
};
122+
123+
} // namespace interface6
124+
125+
} // namespace tbb
126+
127+
namespace tbb {
128+
namespace internal {
129+
130+
__declspec(dllexport)
131+
void __TBB_EXPORTED_FUNC task_scheduler_observer_v3::observe( bool enable ) {
132+
auto* tso = (tbb::detail::d1::task_scheduler_observer*) (this);
133+
tbb::detail::r1::observe(*tso, enable);
134+
}
135+
136+
} // namespace internal
137+
} // namespace tbb

src/tbb/include/oneapi/tbb/detail/_task.h

+3-1
Original file line numberDiff line numberDiff line change
@@ -124,12 +124,14 @@ class wait_context {
124124
}
125125
}
126126

127+
public:
127128
bool continue_execution() const {
128129
std::uint64_t r = m_ref_count.load(std::memory_order_acquire);
129130
__TBB_ASSERT_EX((r & overflow_mask) == 0, "Overflow is detected");
130131
return r > 0;
131132
}
132-
133+
134+
private:
133135
friend class r1::thread_data;
134136
friend class r1::task_dispatcher;
135137
friend class r1::external_waiter;

tools/config/configure.R

+1-1
Original file line numberDiff line numberDiff line change
@@ -316,7 +316,7 @@ if (.Platform$OS.type == "windows" && is.na(tbbLib)) {
316316
define(PKG_CXXFLAGS = "-DRCPP_PARALLEL_USE_TBB=0")
317317
} else {
318318
define(TBB_ENABLED = TRUE)
319-
define(PKG_CXXFLAGS = "-DRCPP_PARALLEL_USE_TBB=1")
319+
define(PKG_CXXFLAGS = "-DRCPP_PARALLEL_USE_TBB=1 -DRCPP_PARALLEL_TBB_COMPAT=1")
320320
}
321321

322322
# macOS needs some extra flags set

0 commit comments

Comments
 (0)