mirror of
https://github.com/RGBCube/serenity
synced 2025-07-26 06:27:45 +00:00
LibC+LibPthread: Make sure TLS keys are destroyed after everything else
This ensures that __thread variables can be used when global destructors are being invoked.
This commit is contained in:
parent
6eedb570a2
commit
4075b306f8
3 changed files with 18 additions and 12 deletions
|
@ -31,6 +31,7 @@
|
||||||
#include <AK/Types.h>
|
#include <AK/Types.h>
|
||||||
#include <AK/Utf8View.h>
|
#include <AK/Utf8View.h>
|
||||||
#include <LibELF/AuxiliaryVector.h>
|
#include <LibELF/AuxiliaryVector.h>
|
||||||
|
#include <LibPthread/pthread.h>
|
||||||
#include <alloca.h>
|
#include <alloca.h>
|
||||||
#include <assert.h>
|
#include <assert.h>
|
||||||
#include <ctype.h>
|
#include <ctype.h>
|
||||||
|
@ -48,6 +49,8 @@
|
||||||
#include <syscall.h>
|
#include <syscall.h>
|
||||||
#include <unistd.h>
|
#include <unistd.h>
|
||||||
|
|
||||||
|
void (*__libc_pthread_key_destroy_for_current_thread)() = nullptr;
|
||||||
|
|
||||||
static void strtons(const char* str, char** endptr)
|
static void strtons(const char* str, char** endptr)
|
||||||
{
|
{
|
||||||
assert(endptr);
|
assert(endptr);
|
||||||
|
@ -224,6 +227,10 @@ void exit(int status)
|
||||||
_fini();
|
_fini();
|
||||||
fflush(stdout);
|
fflush(stdout);
|
||||||
fflush(stderr);
|
fflush(stderr);
|
||||||
|
|
||||||
|
if (__libc_pthread_key_destroy_for_current_thread)
|
||||||
|
__libc_pthread_key_destroy_for_current_thread();
|
||||||
|
|
||||||
_exit(status);
|
_exit(status);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -46,25 +46,17 @@
|
||||||
namespace {
|
namespace {
|
||||||
using PthreadAttrImpl = Syscall::SC_create_thread_params;
|
using PthreadAttrImpl = Syscall::SC_create_thread_params;
|
||||||
|
|
||||||
struct KeyDestroyer {
|
|
||||||
~KeyDestroyer() { destroy_for_current_thread(); }
|
|
||||||
static void destroy_for_current_thread();
|
|
||||||
};
|
|
||||||
|
|
||||||
} // end anonymous namespace
|
} // end anonymous namespace
|
||||||
|
|
||||||
constexpr size_t required_stack_alignment = 4 * MiB;
|
constexpr size_t required_stack_alignment = 4 * MiB;
|
||||||
constexpr size_t highest_reasonable_guard_size = 32 * PAGE_SIZE;
|
constexpr size_t highest_reasonable_guard_size = 32 * PAGE_SIZE;
|
||||||
constexpr size_t highest_reasonable_stack_size = 8 * MiB; // That's the default in Ubuntu?
|
constexpr size_t highest_reasonable_stack_size = 8 * MiB; // That's the default in Ubuntu?
|
||||||
|
|
||||||
// Create an RAII object with a global destructor to destroy pthread keys for the main thread.
|
|
||||||
// Impact of this: Any global object that wants to do something with pthread_getspecific
|
|
||||||
// in its destructor from the main thread might be in for a nasty surprise.
|
|
||||||
static KeyDestroyer s_key_destroyer;
|
|
||||||
|
|
||||||
#define __RETURN_PTHREAD_ERROR(rc) \
|
#define __RETURN_PTHREAD_ERROR(rc) \
|
||||||
return ((rc) < 0 ? -(rc) : 0)
|
return ((rc) < 0 ? -(rc) : 0)
|
||||||
|
|
||||||
|
extern void (*__libc_pthread_key_destroy_for_current_thread)();
|
||||||
|
|
||||||
extern "C" {
|
extern "C" {
|
||||||
|
|
||||||
static void* pthread_create_helper(void* (*routine)(void*), void* argument)
|
static void* pthread_create_helper(void* (*routine)(void*), void* argument)
|
||||||
|
@ -105,7 +97,7 @@ static int create_thread(pthread_t* thread, void* (*entry)(void*), void* argumen
|
||||||
|
|
||||||
[[noreturn]] static void exit_thread(void* code)
|
[[noreturn]] static void exit_thread(void* code)
|
||||||
{
|
{
|
||||||
KeyDestroyer::destroy_for_current_thread();
|
__pthread_key_destroy_for_current_thread();
|
||||||
syscall(SC_exit_thread, code);
|
syscall(SC_exit_thread, code);
|
||||||
VERIFY_NOT_REACHED();
|
VERIFY_NOT_REACHED();
|
||||||
}
|
}
|
||||||
|
@ -592,7 +584,12 @@ int pthread_setspecific(pthread_key_t key, const void* value)
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
void KeyDestroyer::destroy_for_current_thread()
|
[[gnu::constructor]] static void set_libc_key_destructor()
|
||||||
|
{
|
||||||
|
__libc_pthread_key_destroy_for_current_thread = __pthread_key_destroy_for_current_thread;
|
||||||
|
}
|
||||||
|
|
||||||
|
void __pthread_key_destroy_for_current_thread()
|
||||||
{
|
{
|
||||||
// This function will either be called during exit_thread, for a pthread, or
|
// This function will either be called during exit_thread, for a pthread, or
|
||||||
// during global program shutdown for the main thread.
|
// during global program shutdown for the main thread.
|
||||||
|
|
|
@ -146,4 +146,6 @@ int pthread_rwlockattr_setpshared(pthread_rwlockattr_t*, int);
|
||||||
|
|
||||||
int pthread_atfork(void (*prepare)(void), void (*parent)(void), void (*child)(void));
|
int pthread_atfork(void (*prepare)(void), void (*parent)(void), void (*child)(void));
|
||||||
|
|
||||||
|
void __pthread_key_destroy_for_current_thread();
|
||||||
|
|
||||||
__END_DECLS
|
__END_DECLS
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue