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( &region_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( &region_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