• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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
27 struct dtor_list {
28     void (*dtor) (void*);
29     void *arg;
30     void *dso_handle;
31     struct dtor_list* next;
32 };
33 
34 #ifndef ENABLE_HWASAN
35 // A list for current thread local dtors.
36 __thread struct dtor_list* thread_local_dtors = NULL;
37 // Whether the current thread local dtors have not been executed or registered.
38 __thread bool thread_local_dtors_alive = false;
39 #endif
40 
41 static pthread_key_t dtors_key;
42 
43 #ifndef ENABLE_HWASAN
run_cur_thread_dtors(void * unused)44 void run_cur_thread_dtors(void *unused)
45 #else
46 void run_cur_thread_dtors(void *thread_local_dtors)
47 #endif
48 {
49     while (thread_local_dtors != NULL) {
50         struct dtor_list* cur = thread_local_dtors;
51         thread_local_dtors = cur->next;
52         cur->dtor(cur->arg);
53         if (remove_dso_handle_node) {
54             remove_dso_handle_node(cur->dso_handle);
55         }
56         __libc_free(cur);
57     }
58 #ifndef ENABLE_HWASAN
59     thread_local_dtors_alive = false;
60 #endif
61     return;
62 }
63 
cxa_thread_init()64 __attribute__((constructor())) void cxa_thread_init()
65 {
66     if (pthread_key_create(&dtors_key, run_cur_thread_dtors) != 0) {
67         abort();
68     }
69     return;
70 }
71 
72 /*
73  * Used for the thread calls exit(include main thread).
74  * We can't register a destructor of libc for run_cur_thread_dtors because of deadlock problem:
75  *   exit -> __libc_exit_fini[acquire init_fini_lock] -> run_cur_thread_dtors ->
76  *   remove_dso_handle_node-> do_dlclose ->dlclose_impl[try to get init_fini_lock] -> deadlock.
77  * So we call __cxa_thread_finalize actively at exit.
78  */
__cxa_thread_finalize()79 void __cxa_thread_finalize()
80 {
81 #ifndef ENABLE_HWASAN
82     run_cur_thread_dtors(NULL);
83 #else
84     run_cur_thread_dtors(pthread_getspecific(dtors_key));
85 #endif
86 
87     return;
88 }
89 
__cxa_thread_atexit_impl(void (* func)(void *),void * arg,void * dso_handle)90 int __cxa_thread_atexit_impl(void (*func)(void*), void *arg, void *dso_handle)
91 {
92 #ifndef ENABLE_HWASAN
93     if (!thread_local_dtors_alive) {
94         // Bind dtors_key to current thread, so that `run_cur_thread_dtors` can be executed when thread exits.
95         if (pthread_setspecific(dtors_key, &dtors_key) != 0) {
96             return -1;
97         }
98         thread_local_dtors_alive = true;
99     }
100 #else
101     struct dtor_list* prev_dtors = pthread_getspecific(dtors_key);
102 #endif
103     struct dtor_list* dtor = __libc_malloc(sizeof(*dtor));
104     if (!dtor) {
105         return -1;
106     }
107     dtor->dtor = func;
108     dtor->arg = arg;
109     dtor->dso_handle = dso_handle;
110 #ifndef ENABLE_HWASAN
111     dtor->next = thread_local_dtors;
112     thread_local_dtors = dtor;
113 #else
114     dtor->next = prev_dtors;
115     pthread_setspecific(dtors_key, dtor);
116 #endif
117     if (add_dso_handle_node != NULL) {
118         add_dso_handle_node(dso_handle);
119     }
120 
121     return 0;
122 }
123 #endif
124 
125 #ifdef CXA_THREAD_USE_TLS
126 
__cxa_thread_atexit_impl(void (* func)(void *),void * arg,void * dso_handle)127 int __cxa_thread_atexit_impl(void (*func)(void*), void *arg, void *dso_handle)
128 {
129     struct thread_local_dtor* dtor = __libc_malloc(sizeof(*dtor));
130     if (!dtor) {
131         return -1;
132     }
133     dtor->func = func;
134     dtor->arg = arg;
135     dtor->dso_handle = dso_handle;
136     pthread_t thr = __pthread_self();
137     dtor->next = thr->thread_local_dtors;
138     thr->thread_local_dtors = dtor;
139     if (add_dso_handle_node != NULL) {
140         add_dso_handle_node(dso_handle);
141     }
142     return 0;
143 }
144 
__cxa_thread_finalize()145 void __cxa_thread_finalize()
146 {
147     pthread_t thr = __pthread_self();
148     while (thr->thread_local_dtors != NULL) {
149         struct thread_local_dtor* cur = thr->thread_local_dtors;
150         thr->thread_local_dtors= cur->next;
151         cur->func(cur->arg);
152         if (remove_dso_handle_node) {
153             remove_dso_handle_node(cur->dso_handle);
154         }
155     }
156     return;
157 }
158 
159 #endif
160 
161