DPC++ Runtime
Runtime libraries for oneAPI DPC++
global_handler.cpp
Go to the documentation of this file.
1 //==--------- global_handler.cpp --- Global objects handler ----------------==//
2 //
3 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4 // See https://llvm.org/LICENSE.txt for license information.
5 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6 //
7 //===----------------------------------------------------------------------===//
8 
9 #include <detail/config.hpp>
11 #include <detail/platform_impl.hpp>
12 #include <detail/plugin.hpp>
15 #include <detail/thread_pool.hpp>
16 #include <detail/xpti_registry.hpp>
18 #include <sycl/detail/pi.hpp>
19 #include <sycl/detail/spinlock.hpp>
20 
21 #ifdef _WIN32
22 #include <windows.h>
23 #endif
24 
25 #include <vector>
26 
27 namespace sycl {
29 namespace detail {
30 using LockGuard = std::lock_guard<SpinLock>;
31 
32 GlobalHandler::GlobalHandler() = default;
33 GlobalHandler::~GlobalHandler() = default;
34 
35 GlobalHandler &GlobalHandler::instance() {
36  static GlobalHandler *SyclGlobalObjectsHandler = new GlobalHandler();
37  return *SyclGlobalObjectsHandler;
38 }
39 
40 template <typename T, typename... Types>
41 T &GlobalHandler::getOrCreate(InstWithLock<T> &IWL, Types... Args) {
42  const LockGuard Lock{IWL.Lock};
43 
44  if (!IWL.Inst)
45  IWL.Inst = std::make_unique<T>(Args...);
46 
47  return *IWL.Inst;
48 }
49 
50 Scheduler &GlobalHandler::getScheduler() { return getOrCreate(MScheduler); }
51 
52 ProgramManager &GlobalHandler::getProgramManager() {
53  return getOrCreate(MProgramManager);
54 }
55 
56 std::unordered_map<PlatformImplPtr, ContextImplPtr> &
57 GlobalHandler::getPlatformToDefaultContextCache() {
58  return getOrCreate(MPlatformToDefaultContextCache);
59 }
60 
61 std::mutex &GlobalHandler::getPlatformToDefaultContextCacheMutex() {
62  return getOrCreate(MPlatformToDefaultContextCacheMutex);
63 }
64 
65 Sync &GlobalHandler::getSync() { return getOrCreate(MSync); }
66 
67 std::vector<PlatformImplPtr> &GlobalHandler::getPlatformCache() {
68  return getOrCreate(MPlatformCache);
69 }
70 
71 std::mutex &GlobalHandler::getPlatformMapMutex() {
72  return getOrCreate(MPlatformMapMutex);
73 }
74 
75 std::mutex &GlobalHandler::getFilterMutex() {
76  return getOrCreate(MFilterMutex);
77 }
78 std::vector<plugin> &GlobalHandler::getPlugins() {
79  return getOrCreate(MPlugins);
80 }
82 GlobalHandler::getDeviceFilterList(const std::string &InitValue) {
83  return getOrCreate(MDeviceFilterList, InitValue);
84 }
85 
87 GlobalHandler::getOneapiDeviceSelectorTargets(const std::string &InitValue) {
88  return getOrCreate(MOneapiDeviceSelectorTargets, InitValue);
89 }
90 
91 XPTIRegistry &GlobalHandler::getXPTIRegistry() {
92  return getOrCreate(MXPTIRegistry);
93 }
94 
95 ThreadPool &GlobalHandler::getHostTaskThreadPool() {
97  ThreadPool &TP = getOrCreate(MHostTaskThreadPool, Size);
98 
99  return TP;
100 }
101 
103  // Release shared-pointers to SYCL objects.
104 #ifndef _WIN32
105  GlobalHandler::instance().MPlatformToDefaultContextCache.Inst.reset(nullptr);
106 #else
107  // Windows does not maintain dependencies between dynamically loaded libraries
108  // and can unload SYCL runtime dependencies before sycl.dll's DllMain has
109  // finished. To avoid calls to nowhere, intentionally leak platform to device
110  // cache. This will prevent destructors from being called, thus no PI cleanup
111  // routines will be called in the end.
112  GlobalHandler::instance().MPlatformToDefaultContextCache.Inst.release();
113 #endif
114 }
115 
118 };
119 
120 void GlobalHandler::registerDefaultContextReleaseHandler() {
122 }
123 
124 // Note: Split from shutdown so it is available to the unittests for ensuring
125 // that the mock plugin is the lone plugin.
126 void GlobalHandler::unloadPlugins() {
127  // Call to GlobalHandler::instance().getPlugins() initializes plugins. If
128  // user application has loaded SYCL runtime, and never called any APIs,
129  // there's no need to load and unload plugins.
130  if (GlobalHandler::instance().MPlugins.Inst) {
131  for (plugin &Plugin : GlobalHandler::instance().getPlugins()) {
132  // PluginParameter is reserved for future use that can control
133  // some parameters in the plugin tear-down process.
134  // Currently, it is not used.
135  void *PluginParameter = nullptr;
136  Plugin.call<PiApiKind::piTearDown>(PluginParameter);
137  Plugin.unload();
138  }
139  }
140  // Clear after unload to avoid uses after unload.
141  GlobalHandler::instance().getPlugins().clear();
142 }
143 
144 void shutdown() {
145  // Ensure neither host task is working so that no default context is accessed
146  // upon its release
147  if (GlobalHandler::instance().MHostTaskThreadPool.Inst)
148  GlobalHandler::instance().MHostTaskThreadPool.Inst->finishAndWait();
149 
150  // If default contexts are requested after the first default contexts have
151  // been released there may be a new default context. These must be released
152  // prior to closing the plugins.
153  // Note: Releasing a default context here may cause failures in plugins with
154  // global state as the global state may have been released.
156 
157  // First, release resources, that may access plugins.
158  GlobalHandler::instance().MPlatformCache.Inst.reset(nullptr);
159  GlobalHandler::instance().MScheduler.Inst.reset(nullptr);
160  GlobalHandler::instance().MProgramManager.Inst.reset(nullptr);
161 
162  // Clear the plugins and reset the instance if it was there.
163  GlobalHandler::instance().unloadPlugins();
164  if (GlobalHandler::instance().MPlugins.Inst)
165  GlobalHandler::instance().MPlugins.Inst.reset(nullptr);
166 
167  // Release the rest of global resources.
168  delete &GlobalHandler::instance();
169 }
170 
171 #ifdef _WIN32
172 extern "C" __SYCL_EXPORT BOOL WINAPI DllMain(HINSTANCE hinstDLL,
173  DWORD fdwReason,
174  LPVOID lpReserved) {
175  // Perform actions based on the reason for calling.
176  switch (fdwReason) {
177  case DLL_PROCESS_DETACH:
178  if (!lpReserved)
179  shutdown();
180  break;
181  case DLL_PROCESS_ATTACH:
182  case DLL_THREAD_ATTACH:
183  case DLL_THREAD_DETACH:
184  break;
185  }
186  return TRUE; // Successful DLL_PROCESS_ATTACH.
187 }
188 #else
189 // Setting low priority on destructor ensures it runs after all other global
190 // destructors. Priorities 0-100 are reserved by the compiler. The priority
191 // value 110 allows SYCL users to run their destructors after runtime library
192 // deinitialization.
193 __attribute__((destructor(110))) static void syclUnload() { shutdown(); }
194 #endif
195 } // namespace detail
196 } // __SYCL_INLINE_VER_NAMESPACE(_V1)
197 } // namespace sycl
Wrapper class for global data structures with non-trivial destructors.
DPC++ graph scheduler class.
Definition: scheduler.hpp:358
Groups and provides access to all the locks used the SYCL runtime.
Definition: util.hpp:24
The plugin class provides a unified interface to the underlying low-level runtimes for the device-agn...
Definition: plugin.hpp:90
Command group handler class.
Definition: handler.hpp:310
#define __SYCL_INLINE_VER_NAMESPACE(X)
constexpr tuple_element< I, tuple< Types... > >::type & get(sycl::detail::tuple< Types... > &Arg) noexcept
Definition: tuple.hpp:199
__attribute__((destructor(110))) static void syclUnload()
std::lock_guard< SpinLock > LockGuard
---— Error handling, matching OpenCL plugin semantics.
Definition: access.hpp:14
pi_result piTearDown(void *PluginParameter)
API to notify that the plugin should clean up its resources.
C++ wrapper of extern "C" PI interfaces.