1 /*
2     Copyright (c) 2005-2021 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 #ifndef _TBB_main_H
18 #define _TBB_main_H
19 
20 #include "governor.h"
21 
22 #include <atomic>
23 
24 namespace tbb {
25 namespace detail {
26 namespace r1 {
27 
28 void DoOneTimeInitialization();
29 
30 //------------------------------------------------------------------------
31 // __TBB_InitOnce
32 //------------------------------------------------------------------------
33 
34 // TODO (TBB_REVAMP_TODO): consider better names
35 //! Class that supports TBB initialization.
36 /** It handles acquisition and release of global resources (e.g. TLS) during startup and shutdown,
37     as well as synchronization for DoOneTimeInitialization. */
38 class __TBB_InitOnce {
39     friend void DoOneTimeInitialization();
40     friend void ITT_DoUnsafeOneTimeInitialization();
41 
42     static std::atomic<int> count;
43 
44     //! Platform specific code to acquire resources.
45     static void acquire_resources();
46 
47     //! Platform specific code to release resources.
48     static void release_resources();
49 
50     //! Specifies if the one-time initializations has been done.
51     static std::atomic<bool> InitializationDone;
52 
53     //! Global initialization lock
54     /** Scenarios are possible when tools interop has to be initialized before the
55         TBB itself. This imposes a requirement that the global initialization lock
56         has to support valid static initialization, and does not issue any tool
57         notifications in any build mode. **/
58     static std::atomic_flag InitializationLock;
59 
60 public:
lock()61     static void lock() {
62         tbb::detail::atomic_backoff backoff;
63         while( InitializationLock.test_and_set() ) backoff.pause();
64     }
65 
unlock()66     static void unlock() { InitializationLock.clear(std::memory_order_release); }
67 
initialization_done()68     static bool initialization_done() { return InitializationDone.load(std::memory_order_acquire); }
69 
70     //! Add initial reference to resources.
71     /** We assume that dynamic loading of the library prevents any other threads
72         from entering the library until this constructor has finished running. **/
__TBB_InitOnce()73     __TBB_InitOnce() { add_ref(); }
74 
75     //! Remove the initial reference to resources.
76     /** This is not necessarily the last reference if other threads are still running. **/
~__TBB_InitOnce()77     ~__TBB_InitOnce() {
78         governor::terminate_external_thread(); // TLS dtor not called for the main thread
79         remove_ref();
80         // We assume that InitializationDone is not set after file-scope destructors
81         // start running, and thus no race on InitializationDone is possible.
82         if ( initialization_done() ) {
83             // Remove an extra reference that was added in DoOneTimeInitialization.
84             remove_ref();
85         }
86     }
87     //! Add reference to resources.  If first reference added, acquire the resources.
88     static void add_ref();
89 
90     //! Remove reference to resources.  If last reference removed, release the resources.
91     static void remove_ref();
92 
93 }; // class __TBB_InitOnce
94 
95 } // namespace r1
96 } // namespace detail
97 } // namespace tbb
98 
99 #endif /* _TBB_main_H */
100