Skip to content

Commit c276b03

Browse files
authored
provide some backwards compatibility with existing binaries (#233)
* first steps at backwards compat * more exports for linux * include stub library on Windows * tweaks * dll export * clean up when we're done * overwrite
1 parent 965e198 commit c276b03

File tree

17 files changed

+378
-25
lines changed

17 files changed

+378
-25
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 (libNameinlibNames) {
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

+18-8
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 building 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) {
@@ -99,7 +112,7 @@ useBundledTbb <- function() {
99112
"-DTBB_EXAMPLES=0",
100113
"-DTBB_STRICT=0",
101114
".."
102-
)
115+
)
103116

104117
writeLines("*** configuring tbb")
105118
owd<- setwd("tbb/build-tbb")
@@ -133,17 +146,14 @@ useBundledTbb <- function() {
133146
)
134147

135148
tbbFiles<- list.files(
136-
"tbb/build-tbb",
149+
file.path(getwd(), "tbb/build-tbb"),
137150
pattern=shlibPattern,
138151
recursive=TRUE,
139152
full.names=TRUE
140153
)
141154

142-
tbbDir<- dirname(tbbFiles[[1L]])
143-
144-
dir.create("tbb/build", showWarnings=FALSE)
145-
unlink("tbb/build/lib_release", recursive=TRUE)
146-
file.rename(tbbDir, "tbb/build/lib_release")
155+
dir.create("tbb/build/lib_release", recursive=TRUE, showWarnings=FALSE)
156+
file.copy(tbbFiles, "tbb/build/lib_release", overwrite=TRUE)
147157
unlink("tbb/build-tbb", recursive=TRUE)
148158
writeLines("*** finished building tbb")
149159

src/tbb-compat/tbb-compat.cpp

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

0 commit comments

Comments
 (0)
close