1/* 2 * Copyright (c) 2024 Huawei Device Co., Ltd. 3 * Licensed under the Apache License, Version 2.0 (the "License"); 4 * you may not use this file except in compliance with the License. 5 * You may obtain a copy of the License at 6 * 7 * http://www.apache.org/licenses/LICENSE-2.0 8 * 9 * Unless required by applicable law or agreed to in writing, software 10 * distributed under the License is distributed on an "AS IS" BASIS, 11 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 * See the License for the specific language governing permissions and 13 * limitations under the License. 14 */ 15 16#include "pthread_impl.h" 17 18__attribute__((__weak__)) extern void add_dso_handle_node(void *dso_handle) ; 19__attribute__((__weak__)) extern void remove_dso_handle_node(void *dso_handle); 20 21/* 22 * There are two ways to implement cxa_thread_atexit_impl: 23 * - CXA_THREAD_USE_TSD(default): use pthread_key_xxx to implement cxa_thread_atexit_impl. 24 * - CXA_THREAD_USE_TLS: put dtors in pthread to implement cxa_thread_atexit_impl. 25 */ 26#ifdef CXA_THREAD_USE_TSD 27struct dtor_list { 28 void (*dtor) (void*); 29 void *arg; 30 void *dso_handle; 31 struct dtor_list* next; 32}; 33 34// A list for current thread local dtors. 35__thread struct dtor_list* thread_local_dtors = NULL; 36// Whether the current thread local dtors have not been executed or registered. 37__thread bool thread_local_dtors_alive = false; 38static pthread_key_t dtors_key; 39 40void run_cur_thread_dtors(void *) 41{ 42 while (thread_local_dtors != NULL) { 43 struct dtor_list* cur = thread_local_dtors; 44 thread_local_dtors = cur->next; 45 cur->dtor(cur->arg); 46 if (remove_dso_handle_node) { 47 remove_dso_handle_node(cur->dso_handle); 48 } 49 __libc_free(cur); 50 } 51 thread_local_dtors_alive = false; 52 return; 53} 54 55__attribute__((constructor())) void cxa_thread_init() 56{ 57 if (pthread_key_create(&dtors_key, run_cur_thread_dtors) != 0) { 58 abort(); 59 } 60 return; 61} 62 63/* 64 * Used for the thread calls exit(include main thread). 65 * We can't register a destructor of libc for run_cur_thread_dtors because of deadlock problem: 66 * exit -> __libc_exit_fini[acquire init_fini_lock] -> run_cur_thread_dtors -> 67 * remove_dso_handle_node-> do_dlclose ->dlclose_impl[try to get init_fini_lock] -> deadlock. 68 * So we call __cxa_thread_finalize actively at exit. 69 */ 70void __cxa_thread_finalize() 71{ 72 run_cur_thread_dtors(NULL); 73 return; 74} 75 76int __cxa_thread_atexit_impl(void (*func)(void*), void *arg, void *dso_handle) 77{ 78 if (!thread_local_dtors_alive) { 79 // Bind dtors_key to current thread, so that `run_cur_thread_dtors` can be executed when thread exits. 80 if (pthread_setspecific(dtors_key, &dtors_key) != 0) { 81 return -1; 82 } 83 thread_local_dtors_alive = true; 84 } 85 struct dtor_list* dtor = __libc_malloc(sizeof(*dtor)); 86 if (!dtor) { 87 return -1; 88 } 89 dtor->dtor = func; 90 dtor->arg = arg; 91 dtor->dso_handle = dso_handle; 92 dtor->next = thread_local_dtors; 93 thread_local_dtors = dtor; 94 if (add_dso_handle_node != NULL) { 95 add_dso_handle_node(dso_handle); 96 } 97 98 return 0; 99} 100#endif 101 102#ifdef CXA_THREAD_USE_TLS 103 104int __cxa_thread_atexit_impl(void (*func)(void*), void *arg, void *dso_handle) 105{ 106 struct thread_local_dtor* dtor = __libc_malloc(sizeof(*dtor)); 107 if (!dtor) { 108 return -1; 109 } 110 dtor->func = func; 111 dtor->arg = arg; 112 dtor->dso_handle = dso_handle; 113 pthread_t thr = __pthread_self(); 114 dtor->next = thr->thread_local_dtors; 115 thr->thread_local_dtors = dtor; 116 if (add_dso_handle_node != NULL) { 117 add_dso_handle_node(dso_handle); 118 } 119 return 0; 120} 121 122void __cxa_thread_finalize() 123{ 124 pthread_t thr = __pthread_self(); 125 while (thr->thread_local_dtors != NULL) { 126 struct thread_local_dtor* cur = thr->thread_local_dtors; 127 thr->thread_local_dtors= cur->next; 128 cur->func(cur->arg); 129 if (remove_dso_handle_node) { 130 remove_dso_handle_node(cur->dso_handle); 131 } 132 } 133 return; 134} 135 136#endif 137 138