1570af302Sopenharmony_ci/* 2570af302Sopenharmony_ci * Copyright (c) 2024 Huawei Device Co., Ltd. 3570af302Sopenharmony_ci * Licensed under the Apache License, Version 2.0 (the "License"); 4570af302Sopenharmony_ci * you may not use this file except in compliance with the License. 5570af302Sopenharmony_ci * You may obtain a copy of the License at 6570af302Sopenharmony_ci * 7570af302Sopenharmony_ci * http://www.apache.org/licenses/LICENSE-2.0 8570af302Sopenharmony_ci * 9570af302Sopenharmony_ci * Unless required by applicable law or agreed to in writing, software 10570af302Sopenharmony_ci * distributed under the License is distributed on an "AS IS" BASIS, 11570af302Sopenharmony_ci * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12570af302Sopenharmony_ci * See the License for the specific language governing permissions and 13570af302Sopenharmony_ci * limitations under the License. 14570af302Sopenharmony_ci */ 15570af302Sopenharmony_ci 16570af302Sopenharmony_ci#include "pthread_impl.h" 17570af302Sopenharmony_ci 18570af302Sopenharmony_ci__attribute__((__weak__)) extern void add_dso_handle_node(void *dso_handle) ; 19570af302Sopenharmony_ci__attribute__((__weak__)) extern void remove_dso_handle_node(void *dso_handle); 20570af302Sopenharmony_ci 21570af302Sopenharmony_ci/* 22570af302Sopenharmony_ci * There are two ways to implement cxa_thread_atexit_impl: 23570af302Sopenharmony_ci * - CXA_THREAD_USE_TSD(default): use pthread_key_xxx to implement cxa_thread_atexit_impl. 24570af302Sopenharmony_ci * - CXA_THREAD_USE_TLS: put dtors in pthread to implement cxa_thread_atexit_impl. 25570af302Sopenharmony_ci */ 26570af302Sopenharmony_ci#ifdef CXA_THREAD_USE_TSD 27570af302Sopenharmony_cistruct dtor_list { 28570af302Sopenharmony_ci void (*dtor) (void*); 29570af302Sopenharmony_ci void *arg; 30570af302Sopenharmony_ci void *dso_handle; 31570af302Sopenharmony_ci struct dtor_list* next; 32570af302Sopenharmony_ci}; 33570af302Sopenharmony_ci 34570af302Sopenharmony_ci// A list for current thread local dtors. 35570af302Sopenharmony_ci__thread struct dtor_list* thread_local_dtors = NULL; 36570af302Sopenharmony_ci// Whether the current thread local dtors have not been executed or registered. 37570af302Sopenharmony_ci__thread bool thread_local_dtors_alive = false; 38570af302Sopenharmony_cistatic pthread_key_t dtors_key; 39570af302Sopenharmony_ci 40570af302Sopenharmony_civoid run_cur_thread_dtors(void *) 41570af302Sopenharmony_ci{ 42570af302Sopenharmony_ci while (thread_local_dtors != NULL) { 43570af302Sopenharmony_ci struct dtor_list* cur = thread_local_dtors; 44570af302Sopenharmony_ci thread_local_dtors = cur->next; 45570af302Sopenharmony_ci cur->dtor(cur->arg); 46570af302Sopenharmony_ci if (remove_dso_handle_node) { 47570af302Sopenharmony_ci remove_dso_handle_node(cur->dso_handle); 48570af302Sopenharmony_ci } 49570af302Sopenharmony_ci __libc_free(cur); 50570af302Sopenharmony_ci } 51570af302Sopenharmony_ci thread_local_dtors_alive = false; 52570af302Sopenharmony_ci return; 53570af302Sopenharmony_ci} 54570af302Sopenharmony_ci 55570af302Sopenharmony_ci__attribute__((constructor())) void cxa_thread_init() 56570af302Sopenharmony_ci{ 57570af302Sopenharmony_ci if (pthread_key_create(&dtors_key, run_cur_thread_dtors) != 0) { 58570af302Sopenharmony_ci abort(); 59570af302Sopenharmony_ci } 60570af302Sopenharmony_ci return; 61570af302Sopenharmony_ci} 62570af302Sopenharmony_ci 63570af302Sopenharmony_ci/* 64570af302Sopenharmony_ci * Used for the thread calls exit(include main thread). 65570af302Sopenharmony_ci * We can't register a destructor of libc for run_cur_thread_dtors because of deadlock problem: 66570af302Sopenharmony_ci * exit -> __libc_exit_fini[acquire init_fini_lock] -> run_cur_thread_dtors -> 67570af302Sopenharmony_ci * remove_dso_handle_node-> do_dlclose ->dlclose_impl[try to get init_fini_lock] -> deadlock. 68570af302Sopenharmony_ci * So we call __cxa_thread_finalize actively at exit. 69570af302Sopenharmony_ci */ 70570af302Sopenharmony_civoid __cxa_thread_finalize() 71570af302Sopenharmony_ci{ 72570af302Sopenharmony_ci run_cur_thread_dtors(NULL); 73570af302Sopenharmony_ci return; 74570af302Sopenharmony_ci} 75570af302Sopenharmony_ci 76570af302Sopenharmony_ciint __cxa_thread_atexit_impl(void (*func)(void*), void *arg, void *dso_handle) 77570af302Sopenharmony_ci{ 78570af302Sopenharmony_ci if (!thread_local_dtors_alive) { 79570af302Sopenharmony_ci // Bind dtors_key to current thread, so that `run_cur_thread_dtors` can be executed when thread exits. 80570af302Sopenharmony_ci if (pthread_setspecific(dtors_key, &dtors_key) != 0) { 81570af302Sopenharmony_ci return -1; 82570af302Sopenharmony_ci } 83570af302Sopenharmony_ci thread_local_dtors_alive = true; 84570af302Sopenharmony_ci } 85570af302Sopenharmony_ci struct dtor_list* dtor = __libc_malloc(sizeof(*dtor)); 86570af302Sopenharmony_ci if (!dtor) { 87570af302Sopenharmony_ci return -1; 88570af302Sopenharmony_ci } 89570af302Sopenharmony_ci dtor->dtor = func; 90570af302Sopenharmony_ci dtor->arg = arg; 91570af302Sopenharmony_ci dtor->dso_handle = dso_handle; 92570af302Sopenharmony_ci dtor->next = thread_local_dtors; 93570af302Sopenharmony_ci thread_local_dtors = dtor; 94570af302Sopenharmony_ci if (add_dso_handle_node != NULL) { 95570af302Sopenharmony_ci add_dso_handle_node(dso_handle); 96570af302Sopenharmony_ci } 97570af302Sopenharmony_ci 98570af302Sopenharmony_ci return 0; 99570af302Sopenharmony_ci} 100570af302Sopenharmony_ci#endif 101570af302Sopenharmony_ci 102570af302Sopenharmony_ci#ifdef CXA_THREAD_USE_TLS 103570af302Sopenharmony_ci 104570af302Sopenharmony_ciint __cxa_thread_atexit_impl(void (*func)(void*), void *arg, void *dso_handle) 105570af302Sopenharmony_ci{ 106570af302Sopenharmony_ci struct thread_local_dtor* dtor = __libc_malloc(sizeof(*dtor)); 107570af302Sopenharmony_ci if (!dtor) { 108570af302Sopenharmony_ci return -1; 109570af302Sopenharmony_ci } 110570af302Sopenharmony_ci dtor->func = func; 111570af302Sopenharmony_ci dtor->arg = arg; 112570af302Sopenharmony_ci dtor->dso_handle = dso_handle; 113570af302Sopenharmony_ci pthread_t thr = __pthread_self(); 114570af302Sopenharmony_ci dtor->next = thr->thread_local_dtors; 115570af302Sopenharmony_ci thr->thread_local_dtors = dtor; 116570af302Sopenharmony_ci if (add_dso_handle_node != NULL) { 117570af302Sopenharmony_ci add_dso_handle_node(dso_handle); 118570af302Sopenharmony_ci } 119570af302Sopenharmony_ci return 0; 120570af302Sopenharmony_ci} 121570af302Sopenharmony_ci 122570af302Sopenharmony_civoid __cxa_thread_finalize() 123570af302Sopenharmony_ci{ 124570af302Sopenharmony_ci pthread_t thr = __pthread_self(); 125570af302Sopenharmony_ci while (thr->thread_local_dtors != NULL) { 126570af302Sopenharmony_ci struct thread_local_dtor* cur = thr->thread_local_dtors; 127570af302Sopenharmony_ci thr->thread_local_dtors= cur->next; 128570af302Sopenharmony_ci cur->func(cur->arg); 129570af302Sopenharmony_ci if (remove_dso_handle_node) { 130570af302Sopenharmony_ci remove_dso_handle_node(cur->dso_handle); 131570af302Sopenharmony_ci } 132570af302Sopenharmony_ci } 133570af302Sopenharmony_ci return; 134570af302Sopenharmony_ci} 135570af302Sopenharmony_ci 136570af302Sopenharmony_ci#endif 137570af302Sopenharmony_ci 138