[llvm] [libsycl] Fix for static vars deinit order (libsycl vs liboffload) (PR #181366)
Kseniya Tikhomirova via llvm-commits
llvm-commits at lists.llvm.org
Fri Feb 13 06:35:51 PST 2026
https://github.com/KseniyaTikhomirova created https://github.com/llvm/llvm-project/pull/181366
both libsycl & liboffload uses static variables.
on Linux static variable destructor is called earlier than the method with __attribute__((destructor(...))).
this fix helps to avoid crash due to liboffload static variable early destruction.
the approach utilizes the following rule
"For each local object obj with static storage duration, obj is destroyed as if a function calling the destructor of obj were registered with [std::atexit](https://en.cppreference.com/w/cpp/utility/program/atexit.html) at the completion of the constructor of obj."
from std::exit.
in the first call of get_platforms we call liboffload's iterateDevices that leads to liboffload static storage initialization. Then we initialize our own local static var after this to be able to call our shutdown methods earlier and before the liboffload objects are destructed at the end of program.
Important note:
SYCL RT follows SYCL 2020 specification that doesn't declare any init/shutdown methods that can help to avoid usage of static variables.
>From 68ddb5a47d7bf53db70063da821c385f2d8c6c64 Mon Sep 17 00:00:00 2001
From: "Tikhomirova, Kseniya" <kseniya.tikhomirova at intel.com>
Date: Fri, 13 Feb 2026 06:24:43 -0800
Subject: [PATCH] [libsycl] Fix for static vars deinit order (libsycl vs
liboffload)
Signed-off-by: Tikhomirova, Kseniya <kseniya.tikhomirova at intel.com>
---
libsycl/src/detail/global_objects.cpp | 28 ++++++++++++++-------------
libsycl/src/detail/global_objects.hpp | 4 ++++
libsycl/src/detail/platform_impl.cpp | 2 ++
3 files changed, 21 insertions(+), 13 deletions(-)
diff --git a/libsycl/src/detail/global_objects.cpp b/libsycl/src/detail/global_objects.cpp
index fa7274d137040..7e76a6067d529 100644
--- a/libsycl/src/detail/global_objects.cpp
+++ b/libsycl/src/detail/global_objects.cpp
@@ -18,6 +18,20 @@
_LIBSYCL_BEGIN_NAMESPACE_SYCL
namespace detail {
+struct StaticVarShutdownHandler {
+ StaticVarShutdownHandler(const StaticVarShutdownHandler &) = delete;
+ StaticVarShutdownHandler &
+ operator=(const StaticVarShutdownHandler &) = delete;
+ ~StaticVarShutdownHandler() {
+ // No error reporting in shutdown
+ std::ignore = olShutDown();
+ }
+};
+
+void registerStaticVarShutdownHandler() {
+ static StaticVarShutdownHandler handler{};
+}
+
std::vector<detail::OffloadTopology> &getOffloadTopologies() {
static std::vector<detail::OffloadTopology> Topologies(
OL_PLATFORM_BACKEND_LAST);
@@ -29,11 +43,6 @@ std::vector<PlatformImplUPtr> &getPlatformCache() {
return PlatformCache;
}
-static void shutdown() {
- // No error reporting in shutdown
- std::ignore = olShutDown();
-}
-
#ifdef _WIN32
extern "C" _LIBSYCL_EXPORT BOOL WINAPI DllMain(HINSTANCE hinstDLL,
DWORD fdwReason,
@@ -41,13 +50,6 @@ extern "C" _LIBSYCL_EXPORT BOOL WINAPI DllMain(HINSTANCE hinstDLL,
// Perform actions based on the reason for calling.
switch (fdwReason) {
case DLL_PROCESS_DETACH:
- try {
- shutdown();
- } catch (std::exception &e) {
- // TODO: Investigate how to handle and report errors that occur during
- // shutdown.
- }
-
break;
case DLL_PROCESS_ATTACH:
break;
@@ -65,7 +67,7 @@ extern "C" _LIBSYCL_EXPORT BOOL WINAPI DllMain(HINSTANCE hinstDLL,
// by the compiler and C and C++ standard libraries. SYCL applications may use
// priorities in the range 101-109 to schedule destructors to run after libsycl
// finalization.
-__attribute__((destructor(110))) static void syclUnload() { shutdown(); }
+__attribute__((destructor(110))) static void syclUnload() {}
#endif
} // namespace detail
_LIBSYCL_END_NAMESPACE_SYCL
diff --git a/libsycl/src/detail/global_objects.hpp b/libsycl/src/detail/global_objects.hpp
index 8e56be22a05fe..4535a254c6609 100644
--- a/libsycl/src/detail/global_objects.hpp
+++ b/libsycl/src/detail/global_objects.hpp
@@ -36,6 +36,10 @@ std::vector<detail::OffloadTopology> &getOffloadTopologies();
/// \returns std::vector of implementation objects for all platforms.
std::vector<std::unique_ptr<PlatformImpl>> &getPlatformCache();
+// This initializes a function-local variable whose destructor is invoked as
+// the SYCL shared library is first being unloaded.
+void registerStaticVarShutdownHandler();
+
} // namespace detail
_LIBSYCL_END_NAMESPACE_SYCL
diff --git a/libsycl/src/detail/platform_impl.cpp b/libsycl/src/detail/platform_impl.cpp
index 0116ad68d4bdd..d96ee4af311a6 100644
--- a/libsycl/src/detail/platform_impl.cpp
+++ b/libsycl/src/detail/platform_impl.cpp
@@ -38,6 +38,8 @@ const std::vector<PlatformImplUPtr> &PlatformImpl::getPlatforms() {
[[maybe_unused]] static auto InitPlatformsOnce = []() {
discoverOffloadDevices();
+ registerStaticVarShutdownHandler();
+
auto &PlatformCache = getPlatformCache();
for (const auto &Topo : getOffloadTopologies()) {
size_t PlatformIndex = 0;
More information about the llvm-commits
mailing list