修复C++11 thread_local对象析构函数与实际内存释放动作顺序相反问题
This commit is contained in:
parent
f55187f830
commit
b421b4e1f4
|
@ -9,6 +9,8 @@
|
|||
* thread.
|
||||
* 2019-02-07 Bernard Add _pthread_destroy to release pthread resource.
|
||||
* 2022-05-10 xiangxistu Modify the recycle logic about resource of pthread.
|
||||
* 2024-04-15 atwww Modify the recycle logic of TLS in function _pthread_data_destroy,
|
||||
* make it safe for C++11's thread_local destructors.
|
||||
*/
|
||||
|
||||
#include <rthw.h>
|
||||
|
@ -85,9 +87,27 @@ pthread_t _pthread_data_create(void)
|
|||
return index;
|
||||
}
|
||||
|
||||
void _pthread_data_destroy(_pthread_data_t *ptd)
|
||||
static inline void _destroy_item(int index, _pthread_data_t *ptd)
|
||||
{
|
||||
extern _pthread_key_data_t _thread_keys[PTHREAD_KEY_MAX];
|
||||
void *data;
|
||||
|
||||
if (_thread_keys[index].is_used)
|
||||
{
|
||||
data = ptd->tls[index];
|
||||
if (data && _thread_keys[index].destructor)
|
||||
{
|
||||
_thread_keys[index].destructor(data);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#ifdef RT_USING_CPLUSPLUS11
|
||||
#define NOT_USE_CXX_TLS -1
|
||||
#endif
|
||||
|
||||
void _pthread_data_destroy(_pthread_data_t *ptd)
|
||||
{
|
||||
pthread_t pth;
|
||||
|
||||
if (ptd)
|
||||
|
@ -97,18 +117,37 @@ void _pthread_data_destroy(_pthread_data_t *ptd)
|
|||
*/
|
||||
if (ptd->tls != RT_NULL)
|
||||
{
|
||||
void *data;
|
||||
rt_uint32_t index;
|
||||
int index;
|
||||
#ifdef RT_USING_CPLUSPLUS11
|
||||
/* If C++11 is enabled and emutls is used,
|
||||
* destructors of C++ object must be called safely.
|
||||
*/
|
||||
extern pthread_key_t emutls_get_pthread_key(void);
|
||||
pthread_key_t emutls_pthread_key = emutls_get_pthread_key();
|
||||
|
||||
if (emutls_pthread_key != NOT_USE_CXX_TLS)
|
||||
{
|
||||
/* If execution reaches here, C++ 'thread_local' may be used.
|
||||
* Destructors of c++ class object must be called before emutls_key_destructor.
|
||||
*/
|
||||
int start = ((emutls_pthread_key - 1 + PTHREAD_KEY_MAX) % PTHREAD_KEY_MAX);
|
||||
int i = 0;
|
||||
for (index = start; i < PTHREAD_KEY_MAX; index = (index - 1 + PTHREAD_KEY_MAX) % PTHREAD_KEY_MAX, i ++)
|
||||
{
|
||||
_destroy_item(index, ptd);
|
||||
}
|
||||
}
|
||||
else
|
||||
#endif
|
||||
{
|
||||
/* If only C TLS is used, that is, POSIX TLS or __Thread_local,
|
||||
* just iterate the _thread_keys from index 0.
|
||||
*/
|
||||
for (index = 0; index < PTHREAD_KEY_MAX; index ++)
|
||||
{
|
||||
if (_thread_keys[index].is_used)
|
||||
{
|
||||
data = ptd->tls[index];
|
||||
if (data && _thread_keys[index].destructor)
|
||||
_thread_keys[index].destructor(data);
|
||||
_destroy_item(index, ptd);
|
||||
}
|
||||
}
|
||||
|
||||
/* release tls area */
|
||||
rt_free(ptd->tls);
|
||||
ptd->tls = RT_NULL;
|
||||
|
|
|
@ -0,0 +1,9 @@
|
|||
from building import *
|
||||
|
||||
cwd = GetCurrentDir()
|
||||
src = Glob('*.c')
|
||||
CPPPATH = [cwd]
|
||||
|
||||
group = DefineGroup('POSIX', src, depend = ['RT_USING_PTHREADS'], CPPPATH = CPPPATH)
|
||||
|
||||
Return('group')
|
|
@ -6,6 +6,10 @@
|
|||
* Change Logs:
|
||||
* Date Author Notes
|
||||
* 2021-04-27 peterfan Add copyright header.
|
||||
* 2024-04-15 atwww Add emutls_get_pthread_key to make c++11's thread_local destructe safely.
|
||||
* Use emutls_pthread_key to determine whether C++11 thread_local is used.
|
||||
* Move this file from components\libc\cplusplus\cpp11 to components\libc\posix\tls,
|
||||
* because _Thread_local in C will also use emutls.
|
||||
*/
|
||||
|
||||
/* ===---------- emutls.c - Implements __emutls_get_address ---------------===
|
||||
|
@ -109,7 +113,16 @@ typedef struct emutls_address_array
|
|||
void *data[];
|
||||
} emutls_address_array;
|
||||
|
||||
static pthread_key_t emutls_pthread_key;
|
||||
static pthread_key_t emutls_pthread_key = -1; /* -1 means that TLS in C or C++ is not used. */
|
||||
|
||||
pthread_key_t emutls_get_pthread_key(void)
|
||||
{
|
||||
/* If program uses C or C++ TLS keyword, _Thread_local、__thread or thread_local,
|
||||
* the function emutls_get_index will ensure that emutls_pthread_key is initialized once
|
||||
* when it is first used. Therefore, there is no need to use synchronization measures here.
|
||||
*/
|
||||
return emutls_pthread_key;
|
||||
}
|
||||
|
||||
static void emutls_key_destructor(void *ptr)
|
||||
{
|
Loading…
Reference in New Issue