Skip to content

Commit b421b4e

Browse files
authored
修复C++11 thread_local对象析构函数与实际内存释放动作顺序相反问题
1 parent f55187f commit b421b4e

File tree

3 files changed

+71
-10
lines changed

3 files changed

+71
-10
lines changed

components/libc/posix/pthreads/pthread.c

+48-9
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,8 @@
99
* thread.
1010
* 2019-02-07 Bernard Add _pthread_destroy to release pthread resource.
1111
* 2022-05-10 xiangxistu Modify the recycle logic about resource of pthread.
12+
* 2024-04-15 atwww Modify the recycle logic of TLS in function _pthread_data_destroy,
13+
* make it safe for C++11's thread_local destructors.
1214
*/
1315

1416
#include <rthw.h>
@@ -85,9 +87,27 @@ pthread_t _pthread_data_create(void)
8587
return index;
8688
}
8789

88-
void _pthread_data_destroy(_pthread_data_t *ptd)
90+
static inline void _destroy_item(int index, _pthread_data_t *ptd)
8991
{
9092
extern _pthread_key_data_t _thread_keys[PTHREAD_KEY_MAX];
93+
void *data;
94+
95+
if (_thread_keys[index].is_used)
96+
{
97+
data = ptd->tls[index];
98+
if (data && _thread_keys[index].destructor)
99+
{
100+
_thread_keys[index].destructor(data);
101+
}
102+
}
103+
}
104+
105+
#ifdef RT_USING_CPLUSPLUS11
106+
#define NOT_USE_CXX_TLS -1
107+
#endif
108+
109+
void _pthread_data_destroy(_pthread_data_t *ptd)
110+
{
91111
pthread_t pth;
92112

93113
if (ptd)
@@ -97,18 +117,37 @@ void _pthread_data_destroy(_pthread_data_t *ptd)
97117
*/
98118
if (ptd->tls != RT_NULL)
99119
{
100-
void *data;
101-
rt_uint32_t index;
102-
for (index = 0; index < PTHREAD_KEY_MAX; index ++)
120+
int index;
121+
#ifdef RT_USING_CPLUSPLUS11
122+
/* If C++11 is enabled and emutls is used,
123+
* destructors of C++ object must be called safely.
124+
*/
125+
extern pthread_key_t emutls_get_pthread_key(void);
126+
pthread_key_t emutls_pthread_key = emutls_get_pthread_key();
127+
128+
if (emutls_pthread_key != NOT_USE_CXX_TLS)
103129
{
104-
if (_thread_keys[index].is_used)
130+
/* If execution reaches here, C++ 'thread_local' may be used.
131+
* Destructors of c++ class object must be called before emutls_key_destructor.
132+
*/
133+
int start = ((emutls_pthread_key - 1 + PTHREAD_KEY_MAX) % PTHREAD_KEY_MAX);
134+
int i = 0;
135+
for (index = start; i < PTHREAD_KEY_MAX; index = (index - 1 + PTHREAD_KEY_MAX) % PTHREAD_KEY_MAX, i ++)
105136
{
106-
data = ptd->tls[index];
107-
if (data && _thread_keys[index].destructor)
108-
_thread_keys[index].destructor(data);
137+
_destroy_item(index, ptd);
138+
}
139+
}
140+
else
141+
#endif
142+
{
143+
/* If only C TLS is used, that is, POSIX TLS or __Thread_local,
144+
* just iterate the _thread_keys from index 0.
145+
*/
146+
for (index = 0; index < PTHREAD_KEY_MAX; index ++)
147+
{
148+
_destroy_item(index, ptd);
109149
}
110150
}
111-
112151
/* release tls area */
113152
rt_free(ptd->tls);
114153
ptd->tls = RT_NULL;

components/libc/posix/tls/SConscript

+9
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
from building import *
2+
3+
cwd = GetCurrentDir()
4+
src = Glob('*.c')
5+
CPPPATH = [cwd]
6+
7+
group = DefineGroup('POSIX', src, depend = ['RT_USING_PTHREADS'], CPPPATH = CPPPATH)
8+
9+
Return('group')

components/libc/cplusplus/cpp11/emutls.c renamed to components/libc/posix/tls/emutls.c

+14-1
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,10 @@
66
* Change Logs:
77
* Date Author Notes
88
* 2021-04-27 peterfan Add copyright header.
9+
* 2024-04-15 atwww Add emutls_get_pthread_key to make c++11's thread_local destructe safely.
10+
* Use emutls_pthread_key to determine whether C++11 thread_local is used.
11+
* Move this file from components\libc\cplusplus\cpp11 to components\libc\posix\tls,
12+
* because _Thread_local in C will also use emutls.
913
*/
1014

1115
/* ===---------- emutls.c - Implements __emutls_get_address ---------------===
@@ -109,7 +113,16 @@ typedef struct emutls_address_array
109113
void *data[];
110114
} emutls_address_array;
111115

112-
static pthread_key_t emutls_pthread_key;
116+
static pthread_key_t emutls_pthread_key = -1; /* -1 means that TLS in C or C++ is not used. */
117+
118+
pthread_key_t emutls_get_pthread_key(void)
119+
{
120+
/* If program uses C or C++ TLS keyword, _Thread_local、__thread or thread_local,
121+
* the function emutls_get_index will ensure that emutls_pthread_key is initialized once
122+
* when it is first used. Therefore, there is no need to use synchronization measures here.
123+
*/
124+
return emutls_pthread_key;
125+
}
113126

114127
static void emutls_key_destructor(void *ptr)
115128
{

0 commit comments

Comments
 (0)