1 /*
2 Copyright (c) 2005-2020 Intel Corporation
3
4 Licensed under the Apache License, Version 2.0 (the "License");
5 you may not use this file except in compliance with the License.
6 You may obtain a copy of the License at
7
8 http://www.apache.org/licenses/LICENSE-2.0
9
10 Unless required by applicable law or agreed to in writing, software
11 distributed under the License is distributed on an "AS IS" BASIS,
12 WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 See the License for the specific language governing permissions and
14 limitations under the License.
15 */
16
17 #include "tbb/tbb_config.h"
18 #include "tbb/global_control.h"
19 #include "tbb_main.h"
20 #include "governor.h"
21 #include "market.h"
22 #include "tbb_misc.h"
23 #include "itt_notify.h"
24
25 namespace tbb {
26 namespace internal {
27
28 //------------------------------------------------------------------------
29 // Begin shared data layout.
30 // The following global data items are mostly read-only after initialization.
31 //------------------------------------------------------------------------
32
33 //! Padding in order to prevent false sharing.
34 static const char _pad[NFS_MaxLineSize - sizeof(int)] = {};
35
36 //------------------------------------------------------------------------
37 // governor data
38 basic_tls<uintptr_t> governor::theTLS;
39 unsigned governor::DefaultNumberOfThreads;
40 size_t governor::DefaultPageSize;
41 rml::tbb_factory governor::theRMLServerFactory;
42 bool governor::UsePrivateRML;
43 bool governor::is_speculation_enabled;
44 bool governor::is_rethrow_broken;
45
46 //------------------------------------------------------------------------
47 // market data
48 market* market::theMarket;
49 market::global_market_mutex_type market::theMarketMutex;
50
51 //------------------------------------------------------------------------
52 // One time initialization data
53
54 //! Counter of references to global shared resources such as TLS.
55 atomic<int> __TBB_InitOnce::count;
56
57 __TBB_atomic_flag __TBB_InitOnce::InitializationLock;
58
59 //! Flag that is set to true after one-time initializations are done.
60 bool __TBB_InitOnce::InitializationDone;
61
62 #if DO_ITT_NOTIFY
63 static bool ITT_Present;
64 static atomic<bool> ITT_InitializationDone;
65 #endif
66
67 #if !(_WIN32||_WIN64) || __TBB_SOURCE_DIRECTLY_INCLUDED
68 static __TBB_InitOnce __TBB_InitOnceHiddenInstance;
69 #endif
70
71 //------------------------------------------------------------------------
72 // generic_scheduler data
73
74 //! Pointer to the scheduler factory function
75 generic_scheduler* (*AllocateSchedulerPtr)( market&, bool );
76
77 #if __TBB_OLD_PRIMES_RNG
78 //! Table of primes used by fast random-number generator (FastRandom).
79 /** Also serves to keep anything else from being placed in the same
80 cache line as the global data items preceding it. */
81 static const unsigned Primes[] = {
82 0x9e3779b1, 0xffe6cc59, 0x2109f6dd, 0x43977ab5,
83 0xba5703f5, 0xb495a877, 0xe1626741, 0x79695e6b,
84 0xbc98c09f, 0xd5bee2b3, 0x287488f9, 0x3af18231,
85 0x9677cd4d, 0xbe3a6929, 0xadc6a877, 0xdcf0674b,
86 0xbe4d6fe9, 0x5f15e201, 0x99afc3fd, 0xf3f16801,
87 0xe222cfff, 0x24ba5fdb, 0x0620452d, 0x79f149e3,
88 0xc8b93f49, 0x972702cd, 0xb07dd827, 0x6c97d5ed,
89 0x085a3d61, 0x46eb5ea7, 0x3d9910ed, 0x2e687b5b,
90 0x29609227, 0x6eb081f1, 0x0954c4e1, 0x9d114db9,
91 0x542acfa9, 0xb3e6bd7b, 0x0742d917, 0xe9f3ffa7,
92 0x54581edb, 0xf2480f45, 0x0bb9288f, 0xef1affc7,
93 0x85fa0ca7, 0x3ccc14db, 0xe6baf34b, 0x343377f7,
94 0x5ca19031, 0xe6d9293b, 0xf0a9f391, 0x5d2e980b,
95 0xfc411073, 0xc3749363, 0xb892d829, 0x3549366b,
96 0x629750ad, 0xb98294e5, 0x892d9483, 0xc235baf3,
97 0x3d2402a3, 0x6bdef3c9, 0xbec333cd, 0x40c9520f
98 };
99
100 //------------------------------------------------------------------------
101 // End of shared data layout
102 //------------------------------------------------------------------------
103
104 //------------------------------------------------------------------------
105 // Shared data accessors
106 //------------------------------------------------------------------------
107
GetPrime(unsigned seed)108 unsigned GetPrime ( unsigned seed ) {
109 return Primes[seed%(sizeof(Primes)/sizeof(Primes[0]))];
110 }
111 #endif //__TBB_OLD_PRIMES_RNG
112
113 //------------------------------------------------------------------------
114 // __TBB_InitOnce
115 //------------------------------------------------------------------------
116
add_ref()117 void __TBB_InitOnce::add_ref() {
118 if( ++count==1 )
119 governor::acquire_resources();
120 }
121
remove_ref()122 void __TBB_InitOnce::remove_ref() {
123 int k = --count;
124 __TBB_ASSERT(k>=0,"removed __TBB_InitOnce ref that was not added?");
125 if( k==0 ) {
126 governor::release_resources();
127 ITT_FINI_ITTLIB();
128 }
129 }
130
131 //------------------------------------------------------------------------
132 // One-time Initializations
133 //------------------------------------------------------------------------
134
135 //! Defined in cache_aligned_allocator.cpp
136 void initialize_cache_aligned_allocator();
137
138 //! Defined in scheduler.cpp
139 void Scheduler_OneTimeInitialization ( bool itt_present );
140
141 #if DO_ITT_NOTIFY
142
143 static __itt_domain *tbb_domains[ITT_NUM_DOMAINS] = {};
144
145 struct resource_string {
146 const char *str;
147 __itt_string_handle *itt_str_handle;
148 };
149
150 //
151 // populate resource strings
152 //
153 #define TBB_STRING_RESOURCE( index_name, str ) { str, NULL },
154 static resource_string strings_for_itt[] = {
155 #include "tbb/internal/_tbb_strings.h"
156 { "num_resource_strings", NULL }
157 };
158 #undef TBB_STRING_RESOURCE
159
ITT_get_string_handle(int idx)160 static __itt_string_handle *ITT_get_string_handle(int idx) {
161 __TBB_ASSERT( idx >= 0 && idx < NUM_STRINGS, "string handle out of valid range");
162 return (idx >= 0 && idx < NUM_STRINGS) ? strings_for_itt[idx].itt_str_handle : NULL;
163 }
164
ITT_init_domains()165 static void ITT_init_domains() {
166 tbb_domains[ITT_DOMAIN_MAIN] = __itt_domain_create( _T("tbb") );
167 tbb_domains[ITT_DOMAIN_MAIN]->flags = 1;
168 tbb_domains[ITT_DOMAIN_FLOW] = __itt_domain_create( _T("tbb.flow") );
169 tbb_domains[ITT_DOMAIN_FLOW]->flags = 1;
170 tbb_domains[ITT_DOMAIN_ALGO] = __itt_domain_create( _T("tbb.algorithm") );
171 tbb_domains[ITT_DOMAIN_ALGO]->flags = 1;
172 }
173
ITT_init_strings()174 static void ITT_init_strings() {
175 for ( int i = 0; i < NUM_STRINGS; ++i ) {
176 #if _WIN32||_WIN64
177 strings_for_itt[i].itt_str_handle = __itt_string_handle_createA( strings_for_itt[i].str );
178 #else
179 strings_for_itt[i].itt_str_handle = __itt_string_handle_create( strings_for_itt[i].str );
180 #endif
181 }
182 }
183
ITT_init()184 static void ITT_init() {
185 ITT_init_domains();
186 ITT_init_strings();
187 }
188
189 /** Thread-unsafe lazy one-time initialization of tools interop.
190 Used by both dummy handlers and general TBB one-time initialization routine. **/
ITT_DoUnsafeOneTimeInitialization()191 void ITT_DoUnsafeOneTimeInitialization () {
192 // Double check ITT_InitializationDone is necessary because the first check
193 // in ITT_DoOneTimeInitialization is not guarded with the __TBB_InitOnce lock.
194 if ( !ITT_InitializationDone ) {
195 ITT_Present = (__TBB_load_ittnotify()!=0);
196 if (ITT_Present) ITT_init();
197 ITT_InitializationDone = true;
198 ITT_SYNC_CREATE(&market::theMarketMutex, SyncType_GlobalLock, SyncObj_SchedulerInitialization);
199 }
200 }
201
202 /** Thread-safe lazy one-time initialization of tools interop.
203 Used by dummy handlers only. **/
204 extern "C"
ITT_DoOneTimeInitialization()205 void ITT_DoOneTimeInitialization() {
206 if ( !ITT_InitializationDone ) {
207 __TBB_InitOnce::lock();
208 ITT_DoUnsafeOneTimeInitialization();
209 __TBB_InitOnce::unlock();
210 }
211 }
212 #endif /* DO_ITT_NOTIFY */
213
214 //! Performs thread-safe lazy one-time general TBB initialization.
DoOneTimeInitializations()215 void DoOneTimeInitializations() {
216 suppress_unused_warning(_pad);
217 __TBB_InitOnce::lock();
218 // No fence required for load of InitializationDone, because we are inside a critical section.
219 if( !__TBB_InitOnce::InitializationDone ) {
220 __TBB_InitOnce::add_ref();
221 if( GetBoolEnvironmentVariable("TBB_VERSION") )
222 PrintVersion();
223 bool itt_present = false;
224 #if DO_ITT_NOTIFY
225 ITT_DoUnsafeOneTimeInitialization();
226 itt_present = ITT_Present;
227 #endif /* DO_ITT_NOTIFY */
228 initialize_cache_aligned_allocator();
229 governor::initialize_rml_factory();
230 Scheduler_OneTimeInitialization( itt_present );
231 // Force processor groups support detection
232 governor::default_num_threads();
233 // Force OS regular page size detection
234 governor::default_page_size();
235 // Dump version data
236 governor::print_version_info();
237 PrintExtraVersionInfo( "Tools support", itt_present ? "enabled" : "disabled" );
238 __TBB_InitOnce::InitializationDone = true;
239 }
240 __TBB_InitOnce::unlock();
241 }
242
243 #if (_WIN32||_WIN64) && !__TBB_SOURCE_DIRECTLY_INCLUDED
244 //! Windows "DllMain" that handles startup and shutdown of dynamic library.
DllMain(HANDLE,DWORD reason,LPVOID lpvReserved)245 extern "C" bool WINAPI DllMain( HANDLE /*hinstDLL*/, DWORD reason, LPVOID lpvReserved ) {
246 switch( reason ) {
247 case DLL_PROCESS_ATTACH:
248 __TBB_InitOnce::add_ref();
249 break;
250 case DLL_PROCESS_DETACH:
251 // Since THREAD_DETACH is not called for the main thread, call auto-termination
252 // here as well - but not during process shutdown (due to risk of a deadlock).
253 if( lpvReserved==NULL ) // library unload
254 governor::terminate_auto_initialized_scheduler();
255 __TBB_InitOnce::remove_ref();
256 // It is assumed that InitializationDone is not set after DLL_PROCESS_DETACH,
257 // and thus no race on InitializationDone is possible.
258 if( __TBB_InitOnce::initialization_done() ) {
259 // Remove reference that we added in DoOneTimeInitializations.
260 __TBB_InitOnce::remove_ref();
261 }
262 break;
263 case DLL_THREAD_DETACH:
264 governor::terminate_auto_initialized_scheduler();
265 break;
266 }
267 return true;
268 }
269 #endif /* (_WIN32||_WIN64) && !__TBB_SOURCE_DIRECTLY_INCLUDED */
270
itt_store_pointer_with_release_v3(void * dst,void * src)271 void itt_store_pointer_with_release_v3( void* dst, void* src ) {
272 ITT_NOTIFY(sync_releasing, dst);
273 __TBB_store_with_release(*static_cast<void**>(dst),src);
274 }
275
itt_load_pointer_with_acquire_v3(const void * src)276 void* itt_load_pointer_with_acquire_v3( const void* src ) {
277 void* result = __TBB_load_with_acquire(*static_cast<void*const*>(src));
278 ITT_NOTIFY(sync_acquired, const_cast<void*>(src));
279 return result;
280 }
281
282 #if DO_ITT_NOTIFY
call_itt_notify_v5(int t,void * ptr)283 void call_itt_notify_v5(int t, void *ptr) {
284 switch (t) {
285 case 0: ITT_NOTIFY(sync_prepare, ptr); break;
286 case 1: ITT_NOTIFY(sync_cancel, ptr); break;
287 case 2: ITT_NOTIFY(sync_acquired, ptr); break;
288 case 3: ITT_NOTIFY(sync_releasing, ptr); break;
289 }
290 }
291 #else
call_itt_notify_v5(int,void *)292 void call_itt_notify_v5(int /*t*/, void* /*ptr*/) {}
293 #endif
294
295 #if DO_ITT_NOTIFY
296 const __itt_id itt_null_id = {0, 0, 0};
297
get_itt_domain(itt_domain_enum idx)298 static inline __itt_domain* get_itt_domain( itt_domain_enum idx ) {
299 if (tbb_domains[idx] == NULL) {
300 ITT_DoOneTimeInitialization();
301 }
302 return tbb_domains[idx];
303 }
304
itt_id_make(__itt_id * id,void * addr,unsigned long long extra)305 static inline void itt_id_make(__itt_id *id, void* addr, unsigned long long extra) {
306 *id = __itt_id_make(addr, extra);
307 }
308
itt_id_create(const __itt_domain * domain,__itt_id id)309 static inline void itt_id_create(const __itt_domain *domain, __itt_id id) {
310 ITTNOTIFY_VOID_D1(id_create, domain, id);
311 }
312
itt_make_task_group_v7(itt_domain_enum domain,void * group,unsigned long long group_extra,void * parent,unsigned long long parent_extra,string_index name_index)313 void itt_make_task_group_v7( itt_domain_enum domain, void *group, unsigned long long group_extra,
314 void *parent, unsigned long long parent_extra, string_index name_index ) {
315 if ( __itt_domain *d = get_itt_domain( domain ) ) {
316 __itt_id group_id = itt_null_id;
317 __itt_id parent_id = itt_null_id;
318 itt_id_make( &group_id, group, group_extra );
319 itt_id_create( d, group_id );
320 if ( parent ) {
321 itt_id_make( &parent_id, parent, parent_extra );
322 }
323 __itt_string_handle *n = ITT_get_string_handle(name_index);
324 ITTNOTIFY_VOID_D3(task_group, d, group_id, parent_id, n);
325 }
326 }
327
itt_metadata_str_add_v7(itt_domain_enum domain,void * addr,unsigned long long addr_extra,string_index key,const char * value)328 void itt_metadata_str_add_v7( itt_domain_enum domain, void *addr, unsigned long long addr_extra,
329 string_index key, const char *value ) {
330 if ( __itt_domain *d = get_itt_domain( domain ) ) {
331 __itt_id id = itt_null_id;
332 itt_id_make( &id, addr, addr_extra );
333 __itt_string_handle *k = ITT_get_string_handle(key);
334 size_t value_length = strlen( value );
335 #if _WIN32||_WIN64
336 ITTNOTIFY_VOID_D4(metadata_str_addA, d, id, k, value, value_length);
337 #else
338 ITTNOTIFY_VOID_D4(metadata_str_add, d, id, k, value, value_length);
339 #endif
340 }
341 }
342
itt_metadata_ptr_add_v11(itt_domain_enum domain,void * addr,unsigned long long addr_extra,string_index key,void * value)343 void itt_metadata_ptr_add_v11( itt_domain_enum domain, void *addr, unsigned long long addr_extra,
344 string_index key, void *value ) {
345 if ( __itt_domain *d = get_itt_domain( domain ) ) {
346 __itt_id id = itt_null_id;
347 itt_id_make( &id, addr, addr_extra );
348 __itt_string_handle *k = ITT_get_string_handle(key);
349 #if __TBB_x86_32
350 ITTNOTIFY_VOID_D5(metadata_add, d, id, k, __itt_metadata_u32, 1, value);
351 #else
352 ITTNOTIFY_VOID_D5(metadata_add, d, id, k, __itt_metadata_u64, 1, value);
353 #endif
354 }
355 }
356
357
itt_relation_add_v7(itt_domain_enum domain,void * addr0,unsigned long long addr0_extra,itt_relation relation,void * addr1,unsigned long long addr1_extra)358 void itt_relation_add_v7( itt_domain_enum domain, void *addr0, unsigned long long addr0_extra,
359 itt_relation relation, void *addr1, unsigned long long addr1_extra ) {
360 if ( __itt_domain *d = get_itt_domain( domain ) ) {
361 __itt_id id0 = itt_null_id;
362 __itt_id id1 = itt_null_id;
363 itt_id_make( &id0, addr0, addr0_extra );
364 itt_id_make( &id1, addr1, addr1_extra );
365 ITTNOTIFY_VOID_D3(relation_add, d, id0, (__itt_relation)relation, id1);
366 }
367 }
368
itt_task_begin_v7(itt_domain_enum domain,void * task,unsigned long long task_extra,void * parent,unsigned long long parent_extra,string_index name_index)369 void itt_task_begin_v7( itt_domain_enum domain, void *task, unsigned long long task_extra,
370 void *parent, unsigned long long parent_extra, string_index name_index ) {
371 if ( __itt_domain *d = get_itt_domain( domain ) ) {
372 __itt_id task_id = itt_null_id;
373 __itt_id parent_id = itt_null_id;
374 if ( task ) {
375 itt_id_make( &task_id, task, task_extra );
376 }
377 if ( parent ) {
378 itt_id_make( &parent_id, parent, parent_extra );
379 }
380 __itt_string_handle *n = ITT_get_string_handle(name_index);
381 ITTNOTIFY_VOID_D3(task_begin, d, task_id, parent_id, n );
382 }
383 }
384
itt_task_end_v7(itt_domain_enum domain)385 void itt_task_end_v7( itt_domain_enum domain ) {
386 if ( __itt_domain *d = get_itt_domain( domain ) ) {
387 ITTNOTIFY_VOID_D0(task_end, d);
388 }
389 }
390
itt_region_begin_v9(itt_domain_enum domain,void * region,unsigned long long region_extra,void * parent,unsigned long long parent_extra,string_index)391 void itt_region_begin_v9( itt_domain_enum domain, void *region, unsigned long long region_extra,
392 void *parent, unsigned long long parent_extra, string_index /* name_index */ ) {
393 if ( __itt_domain *d = get_itt_domain( domain ) ) {
394 __itt_id region_id = itt_null_id;
395 __itt_id parent_id = itt_null_id;
396 itt_id_make( ®ion_id, region, region_extra );
397 if ( parent ) {
398 itt_id_make( &parent_id, parent, parent_extra );
399 }
400 ITTNOTIFY_VOID_D3(region_begin, d, region_id, parent_id, NULL );
401 }
402 }
403
itt_region_end_v9(itt_domain_enum domain,void * region,unsigned long long region_extra)404 void itt_region_end_v9( itt_domain_enum domain, void *region, unsigned long long region_extra ) {
405 if ( __itt_domain *d = get_itt_domain( domain ) ) {
406 __itt_id region_id = itt_null_id;
407 itt_id_make( ®ion_id, region, region_extra );
408 ITTNOTIFY_VOID_D1( region_end, d, region_id );
409 }
410 }
411
412 #else // DO_ITT_NOTIFY
413
itt_make_task_group_v7(itt_domain_enum,void *,unsigned long long,void *,unsigned long long,string_index)414 void itt_make_task_group_v7( itt_domain_enum /*domain*/, void* /*group*/, unsigned long long /*group_extra*/,
415 void* /*parent*/, unsigned long long /*parent_extra*/, string_index /*name_index*/ ) { }
416
itt_metadata_str_add_v7(itt_domain_enum,void *,unsigned long long,string_index,const char *)417 void itt_metadata_str_add_v7( itt_domain_enum /*domain*/, void* /*addr*/, unsigned long long /*addr_extra*/,
418 string_index /*key*/, const char* /*value*/ ) { }
419
itt_relation_add_v7(itt_domain_enum,void *,unsigned long long,itt_relation,void *,unsigned long long)420 void itt_relation_add_v7( itt_domain_enum /*domain*/, void* /*addr0*/, unsigned long long /*addr0_extra*/,
421 itt_relation /*relation*/, void* /*addr1*/, unsigned long long /*addr1_extra*/ ) { }
422
itt_metadata_ptr_add_v11(itt_domain_enum,void *,unsigned long long,string_index,void *)423 void itt_metadata_ptr_add_v11( itt_domain_enum /*domain*/, void * /*addr*/, unsigned long long /*addr_extra*/,
424 string_index /*key*/, void * /*value*/ ) {}
425
itt_task_begin_v7(itt_domain_enum,void *,unsigned long long,void *,unsigned long long,string_index)426 void itt_task_begin_v7( itt_domain_enum /*domain*/, void* /*task*/, unsigned long long /*task_extra*/,
427 void* /*parent*/, unsigned long long /*parent_extra*/, string_index /*name_index*/ ) { }
428
itt_task_end_v7(itt_domain_enum)429 void itt_task_end_v7( itt_domain_enum /*domain*/ ) { }
430
itt_region_begin_v9(itt_domain_enum,void *,unsigned long long,void *,unsigned long long,string_index)431 void itt_region_begin_v9( itt_domain_enum /*domain*/, void* /*region*/, unsigned long long /*region_extra*/,
432 void* /*parent*/, unsigned long long /*parent_extra*/, string_index /*name_index*/ ) { }
433
itt_region_end_v9(itt_domain_enum,void *,unsigned long long)434 void itt_region_end_v9( itt_domain_enum /*domain*/, void* /*region*/, unsigned long long /*region_extra*/ ) { }
435
436 #endif // DO_ITT_NOTIFY
437
itt_load_pointer_v3(const void * src)438 void* itt_load_pointer_v3( const void* src ) {
439 //TODO: replace this with __TBB_load_relaxed
440 void* result = *static_cast<void*const*>(src);
441 return result;
442 }
443
itt_set_sync_name_v3(void * obj,const tchar * name)444 void itt_set_sync_name_v3( void* obj, const tchar* name) {
445 ITT_SYNC_RENAME(obj, name);
446 suppress_unused_warning(obj, name);
447 }
448
449 class control_storage {
450 friend class tbb::interface9::global_control;
451 protected:
452 size_t my_active_value;
453 atomic<global_control*> my_head;
454 spin_mutex my_list_mutex;
455
456 virtual size_t default_value() const = 0;
apply_active() const457 virtual void apply_active() const {}
is_first_arg_preferred(size_t a,size_t b) const458 virtual bool is_first_arg_preferred(size_t a, size_t b) const {
459 return a>b; // prefer max by default
460 }
active_value() const461 virtual size_t active_value() const {
462 return my_head? my_active_value : default_value();
463 }
464 };
465
466 class allowed_parallelism_control : public padded<control_storage> {
default_value() const467 virtual size_t default_value() const __TBB_override {
468 return max(1U, governor::default_num_threads());
469 }
is_first_arg_preferred(size_t a,size_t b) const470 virtual bool is_first_arg_preferred(size_t a, size_t b) const __TBB_override {
471 return a<b; // prefer min allowed parallelism
472 }
apply_active() const473 virtual void apply_active() const __TBB_override {
474 __TBB_ASSERT( my_active_value>=1, NULL );
475 // -1 to take master into account
476 market::set_active_num_workers( my_active_value-1 );
477 }
active_value() const478 virtual size_t active_value() const __TBB_override {
479 /* Reading of my_active_value is not synchronized with possible updating
480 of my_head by other thread. It's ok, as value of my_active_value became
481 not invalid, just obsolete. */
482 if (!my_head)
483 return default_value();
484 // non-zero, if market is active
485 const size_t workers = market::max_num_workers();
486 // We can't exceed market's maximal number of workers.
487 // +1 to take master into account
488 return workers? min(workers+1, my_active_value): my_active_value;
489 }
490 public:
active_value_if_present() const491 size_t active_value_if_present() const {
492 return my_head? my_active_value : 0;
493 }
494 };
495
496 class stack_size_control : public padded<control_storage> {
default_value() const497 virtual size_t default_value() const __TBB_override {
498 return tbb::internal::ThreadStackSize;
499 }
apply_active() const500 virtual void apply_active() const __TBB_override {
501 #if __TBB_WIN8UI_SUPPORT && (_WIN32_WINNT < 0x0A00)
502 __TBB_ASSERT( false, "For Windows 8 Store* apps we must not set stack size" );
503 #endif
504 }
505 };
506
507 static allowed_parallelism_control allowed_parallelism_ctl;
508 static stack_size_control stack_size_ctl;
509
510 static control_storage *controls[] = {&allowed_parallelism_ctl, &stack_size_ctl};
511
app_parallelism_limit()512 unsigned market::app_parallelism_limit() {
513 return allowed_parallelism_ctl.active_value_if_present();
514 }
515
516 } // namespace internal
517
518 namespace interface9 {
519
520 using namespace internal;
521 using namespace tbb::internal;
522
internal_create()523 void global_control::internal_create() {
524 __TBB_ASSERT_RELEASE( my_param < global_control::parameter_max, NULL );
525 control_storage *const c = controls[my_param];
526
527 spin_mutex::scoped_lock lock(c->my_list_mutex);
528 if (!c->my_head || c->is_first_arg_preferred(my_value, c->my_active_value)) {
529 c->my_active_value = my_value;
530 // to guarantee that apply_active() is called with current active value,
531 // calls it here and in internal_destroy() under my_list_mutex
532 c->apply_active();
533 }
534 my_next = c->my_head;
535 // publish my_head, at this point my_active_value must be valid
536 c->my_head = this;
537 }
538
internal_destroy()539 void global_control::internal_destroy() {
540 global_control *prev = 0;
541
542 __TBB_ASSERT_RELEASE( my_param < global_control::parameter_max, NULL );
543 control_storage *const c = controls[my_param];
544 __TBB_ASSERT( c->my_head, NULL );
545
546 // Concurrent reading and changing global parameter is possible.
547 // In this case, my_active_value may not match current state of parameters.
548 // This is OK because:
549 // 1) my_active_value is either current or previous
550 // 2) my_active_value is current on internal_destroy leave
551 spin_mutex::scoped_lock lock(c->my_list_mutex);
552 size_t new_active = (size_t)-1, old_active = c->my_active_value;
553
554 if ( c->my_head != this )
555 new_active = c->my_head->my_value;
556 else if ( c->my_head->my_next )
557 new_active = c->my_head->my_next->my_value;
558 // if there is only one element, new_active will be set later
559 for ( global_control *curr = c->my_head; curr; prev = curr, curr = curr->my_next )
560 if ( curr == this ) {
561 if ( prev )
562 prev->my_next = my_next;
563 else
564 c->my_head = my_next;
565 } else
566 if (c->is_first_arg_preferred(curr->my_value, new_active))
567 new_active = curr->my_value;
568
569 if ( !c->my_head ) {
570 __TBB_ASSERT( new_active==(size_t)-1, NULL );
571 new_active = c->default_value();
572 }
573 if ( new_active != old_active ) {
574 c->my_active_value = new_active;
575 c->apply_active();
576 }
577 }
578
active_value(int param)579 size_t global_control::active_value( int param ) {
580 __TBB_ASSERT_RELEASE( param < global_control::parameter_max, NULL );
581 return controls[param]->active_value();
582 }
583
584 } // tbb::interface9
585 } // namespace tbb
586