[libc-commits] [libc] [libc] Implement 'atexit' on the GPU correctly (PR #83037)

Joseph Huber via libc-commits libc-commits at lists.llvm.org
Mon Feb 26 09:19:17 PST 2024


https://github.com/jhuber6 created https://github.com/llvm/llvm-project/pull/83037

Summary:
This function was never marked at supported because it was fundamentally
broken when called with multiple threads. The patch in
https://github.com/llvm/llvm-project/pull/83026 introduces a lock-free
stack that can be used to correctly handle enqueuing callbacks from
multiple threads. Although the previous interface tried to provide a
consistent API, this was not feasible with the needs for a lock-free
stack so I have elected to just use ifdefs. The size is fixed to
whatever we use for testing, which currently amounts to about 8KiB
dedicated for this thing, which isn't enough to be concenred about.

Depends on https://github.com/llvm/llvm-project/pull/83026


>From 2abf5a3525c540ab2d53c2d649441a9b90704f3d Mon Sep 17 00:00:00 2001
From: Joseph Huber <huberjn at outlook.com>
Date: Mon, 26 Feb 2024 11:15:48 -0600
Subject: [PATCH] [libc] Implement 'atexit' on the GPU correctly

Summary:
This function was never marked at supported because it was fundamentally
broken when called with multiple threads. The patch in
https://github.com/llvm/llvm-project/pull/83026 introduces a lock-free
stack that can be used to correctly handle enqueuing callbacks from
multiple threads. Although the previous interface tried to provide a
consistent API, this was not feasible with the needs for a lock-free
stack so I have elected to just use ifdefs. The size is fixed to
whatever we use for testing, which currently amounts to about 8KiB
dedicated for this thing, which isn't enough to be concenred about.

Depends on https://github.com/llvm/llvm-project/pull/83026
---
 libc/docs/gpu/support.rst  |  1 +
 libc/src/stdlib/atexit.cpp | 24 +++++++++++++++++-------
 2 files changed, 18 insertions(+), 7 deletions(-)

diff --git a/libc/docs/gpu/support.rst b/libc/docs/gpu/support.rst
index 250f0a7794de3c..b2231eb69a590a 100644
--- a/libc/docs/gpu/support.rst
+++ b/libc/docs/gpu/support.rst
@@ -102,6 +102,7 @@ atol           |check|
 atoll          |check|
 exit           |check|    |check|
 abort          |check|    |check|
+atexit         |check|
 labs           |check|
 llabs          |check|
 div            |check|
diff --git a/libc/src/stdlib/atexit.cpp b/libc/src/stdlib/atexit.cpp
index 1513b7969f0dbc..5951c5c77e8d1f 100644
--- a/libc/src/stdlib/atexit.cpp
+++ b/libc/src/stdlib/atexit.cpp
@@ -9,6 +9,7 @@
 #include "src/stdlib/atexit.h"
 #include "src/__support/blockstore.h"
 #include "src/__support/common.h"
+#include "src/__support/fixedstack.h"
 #include "src/__support/fixedvector.h"
 #include "src/__support/threads/mutex.h"
 
@@ -16,7 +17,7 @@ namespace LIBC_NAMESPACE {
 
 namespace {
 
-Mutex handler_list_mtx(false, false, false);
+[[maybe_unused]] Mutex handler_list_mtx(false, false, false);
 
 using AtExitCallback = void(void *);
 using StdCAtExitCallback = void(void);
@@ -29,12 +30,10 @@ struct AtExitUnit {
 };
 
 #if defined(LIBC_TARGET_ARCH_IS_GPU)
-// The GPU build cannot handle the potentially recursive definitions required by
-// the BlockStore class. Additionally, the liklihood that someone exceeds this
-// while executing on the GPU is extremely small.
-// FIXME: It is not generally safe to use 'atexit' on the GPU because the
-//        mutexes simply passthrough. We will need a lock free stack.
-using ExitCallbackList = FixedVector<AtExitUnit, 64>;
+// The GPU interface cannot use the standard implementation because it does not
+// support the Mutex type. Instead we use a lock free stack with a sufficiently
+// large size.
+using ExitCallbackList = FixedStack<AtExitUnit, CALLBACK_LIST_SIZE_FOR_TESTS>;
 #elif defined(LIBC_COPT_PUBLIC_PACKAGING)
 using ExitCallbackList = cpp::ReverseOrderBlockStore<AtExitUnit, 32>;
 #else
@@ -60,6 +59,11 @@ void stdc_at_exit_func(void *payload) {
 namespace internal {
 
 void call_exit_callbacks() {
+#if defined(LIBC_TARGET_ARCH_IS_GPU)
+  AtExitUnit unit;
+  while (exit_callbacks.pop(unit))
+    unit.callback(unit.payload);
+#else
   handler_list_mtx.lock();
   while (!exit_callbacks.empty()) {
     auto unit = exit_callbacks.back();
@@ -69,14 +73,20 @@ void call_exit_callbacks() {
     handler_list_mtx.lock();
   }
   ExitCallbackList::destroy(&exit_callbacks);
+#endif
 }
 
 } // namespace internal
 
 static int add_atexit_unit(const AtExitUnit &unit) {
+#if defined(LIBC_TARGET_ARCH_IS_GPU)
+  if (!exit_callbacks.push(unit))
+    return -1;
+#else
   MutexLock lock(&handler_list_mtx);
   if (!exit_callbacks.push_back(unit))
     return -1;
+#endif
   return 0;
 }
 



More information about the libc-commits mailing list