@@ -28,17 +28,18 @@ namespace sycl {
28
28
__SYCL_INLINE_VER_NAMESPACE (_V1) {
29
29
namespace detail {
30
30
31
+ using LockGuard = std::lock_guard<SpinLock>;
32
+ SpinLock GlobalHandler::MSyclGlobalHandlerProtector{};
33
+
31
34
// Utility class to track references on object.
32
- // Used for Scheduler now and created as thread_local object.
33
- // Origin idea is to track usage of Scheduler from main and other used threads -
34
- // they increment MCounter; and to use but not add extra reference by our
35
- // thread_pool threads. For this control MIncrementCounter class member is used.
36
- template <class ResourceHandler > class ObjectUsageCounter {
35
+ // Used for GlobalHandler now and created as thread_local object on the first
36
+ // Scheduler usage. Origin idea is to track usage of Scheduler from main and
37
+ // other used threads - they increment MCounter; and to use but not add extra
38
+ // reference by our thread_pool threads. For this control MIncrementCounter
39
+ // class member is used.
40
+ class ObjectUsageCounter {
37
41
public:
38
- // Note: -Wctad-maybe-unsupported may generate warning if no ResourceHandler
39
- // type explicitly declared.
40
- ObjectUsageCounter (std::unique_ptr<ResourceHandler> &Obj, bool ModifyCounter)
41
- : MModifyCounter(ModifyCounter), MObj(Obj) {
42
+ ObjectUsageCounter (bool ModifyCounter) : MModifyCounter(ModifyCounter) {
42
43
if (MModifyCounter)
43
44
MCounter++;
44
45
}
@@ -47,26 +48,35 @@ template <class ResourceHandler> class ObjectUsageCounter {
47
48
return ;
48
49
49
50
MCounter--;
50
- if (!MCounter && MObj)
51
- MObj->releaseResources ();
51
+ if (!MCounter) {
52
+ LockGuard Guard (GlobalHandler::MSyclGlobalHandlerProtector);
53
+ GlobalHandler *RTGlobalObjHandler = GlobalHandler::getInstancePtr ();
54
+ if (RTGlobalObjHandler) {
55
+ RTGlobalObjHandler->drainThreadPool ();
56
+ if (RTGlobalObjHandler->MScheduler .Inst )
57
+ RTGlobalObjHandler->MScheduler .Inst ->releaseResources ();
58
+ }
59
+ }
52
60
}
53
61
54
62
private:
55
63
static std::atomic_uint MCounter;
56
64
bool MModifyCounter;
57
- std::unique_ptr<ResourceHandler> &MObj;
58
65
};
59
- template <class ResourceHandler >
60
- std::atomic_uint ObjectUsageCounter<ResourceHandler>::MCounter{0 };
61
-
62
- using LockGuard = std::lock_guard<SpinLock>;
66
+ std::atomic_uint ObjectUsageCounter::MCounter{0 };
63
67
64
68
GlobalHandler::GlobalHandler () = default ;
65
69
GlobalHandler::~GlobalHandler () = default ;
66
70
71
+ GlobalHandler *&GlobalHandler::getInstancePtr () {
72
+ static GlobalHandler *RTGlobalObjHandler = new GlobalHandler ();
73
+ return RTGlobalObjHandler;
74
+ }
75
+
67
76
GlobalHandler &GlobalHandler::instance () {
68
- static GlobalHandler *SyclGlobalObjectsHandler = new GlobalHandler ();
69
- return *SyclGlobalObjectsHandler;
77
+ GlobalHandler *RTGlobalObjHandler = GlobalHandler::getInstancePtr ();
78
+ assert (RTGlobalObjHandler && " Handler must not be deallocated earlier" );
79
+ return *RTGlobalObjHandler;
70
80
}
71
81
72
82
template <typename T, typename ... Types>
@@ -94,8 +104,7 @@ Scheduler &GlobalHandler::getScheduler() {
94
104
}
95
105
96
106
void GlobalHandler::registerSchedulerUsage (bool ModifyCounter) {
97
- thread_local ObjectUsageCounter<Scheduler> SchedulerCounter (MScheduler.Inst ,
98
- ModifyCounter);
107
+ thread_local ObjectUsageCounter SchedulerCounter (ModifyCounter);
99
108
}
100
109
101
110
ProgramManager &GlobalHandler::getProgramManager () {
@@ -151,14 +160,14 @@ ThreadPool &GlobalHandler::getHostTaskThreadPool() {
151
160
void GlobalHandler::releaseDefaultContexts () {
152
161
// Release shared-pointers to SYCL objects.
153
162
#ifndef _WIN32
154
- GlobalHandler::instance (). MPlatformToDefaultContextCache .Inst .reset (nullptr );
163
+ MPlatformToDefaultContextCache.Inst .reset (nullptr );
155
164
#else
156
165
// Windows does not maintain dependencies between dynamically loaded libraries
157
166
// and can unload SYCL runtime dependencies before sycl.dll's DllMain has
158
167
// finished. To avoid calls to nowhere, intentionally leak platform to device
159
168
// cache. This will prevent destructors from being called, thus no PI cleanup
160
169
// routines will be called in the end.
161
- GlobalHandler::instance (). MPlatformToDefaultContextCache .Inst .release ();
170
+ MPlatformToDefaultContextCache.Inst .release ();
162
171
#endif
163
172
}
164
173
@@ -178,8 +187,8 @@ void GlobalHandler::unloadPlugins() {
178
187
// Call to GlobalHandler::instance().getPlugins() initializes plugins. If
179
188
// user application has loaded SYCL runtime, and never called any APIs,
180
189
// there's no need to load and unload plugins.
181
- if (GlobalHandler::instance (). MPlugins .Inst ) {
182
- for (plugin &Plugin : GlobalHandler::instance (). getPlugins ()) {
190
+ if (MPlugins.Inst ) {
191
+ for (plugin &Plugin : getPlugins ()) {
183
192
// PluginParameter is reserved for future use that can control
184
193
// some parameters in the plugin tear-down process.
185
194
// Currently, it is not used.
@@ -189,7 +198,7 @@ void GlobalHandler::unloadPlugins() {
189
198
}
190
199
}
191
200
// Clear after unload to avoid uses after unload.
192
- GlobalHandler::instance (). getPlugins ().clear ();
201
+ getPlugins ().clear ();
193
202
}
194
203
195
204
void GlobalHandler::drainThreadPool () {
@@ -198,34 +207,40 @@ void GlobalHandler::drainThreadPool() {
198
207
}
199
208
200
209
void shutdown () {
210
+ const LockGuard Lock{GlobalHandler::MSyclGlobalHandlerProtector};
211
+ GlobalHandler *&Handler = GlobalHandler::getInstancePtr ();
212
+ if (!Handler)
213
+ return ;
214
+
201
215
// Ensure neither host task is working so that no default context is accessed
202
216
// upon its release
217
+ Handler->drainThreadPool ();
218
+ if (Handler->MScheduler .Inst )
219
+ Handler->MScheduler .Inst ->releaseResources ();
203
220
204
- if (GlobalHandler::instance ().MScheduler .Inst )
205
- GlobalHandler::instance ().MScheduler .Inst ->releaseResources ();
206
-
207
- if (GlobalHandler::instance ().MHostTaskThreadPool .Inst )
208
- GlobalHandler::instance ().MHostTaskThreadPool .Inst ->finishAndWait ();
221
+ if (Handler->MHostTaskThreadPool .Inst )
222
+ Handler->MHostTaskThreadPool .Inst ->finishAndWait ();
209
223
210
224
// If default contexts are requested after the first default contexts have
211
225
// been released there may be a new default context. These must be released
212
226
// prior to closing the plugins.
213
227
// Note: Releasing a default context here may cause failures in plugins with
214
228
// global state as the global state may have been released.
215
- GlobalHandler::instance (). releaseDefaultContexts ();
229
+ Handler-> releaseDefaultContexts ();
216
230
217
231
// First, release resources, that may access plugins.
218
- GlobalHandler::instance (). MPlatformCache .Inst .reset (nullptr );
219
- GlobalHandler::instance (). MScheduler .Inst .reset (nullptr );
220
- GlobalHandler::instance (). MProgramManager .Inst .reset (nullptr );
232
+ Handler-> MPlatformCache .Inst .reset (nullptr );
233
+ Handler-> MScheduler .Inst .reset (nullptr );
234
+ Handler-> MProgramManager .Inst .reset (nullptr );
221
235
222
236
// Clear the plugins and reset the instance if it was there.
223
- GlobalHandler::instance (). unloadPlugins ();
224
- if (GlobalHandler::instance (). MPlugins .Inst )
225
- GlobalHandler::instance (). MPlugins .Inst .reset (nullptr );
237
+ Handler-> unloadPlugins ();
238
+ if (Handler-> MPlugins .Inst )
239
+ Handler-> MPlugins .Inst .reset (nullptr );
226
240
227
241
// Release the rest of global resources.
228
- delete &GlobalHandler::instance ();
242
+ delete Handler;
243
+ Handler = nullptr ;
229
244
}
230
245
231
246
#ifdef _WIN32
0 commit comments