Serenity Operating System
at master 107 lines 2.9 kB view raw
1/* 2 * Copyright (c) 2021, the SerenityOS developers. 3 * 4 * SPDX-License-Identifier: BSD-2-Clause 5 */ 6 7#include <AK/Atomic.h> 8#include <errno.h> 9#include <pthread.h> 10#include <unistd.h> 11 12#ifndef _DYNAMIC_LOADER 13extern "C" { 14 15static constexpr int max_keys = PTHREAD_KEYS_MAX; 16 17struct KeyTable { 18 KeyDestructor destructors[max_keys] { nullptr }; 19 int next { 0 }; 20 pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER; 21}; 22 23struct SpecificTable { 24 void* values[max_keys] { nullptr }; 25}; 26 27static KeyTable s_keys; 28 29__thread SpecificTable t_specifics; 30 31// https://pubs.opengroup.org/onlinepubs/009695399/functions/pthread_key_create.html 32int pthread_key_create(pthread_key_t* key, KeyDestructor destructor) 33{ 34 int ret = 0; 35 pthread_mutex_lock(&s_keys.mutex); 36 if (s_keys.next >= max_keys) { 37 ret = EAGAIN; 38 } else { 39 *key = s_keys.next++; 40 s_keys.destructors[*key] = destructor; 41 ret = 0; 42 } 43 pthread_mutex_unlock(&s_keys.mutex); 44 return ret; 45} 46 47// https://pubs.opengroup.org/onlinepubs/009695399/functions/pthread_key_delete.html 48int pthread_key_delete(pthread_key_t key) 49{ 50 if (key < 0 || key >= max_keys) 51 return EINVAL; 52 pthread_mutex_lock(&s_keys.mutex); 53 s_keys.destructors[key] = nullptr; 54 pthread_mutex_unlock(&s_keys.mutex); 55 return 0; 56} 57 58// https://pubs.opengroup.org/onlinepubs/009695399/functions/pthread_getspecific.html 59void* pthread_getspecific(pthread_key_t key) 60{ 61 if (key < 0) 62 return nullptr; 63 if (key >= max_keys) 64 return nullptr; 65 return t_specifics.values[key]; 66} 67 68// https://pubs.opengroup.org/onlinepubs/009695399/functions/pthread_setspecific.html 69int pthread_setspecific(pthread_key_t key, void const* value) 70{ 71 if (key < 0) 72 return EINVAL; 73 if (key >= max_keys) 74 return EINVAL; 75 76 t_specifics.values[key] = const_cast<void*>(value); 77 return 0; 78} 79 80void __pthread_key_destroy_for_current_thread() 81{ 82 // This function will either be called during exit_thread, for a pthread, or 83 // during global program shutdown for the main thread. 84 85 pthread_mutex_lock(&s_keys.mutex); 86 size_t num_used_keys = s_keys.next; 87 88 // Dr. POSIX accounts for weird key destructors setting their own key again. 89 // Or even, setting other unrelated keys? Odd, but whatever the Doc says goes. 90 91 for (size_t destruct_iteration = 0; destruct_iteration < PTHREAD_DESTRUCTOR_ITERATIONS; ++destruct_iteration) { 92 bool any_nonnull_destructors = false; 93 for (size_t key_index = 0; key_index < num_used_keys; ++key_index) { 94 void* value = exchange(t_specifics.values[key_index], nullptr); 95 96 if (value && s_keys.destructors[key_index]) { 97 any_nonnull_destructors = true; 98 (*s_keys.destructors[key_index])(value); 99 } 100 } 101 if (!any_nonnull_destructors) 102 break; 103 } 104 pthread_mutex_unlock(&s_keys.mutex); 105} 106} 107#endif