Add support for LinuxThreads.
When using LinuxThreads pthread_setspecific triggers recursive allocation on all threads. Work around this by creating a global linked list of in-progress tsd initializations. This modifies the _tsd_get_wrapper macro-generated function. When it has to initialize an TSD object it will push the item to the linked list first. If this causes a recursive allocation then the _get_wrapper request is satisfied from the list. When pthread_setspecific returns the item is removed from the list. This effectively adds a very poor substitute for real TLS used only during pthread_setspecific allocation recursion. Signed-off-by: Crestez Dan Leonard <lcrestez@ixiacom.com>
This commit is contained in:
parent
ac4403cacb
commit
cb17fc6a8f
@ -6,6 +6,12 @@
|
|||||||
|
|
||||||
typedef bool (*malloc_tsd_cleanup_t)(void);
|
typedef bool (*malloc_tsd_cleanup_t)(void);
|
||||||
|
|
||||||
|
#if (!defined(JEMALLOC_MALLOC_THREAD_CLEANUP) && !defined(JEMALLOC_TLS) && \
|
||||||
|
!defined(_WIN32))
|
||||||
|
typedef struct tsd_init_block_s tsd_init_block_t;
|
||||||
|
typedef struct tsd_init_head_s tsd_init_head_t;
|
||||||
|
#endif
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* TLS/TSD-agnostic macro-based implementation of thread-specific data. There
|
* TLS/TSD-agnostic macro-based implementation of thread-specific data. There
|
||||||
* are four macros that support (at least) three use cases: file-private,
|
* are four macros that support (at least) three use cases: file-private,
|
||||||
@ -81,6 +87,7 @@ extern bool a_name##_booted;
|
|||||||
#else
|
#else
|
||||||
#define malloc_tsd_externs(a_name, a_type) \
|
#define malloc_tsd_externs(a_name, a_type) \
|
||||||
extern pthread_key_t a_name##_tsd; \
|
extern pthread_key_t a_name##_tsd; \
|
||||||
|
extern tsd_init_head_t a_name##_tsd_init_head; \
|
||||||
extern bool a_name##_booted;
|
extern bool a_name##_booted;
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
@ -105,6 +112,10 @@ a_attr bool a_name##_booted = false;
|
|||||||
#else
|
#else
|
||||||
#define malloc_tsd_data(a_attr, a_name, a_type, a_initializer) \
|
#define malloc_tsd_data(a_attr, a_name, a_type, a_initializer) \
|
||||||
a_attr pthread_key_t a_name##_tsd; \
|
a_attr pthread_key_t a_name##_tsd; \
|
||||||
|
a_attr tsd_init_head_t a_name##_tsd_init_head = { \
|
||||||
|
ql_head_initializer(blocks), \
|
||||||
|
MALLOC_MUTEX_INITIALIZER \
|
||||||
|
}; \
|
||||||
a_attr bool a_name##_booted = false;
|
a_attr bool a_name##_booted = false;
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
@ -333,8 +344,14 @@ a_name##_tsd_get_wrapper(void) \
|
|||||||
pthread_getspecific(a_name##_tsd); \
|
pthread_getspecific(a_name##_tsd); \
|
||||||
\
|
\
|
||||||
if (wrapper == NULL) { \
|
if (wrapper == NULL) { \
|
||||||
|
tsd_init_block_t block; \
|
||||||
|
wrapper = tsd_init_check_recursion( \
|
||||||
|
&a_name##_tsd_init_head, &block); \
|
||||||
|
if (wrapper) \
|
||||||
|
return wrapper; \
|
||||||
wrapper = (a_name##_tsd_wrapper_t *) \
|
wrapper = (a_name##_tsd_wrapper_t *) \
|
||||||
malloc_tsd_malloc(sizeof(a_name##_tsd_wrapper_t)); \
|
malloc_tsd_malloc(sizeof(a_name##_tsd_wrapper_t)); \
|
||||||
|
block.data = wrapper; \
|
||||||
if (wrapper == NULL) { \
|
if (wrapper == NULL) { \
|
||||||
malloc_write("<jemalloc>: Error allocating" \
|
malloc_write("<jemalloc>: Error allocating" \
|
||||||
" TSD for "#a_name"\n"); \
|
" TSD for "#a_name"\n"); \
|
||||||
@ -350,6 +367,7 @@ a_name##_tsd_get_wrapper(void) \
|
|||||||
" TSD for "#a_name"\n"); \
|
" TSD for "#a_name"\n"); \
|
||||||
abort(); \
|
abort(); \
|
||||||
} \
|
} \
|
||||||
|
tsd_init_finish(&a_name##_tsd_init_head, &block); \
|
||||||
} \
|
} \
|
||||||
return (wrapper); \
|
return (wrapper); \
|
||||||
} \
|
} \
|
||||||
@ -379,6 +397,19 @@ a_name##_tsd_set(a_type *val) \
|
|||||||
/******************************************************************************/
|
/******************************************************************************/
|
||||||
#ifdef JEMALLOC_H_STRUCTS
|
#ifdef JEMALLOC_H_STRUCTS
|
||||||
|
|
||||||
|
#if (!defined(JEMALLOC_MALLOC_THREAD_CLEANUP) && !defined(JEMALLOC_TLS) && \
|
||||||
|
!defined(_WIN32))
|
||||||
|
struct tsd_init_block_s {
|
||||||
|
ql_elm(tsd_init_block_t) link;
|
||||||
|
pthread_t thread;
|
||||||
|
void *data;
|
||||||
|
};
|
||||||
|
struct tsd_init_head_s {
|
||||||
|
ql_head(tsd_init_block_t) blocks;
|
||||||
|
malloc_mutex_t lock;
|
||||||
|
};
|
||||||
|
#endif
|
||||||
|
|
||||||
#endif /* JEMALLOC_H_STRUCTS */
|
#endif /* JEMALLOC_H_STRUCTS */
|
||||||
/******************************************************************************/
|
/******************************************************************************/
|
||||||
#ifdef JEMALLOC_H_EXTERNS
|
#ifdef JEMALLOC_H_EXTERNS
|
||||||
@ -388,6 +419,12 @@ void malloc_tsd_dalloc(void *wrapper);
|
|||||||
void malloc_tsd_no_cleanup(void *);
|
void malloc_tsd_no_cleanup(void *);
|
||||||
void malloc_tsd_cleanup_register(bool (*f)(void));
|
void malloc_tsd_cleanup_register(bool (*f)(void));
|
||||||
void malloc_tsd_boot(void);
|
void malloc_tsd_boot(void);
|
||||||
|
#if (!defined(JEMALLOC_MALLOC_THREAD_CLEANUP) && !defined(JEMALLOC_TLS) && \
|
||||||
|
!defined(_WIN32))
|
||||||
|
void *tsd_init_check_recursion(tsd_init_head_t *head,
|
||||||
|
tsd_init_block_t *block);
|
||||||
|
void tsd_init_finish(tsd_init_head_t *head, tsd_init_block_t *block);
|
||||||
|
#endif
|
||||||
|
|
||||||
#endif /* JEMALLOC_H_EXTERNS */
|
#endif /* JEMALLOC_H_EXTERNS */
|
||||||
/******************************************************************************/
|
/******************************************************************************/
|
||||||
|
34
src/tsd.c
34
src/tsd.c
@ -105,3 +105,37 @@ JEMALLOC_SECTION(".CRT$XLY") JEMALLOC_ATTR(used)
|
|||||||
static const BOOL (WINAPI *tls_callback)(HINSTANCE hinstDLL,
|
static const BOOL (WINAPI *tls_callback)(HINSTANCE hinstDLL,
|
||||||
DWORD fdwReason, LPVOID lpvReserved) = _tls_callback;
|
DWORD fdwReason, LPVOID lpvReserved) = _tls_callback;
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
#if (!defined(JEMALLOC_MALLOC_THREAD_CLEANUP) && !defined(JEMALLOC_TLS) && \
|
||||||
|
!defined(_WIN32))
|
||||||
|
void *
|
||||||
|
tsd_init_check_recursion(tsd_init_head_t *head, tsd_init_block_t *block)
|
||||||
|
{
|
||||||
|
pthread_t self = pthread_self();
|
||||||
|
tsd_init_block_t *iter;
|
||||||
|
|
||||||
|
/* Check whether this thread has already inserted into the list. */
|
||||||
|
malloc_mutex_lock(&head->lock);
|
||||||
|
ql_foreach(iter, &head->blocks, link) {
|
||||||
|
if (iter->thread == self) {
|
||||||
|
malloc_mutex_unlock(&head->lock);
|
||||||
|
return (iter->data);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
/* Insert block into list. */
|
||||||
|
ql_elm_new(block, link);
|
||||||
|
block->thread = self;
|
||||||
|
ql_tail_insert(&head->blocks, block, link);
|
||||||
|
malloc_mutex_unlock(&head->lock);
|
||||||
|
return (NULL);
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
tsd_init_finish(tsd_init_head_t *head, tsd_init_block_t *block)
|
||||||
|
{
|
||||||
|
|
||||||
|
malloc_mutex_lock(&head->lock);
|
||||||
|
ql_remove(&head->blocks, block, link);
|
||||||
|
malloc_mutex_unlock(&head->lock);
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
Loading…
Reference in New Issue
Block a user