summaryrefslogtreecommitdiff
path: root/Userland
diff options
context:
space:
mode:
authorTim Schumacher <timschumi@gmx.de>2022-05-05 10:37:29 +0200
committerLinus Groh <mail@linusgroh.de>2022-06-10 19:06:46 +0100
commit2a27644220b5eb2c8446db75d8d0604e1befbc92 (patch)
tree15e63a42de5a5a26ade6bc617a68ca2a862d5ea8 /Userland
parentb3e0aed91f1c15c1223b23864efac6d90f31324a (diff)
downloadserenity-2a27644220b5eb2c8446db75d8d0604e1befbc92.zip
LibPthread: Implement cleanup handlers
Diffstat (limited to 'Userland')
-rw-r--r--Userland/Libraries/LibPthread/pthread.cpp49
1 files changed, 36 insertions, 13 deletions
diff --git a/Userland/Libraries/LibPthread/pthread.cpp b/Userland/Libraries/LibPthread/pthread.cpp
index ea1b5b3227..e09f6a6850 100644
--- a/Userland/Libraries/LibPthread/pthread.cpp
+++ b/Userland/Libraries/LibPthread/pthread.cpp
@@ -8,6 +8,7 @@
#include <AK/Atomic.h>
#include <AK/Debug.h>
#include <AK/Format.h>
+#include <AK/SinglyLinkedList.h>
#include <AK/StdLibExtras.h>
#include <Kernel/API/Syscall.h>
#include <LibSystem/syscall.h>
@@ -40,8 +41,27 @@ __thread size_t s_stack_size;
#define __RETURN_PTHREAD_ERROR(rc) \
return ((rc) < 0 ? -(rc) : 0)
+struct CleanupHandler {
+ void (*routine)(void*);
+ void* argument;
+};
+
+static thread_local SinglyLinkedList<CleanupHandler> cleanup_handlers;
+
extern "C" {
+[[noreturn]] static void exit_thread(void* code, void* stack_location, size_t stack_size)
+{
+ __pthread_key_destroy_for_current_thread();
+ syscall(SC_exit_thread, code, stack_location, stack_size);
+ VERIFY_NOT_REACHED();
+}
+
+[[noreturn]] static void pthread_exit_without_cleanup_handlers(void* value_ptr)
+{
+ exit_thread(value_ptr, s_stack_location, s_stack_size);
+}
+
static void* pthread_create_helper(void* (*routine)(void*), void* argument, void* stack_location, size_t stack_size)
{
// HACK: This is a __thread - marked thread-local variable. If we initialize it globally, VERY weird errors happen.
@@ -50,7 +70,7 @@ static void* pthread_create_helper(void* (*routine)(void*), void* argument, void
s_stack_location = stack_location;
s_stack_size = stack_size;
void* ret_val = routine(argument);
- pthread_exit(ret_val);
+ pthread_exit_without_cleanup_handlers(ret_val);
}
static int create_thread(pthread_t* thread, void* (*entry)(void*), void* argument, PthreadAttrImpl* thread_params)
@@ -91,13 +111,6 @@ static int create_thread(pthread_t* thread, void* (*entry)(void*), void* argumen
__RETURN_PTHREAD_ERROR(rc);
}
-[[noreturn]] static void exit_thread(void* code, void* stack_location, size_t stack_size)
-{
- __pthread_key_destroy_for_current_thread();
- syscall(SC_exit_thread, code, stack_location, stack_size);
- VERIFY_NOT_REACHED();
-}
-
// https://pubs.opengroup.org/onlinepubs/009695399/functions/pthread_self.html
int pthread_self()
{
@@ -139,19 +152,29 @@ int pthread_create(pthread_t* thread, pthread_attr_t* attributes, void* (*start_
// https://pubs.opengroup.org/onlinepubs/009695399/functions/pthread_exit.html
void pthread_exit(void* value_ptr)
{
- exit_thread(value_ptr, s_stack_location, s_stack_size);
+ while (!cleanup_handlers.is_empty()) {
+ auto handler = cleanup_handlers.take_first();
+ handler.routine(handler.argument);
+ }
+
+ pthread_exit_without_cleanup_handlers(value_ptr);
}
// https://pubs.opengroup.org/onlinepubs/009695399/functions/pthread_cleanup_push.html
-void pthread_cleanup_push([[maybe_unused]] void (*routine)(void*), [[maybe_unused]] void* arg)
+void pthread_cleanup_push(void (*routine)(void*), void* arg)
{
- TODO();
+ cleanup_handlers.prepend({ routine, arg });
}
// https://pubs.opengroup.org/onlinepubs/009695399/functions/pthread_cleanup_pop.html
-void pthread_cleanup_pop([[maybe_unused]] int execute)
+void pthread_cleanup_pop(int execute)
{
- TODO();
+ VERIFY(!cleanup_handlers.is_empty());
+
+ auto handler = cleanup_handlers.take_first();
+
+ if (execute)
+ handler.routine(handler.argument);
}
// https://pubs.opengroup.org/onlinepubs/009695399/functions/pthread_join.html