123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792 |
- /*
- +----------------------------------------------------------------------+
- | Thread Safe Resource Manager |
- +----------------------------------------------------------------------+
- | Copyright (c) 1999-2011, Andi Gutmans, Sascha Schumann, Zeev Suraski |
- | This source file is subject to the TSRM license, that is bundled |
- | with this package in the file LICENSE |
- +----------------------------------------------------------------------+
- | Authors: Zeev Suraski <zeev@php.net> |
- +----------------------------------------------------------------------+
- */
- #include "TSRM.h"
- #ifdef ZTS
- #include <stdio.h>
- #include <stdarg.h>
- #if ZEND_DEBUG
- # include <assert.h>
- # define TSRM_ASSERT(c) assert(c)
- #else
- # define TSRM_ASSERT(c)
- #endif
- typedef struct _tsrm_tls_entry tsrm_tls_entry;
- /* TSRMLS_CACHE_DEFINE; is already done in Zend, this is being always compiled statically. */
- TSRMLS_CACHE_EXTERN();
- struct _tsrm_tls_entry {
- void **storage;
- int count;
- THREAD_T thread_id;
- tsrm_tls_entry *next;
- };
- typedef struct {
- size_t size;
- ts_allocate_ctor ctor;
- ts_allocate_dtor dtor;
- size_t fast_offset;
- int done;
- } tsrm_resource_type;
- /* The memory manager table */
- static tsrm_tls_entry **tsrm_tls_table=NULL;
- static int tsrm_tls_table_size;
- static ts_rsrc_id id_count;
- /* The resource sizes table */
- static tsrm_resource_type *resource_types_table=NULL;
- static int resource_types_table_size;
- /* Reserved space for fast globals access */
- static size_t tsrm_reserved_pos = 0;
- static size_t tsrm_reserved_size = 0;
- static MUTEX_T tsmm_mutex; /* thread-safe memory manager mutex */
- static MUTEX_T tsrm_env_mutex; /* tsrm environ mutex */
- /* New thread handlers */
- static tsrm_thread_begin_func_t tsrm_new_thread_begin_handler = NULL;
- static tsrm_thread_end_func_t tsrm_new_thread_end_handler = NULL;
- static tsrm_shutdown_func_t tsrm_shutdown_handler = NULL;
- /* Debug support */
- int tsrm_error(int level, const char *format, ...);
- /* Read a resource from a thread's resource storage */
- static int tsrm_error_level;
- static FILE *tsrm_error_file;
- #ifdef TSRM_DEBUG
- #define TSRM_ERROR(args) tsrm_error args
- #define TSRM_SAFE_RETURN_RSRC(array, offset, range) \
- { \
- int unshuffled_offset = TSRM_UNSHUFFLE_RSRC_ID(offset); \
- \
- if (offset==0) { \
- return &array; \
- } else if ((unshuffled_offset)>=0 && (unshuffled_offset)<(range)) { \
- TSRM_ERROR((TSRM_ERROR_LEVEL_INFO, "Successfully fetched resource id %d for thread id %ld - 0x%0.8X", \
- unshuffled_offset, (long) thread_resources->thread_id, array[unshuffled_offset])); \
- return array[unshuffled_offset]; \
- } else { \
- TSRM_ERROR((TSRM_ERROR_LEVEL_ERROR, "Resource id %d is out of range (%d..%d)", \
- unshuffled_offset, TSRM_SHUFFLE_RSRC_ID(0), TSRM_SHUFFLE_RSRC_ID(thread_resources->count-1))); \
- return NULL; \
- } \
- }
- #else
- #define TSRM_ERROR(args)
- #define TSRM_SAFE_RETURN_RSRC(array, offset, range) \
- if (offset==0) { \
- return &array; \
- } else { \
- return array[TSRM_UNSHUFFLE_RSRC_ID(offset)]; \
- }
- #endif
- #ifdef TSRM_WIN32
- static DWORD tls_key;
- # define tsrm_tls_set(what) TlsSetValue(tls_key, (void*)(what))
- # define tsrm_tls_get() TlsGetValue(tls_key)
- #else
- static pthread_key_t tls_key;
- # define tsrm_tls_set(what) pthread_setspecific(tls_key, (void*)(what))
- # define tsrm_tls_get() pthread_getspecific(tls_key)
- #endif
- TSRM_TLS uint8_t in_main_thread = 0;
- TSRM_TLS uint8_t is_thread_shutdown = 0;
- /* Startup TSRM (call once for the entire process) */
- TSRM_API int tsrm_startup(int expected_threads, int expected_resources, int debug_level, const char *debug_filename)
- {/*{{{*/
- #ifdef TSRM_WIN32
- tls_key = TlsAlloc();
- #else
- pthread_key_create(&tls_key, 0);
- #endif
- /* ensure singleton */
- in_main_thread = 1;
- is_thread_shutdown = 0;
- tsrm_error_file = stderr;
- tsrm_error_set(debug_level, debug_filename);
- tsrm_tls_table_size = expected_threads;
- tsrm_tls_table = (tsrm_tls_entry **) calloc(tsrm_tls_table_size, sizeof(tsrm_tls_entry *));
- if (!tsrm_tls_table) {
- TSRM_ERROR((TSRM_ERROR_LEVEL_ERROR, "Unable to allocate TLS table"));
- is_thread_shutdown = 1;
- return 0;
- }
- id_count=0;
- resource_types_table_size = expected_resources;
- resource_types_table = (tsrm_resource_type *) calloc(resource_types_table_size, sizeof(tsrm_resource_type));
- if (!resource_types_table) {
- TSRM_ERROR((TSRM_ERROR_LEVEL_ERROR, "Unable to allocate resource types table"));
- is_thread_shutdown = 1;
- free(tsrm_tls_table);
- return 0;
- }
- tsmm_mutex = tsrm_mutex_alloc();
- TSRM_ERROR((TSRM_ERROR_LEVEL_CORE, "Started up TSRM, %d expected threads, %d expected resources", expected_threads, expected_resources));
- tsrm_reserved_pos = 0;
- tsrm_reserved_size = 0;
- tsrm_env_mutex = tsrm_mutex_alloc();
- return 1;
- }/*}}}*/
- /* Shutdown TSRM (call once for the entire process) */
- TSRM_API void tsrm_shutdown(void)
- {/*{{{*/
- int i;
- if (is_thread_shutdown) {
- /* shutdown must only occur once */
- return;
- }
- is_thread_shutdown = 1;
- if (!in_main_thread) {
- /* only the main thread may shutdown tsrm */
- return;
- }
- for (i=0; i<tsrm_tls_table_size; i++) {
- tsrm_tls_entry *p = tsrm_tls_table[i], *next_p;
- while (p) {
- int j;
- next_p = p->next;
- for (j=0; j<p->count; j++) {
- if (p->storage[j]) {
- if (resource_types_table) {
- if (!resource_types_table[j].done) {
- if (resource_types_table[j].dtor) {
- resource_types_table[j].dtor(p->storage[j]);
- }
- if (!resource_types_table[j].fast_offset) {
- free(p->storage[j]);
- }
- }
- }
- }
- }
- free(p->storage);
- free(p);
- p = next_p;
- }
- }
- free(tsrm_tls_table);
- free(resource_types_table);
- tsrm_mutex_free(tsmm_mutex);
- tsrm_mutex_free(tsrm_env_mutex);
- TSRM_ERROR((TSRM_ERROR_LEVEL_CORE, "Shutdown TSRM"));
- if (tsrm_error_file!=stderr) {
- fclose(tsrm_error_file);
- }
- #ifdef TSRM_WIN32
- TlsFree(tls_key);
- #else
- pthread_setspecific(tls_key, 0);
- pthread_key_delete(tls_key);
- #endif
- if (tsrm_shutdown_handler) {
- tsrm_shutdown_handler();
- }
- tsrm_new_thread_begin_handler = NULL;
- tsrm_new_thread_end_handler = NULL;
- tsrm_shutdown_handler = NULL;
- tsrm_reserved_pos = 0;
- tsrm_reserved_size = 0;
- }/*}}}*/
- /* {{{ */
- /* environ lock api */
- TSRM_API void tsrm_env_lock(void) {
- tsrm_mutex_lock(tsrm_env_mutex);
- }
- TSRM_API void tsrm_env_unlock(void) {
- tsrm_mutex_unlock(tsrm_env_mutex);
- } /* }}} */
- /* enlarge the arrays for the already active threads */
- static void tsrm_update_active_threads(void)
- {/*{{{*/
- int i;
- for (i=0; i<tsrm_tls_table_size; i++) {
- tsrm_tls_entry *p = tsrm_tls_table[i];
- while (p) {
- if (p->count < id_count) {
- int j;
- p->storage = (void *) realloc(p->storage, sizeof(void *)*id_count);
- for (j=p->count; j<id_count; j++) {
- if (resource_types_table[j].fast_offset) {
- p->storage[j] = (void *) (((char*)p) + resource_types_table[j].fast_offset);
- } else {
- p->storage[j] = (void *) malloc(resource_types_table[j].size);
- }
- if (resource_types_table[j].ctor) {
- resource_types_table[j].ctor(p->storage[j]);
- }
- }
- p->count = id_count;
- }
- p = p->next;
- }
- }
- }/*}}}*/
- /* allocates a new thread-safe-resource id */
- TSRM_API ts_rsrc_id ts_allocate_id(ts_rsrc_id *rsrc_id, size_t size, ts_allocate_ctor ctor, ts_allocate_dtor dtor)
- {/*{{{*/
- TSRM_ERROR((TSRM_ERROR_LEVEL_CORE, "Obtaining a new resource id, %d bytes", size));
- tsrm_mutex_lock(tsmm_mutex);
- /* obtain a resource id */
- *rsrc_id = TSRM_SHUFFLE_RSRC_ID(id_count++);
- TSRM_ERROR((TSRM_ERROR_LEVEL_CORE, "Obtained resource id %d", *rsrc_id));
- /* store the new resource type in the resource sizes table */
- if (resource_types_table_size < id_count) {
- tsrm_resource_type *_tmp;
- _tmp = (tsrm_resource_type *) realloc(resource_types_table, sizeof(tsrm_resource_type)*id_count);
- if (!_tmp) {
- TSRM_ERROR((TSRM_ERROR_LEVEL_ERROR, "Unable to allocate storage for resource"));
- *rsrc_id = 0;
- tsrm_mutex_unlock(tsmm_mutex);
- return 0;
- }
- resource_types_table = _tmp;
- resource_types_table_size = id_count;
- }
- resource_types_table[TSRM_UNSHUFFLE_RSRC_ID(*rsrc_id)].size = size;
- resource_types_table[TSRM_UNSHUFFLE_RSRC_ID(*rsrc_id)].ctor = ctor;
- resource_types_table[TSRM_UNSHUFFLE_RSRC_ID(*rsrc_id)].dtor = dtor;
- resource_types_table[TSRM_UNSHUFFLE_RSRC_ID(*rsrc_id)].fast_offset = 0;
- resource_types_table[TSRM_UNSHUFFLE_RSRC_ID(*rsrc_id)].done = 0;
- tsrm_update_active_threads();
- tsrm_mutex_unlock(tsmm_mutex);
- TSRM_ERROR((TSRM_ERROR_LEVEL_CORE, "Successfully allocated new resource id %d", *rsrc_id));
- return *rsrc_id;
- }/*}}}*/
- /* Reserve space for fast thread-safe-resources */
- TSRM_API void tsrm_reserve(size_t size)
- {/*{{{*/
- tsrm_reserved_pos = 0;
- tsrm_reserved_size = TSRM_ALIGNED_SIZE(size);
- }/*}}}*/
- /* allocates a new fast thread-safe-resource id */
- TSRM_API ts_rsrc_id ts_allocate_fast_id(ts_rsrc_id *rsrc_id, size_t *offset, size_t size, ts_allocate_ctor ctor, ts_allocate_dtor dtor)
- {/*{{{*/
- TSRM_ERROR((TSRM_ERROR_LEVEL_CORE, "Obtaining a new fast resource id, %d bytes", size));
- tsrm_mutex_lock(tsmm_mutex);
- /* obtain a resource id */
- *rsrc_id = TSRM_SHUFFLE_RSRC_ID(id_count++);
- TSRM_ERROR((TSRM_ERROR_LEVEL_CORE, "Obtained resource id %d", *rsrc_id));
- size = TSRM_ALIGNED_SIZE(size);
- if (tsrm_reserved_size - tsrm_reserved_pos < size) {
- TSRM_ERROR((TSRM_ERROR_LEVEL_ERROR, "Unable to allocate space for fast resource"));
- *rsrc_id = 0;
- *offset = 0;
- tsrm_mutex_unlock(tsmm_mutex);
- return 0;
- }
- *offset = TSRM_ALIGNED_SIZE(sizeof(tsrm_tls_entry)) + tsrm_reserved_pos;
- tsrm_reserved_pos += size;
- /* store the new resource type in the resource sizes table */
- if (resource_types_table_size < id_count) {
- tsrm_resource_type *_tmp;
- _tmp = (tsrm_resource_type *) realloc(resource_types_table, sizeof(tsrm_resource_type)*id_count);
- if (!_tmp) {
- TSRM_ERROR((TSRM_ERROR_LEVEL_ERROR, "Unable to allocate storage for resource"));
- *rsrc_id = 0;
- tsrm_mutex_unlock(tsmm_mutex);
- return 0;
- }
- resource_types_table = _tmp;
- resource_types_table_size = id_count;
- }
- resource_types_table[TSRM_UNSHUFFLE_RSRC_ID(*rsrc_id)].size = size;
- resource_types_table[TSRM_UNSHUFFLE_RSRC_ID(*rsrc_id)].ctor = ctor;
- resource_types_table[TSRM_UNSHUFFLE_RSRC_ID(*rsrc_id)].dtor = dtor;
- resource_types_table[TSRM_UNSHUFFLE_RSRC_ID(*rsrc_id)].fast_offset = *offset;
- resource_types_table[TSRM_UNSHUFFLE_RSRC_ID(*rsrc_id)].done = 0;
- tsrm_update_active_threads();
- tsrm_mutex_unlock(tsmm_mutex);
- TSRM_ERROR((TSRM_ERROR_LEVEL_CORE, "Successfully allocated new resource id %d", *rsrc_id));
- return *rsrc_id;
- }/*}}}*/
- static void allocate_new_resource(tsrm_tls_entry **thread_resources_ptr, THREAD_T thread_id)
- {/*{{{*/
- int i;
- TSRM_ERROR((TSRM_ERROR_LEVEL_CORE, "Creating data structures for thread %x", thread_id));
- (*thread_resources_ptr) = (tsrm_tls_entry *) malloc(TSRM_ALIGNED_SIZE(sizeof(tsrm_tls_entry)) + tsrm_reserved_size);
- (*thread_resources_ptr)->storage = NULL;
- if (id_count > 0) {
- (*thread_resources_ptr)->storage = (void **) malloc(sizeof(void *)*id_count);
- }
- (*thread_resources_ptr)->count = id_count;
- (*thread_resources_ptr)->thread_id = thread_id;
- (*thread_resources_ptr)->next = NULL;
- /* Set thread local storage to this new thread resources structure */
- tsrm_tls_set(*thread_resources_ptr);
- TSRMLS_CACHE = *thread_resources_ptr;
- if (tsrm_new_thread_begin_handler) {
- tsrm_new_thread_begin_handler(thread_id);
- }
- for (i=0; i<id_count; i++) {
- if (resource_types_table[i].done) {
- (*thread_resources_ptr)->storage[i] = NULL;
- } else {
- if (resource_types_table[i].fast_offset) {
- (*thread_resources_ptr)->storage[i] = (void *) (((char*)(*thread_resources_ptr)) + resource_types_table[i].fast_offset);
- } else {
- (*thread_resources_ptr)->storage[i] = (void *) malloc(resource_types_table[i].size);
- }
- if (resource_types_table[i].ctor) {
- resource_types_table[i].ctor((*thread_resources_ptr)->storage[i]);
- }
- }
- }
- if (tsrm_new_thread_end_handler) {
- tsrm_new_thread_end_handler(thread_id);
- }
- tsrm_mutex_unlock(tsmm_mutex);
- }/*}}}*/
- /* fetches the requested resource for the current thread */
- TSRM_API void *ts_resource_ex(ts_rsrc_id id, THREAD_T *th_id)
- {/*{{{*/
- THREAD_T thread_id;
- int hash_value;
- tsrm_tls_entry *thread_resources;
- if (!th_id) {
- /* Fast path for looking up the resources for the current
- * thread. Its used by just about every call to
- * ts_resource_ex(). This avoids the need for a mutex lock
- * and our hashtable lookup.
- */
- thread_resources = tsrm_tls_get();
- if (thread_resources) {
- TSRM_ERROR((TSRM_ERROR_LEVEL_INFO, "Fetching resource id %d for current thread %d", id, (long) thread_resources->thread_id));
- /* Read a specific resource from the thread's resources.
- * This is called outside of a mutex, so have to be aware about external
- * changes to the structure as we read it.
- */
- TSRM_SAFE_RETURN_RSRC(thread_resources->storage, id, thread_resources->count);
- }
- thread_id = tsrm_thread_id();
- } else {
- thread_id = *th_id;
- }
- TSRM_ERROR((TSRM_ERROR_LEVEL_INFO, "Fetching resource id %d for thread %ld", id, (long) thread_id));
- tsrm_mutex_lock(tsmm_mutex);
- hash_value = THREAD_HASH_OF(thread_id, tsrm_tls_table_size);
- thread_resources = tsrm_tls_table[hash_value];
- if (!thread_resources) {
- allocate_new_resource(&tsrm_tls_table[hash_value], thread_id);
- return ts_resource_ex(id, &thread_id);
- } else {
- do {
- if (thread_resources->thread_id == thread_id) {
- break;
- }
- if (thread_resources->next) {
- thread_resources = thread_resources->next;
- } else {
- allocate_new_resource(&thread_resources->next, thread_id);
- return ts_resource_ex(id, &thread_id);
- /*
- * thread_resources = thread_resources->next;
- * break;
- */
- }
- } while (thread_resources);
- }
- tsrm_mutex_unlock(tsmm_mutex);
- /* Read a specific resource from the thread's resources.
- * This is called outside of a mutex, so have to be aware about external
- * changes to the structure as we read it.
- */
- TSRM_SAFE_RETURN_RSRC(thread_resources->storage, id, thread_resources->count);
- }/*}}}*/
- /* frees all resources allocated for the current thread */
- void ts_free_thread(void)
- {/*{{{*/
- tsrm_tls_entry *thread_resources;
- int i;
- THREAD_T thread_id = tsrm_thread_id();
- int hash_value;
- tsrm_tls_entry *last=NULL;
- TSRM_ASSERT(!in_main_thread);
- tsrm_mutex_lock(tsmm_mutex);
- hash_value = THREAD_HASH_OF(thread_id, tsrm_tls_table_size);
- thread_resources = tsrm_tls_table[hash_value];
- while (thread_resources) {
- if (thread_resources->thread_id == thread_id) {
- for (i=0; i<thread_resources->count; i++) {
- if (resource_types_table[i].dtor) {
- resource_types_table[i].dtor(thread_resources->storage[i]);
- }
- }
- for (i=0; i<thread_resources->count; i++) {
- if (!resource_types_table[i].fast_offset) {
- free(thread_resources->storage[i]);
- }
- }
- free(thread_resources->storage);
- if (last) {
- last->next = thread_resources->next;
- } else {
- tsrm_tls_table[hash_value] = thread_resources->next;
- }
- tsrm_tls_set(0);
- free(thread_resources);
- break;
- }
- if (thread_resources->next) {
- last = thread_resources;
- }
- thread_resources = thread_resources->next;
- }
- tsrm_mutex_unlock(tsmm_mutex);
- }/*}}}*/
- /* deallocates all occurrences of a given id */
- void ts_free_id(ts_rsrc_id id)
- {/*{{{*/
- int i;
- int j = TSRM_UNSHUFFLE_RSRC_ID(id);
- tsrm_mutex_lock(tsmm_mutex);
- TSRM_ERROR((TSRM_ERROR_LEVEL_CORE, "Freeing resource id %d", id));
- if (tsrm_tls_table) {
- for (i=0; i<tsrm_tls_table_size; i++) {
- tsrm_tls_entry *p = tsrm_tls_table[i];
- while (p) {
- if (p->count > j && p->storage[j]) {
- if (resource_types_table) {
- if (resource_types_table[j].dtor) {
- resource_types_table[j].dtor(p->storage[j]);
- }
- if (!resource_types_table[j].fast_offset) {
- free(p->storage[j]);
- }
- }
- p->storage[j] = NULL;
- }
- p = p->next;
- }
- }
- }
- resource_types_table[j].done = 1;
- tsrm_mutex_unlock(tsmm_mutex);
- TSRM_ERROR((TSRM_ERROR_LEVEL_CORE, "Successfully freed resource id %d", id));
- }/*}}}*/
- /*
- * Utility Functions
- */
- /* Obtain the current thread id */
- TSRM_API THREAD_T tsrm_thread_id(void)
- {/*{{{*/
- #ifdef TSRM_WIN32
- return GetCurrentThreadId();
- #else
- return pthread_self();
- #endif
- }/*}}}*/
- /* Allocate a mutex */
- TSRM_API MUTEX_T tsrm_mutex_alloc(void)
- {/*{{{*/
- MUTEX_T mutexp;
- #ifdef TSRM_WIN32
- mutexp = malloc(sizeof(CRITICAL_SECTION));
- InitializeCriticalSection(mutexp);
- #else
- mutexp = (pthread_mutex_t *)malloc(sizeof(pthread_mutex_t));
- pthread_mutex_init(mutexp,NULL);
- #endif
- #ifdef THR_DEBUG
- printf("Mutex created thread: %d\n",mythreadid());
- #endif
- return( mutexp );
- }/*}}}*/
- /* Free a mutex */
- TSRM_API void tsrm_mutex_free(MUTEX_T mutexp)
- {/*{{{*/
- if (mutexp) {
- #ifdef TSRM_WIN32
- DeleteCriticalSection(mutexp);
- free(mutexp);
- #else
- pthread_mutex_destroy(mutexp);
- free(mutexp);
- #endif
- }
- #ifdef THR_DEBUG
- printf("Mutex freed thread: %d\n",mythreadid());
- #endif
- }/*}}}*/
- /*
- Lock a mutex.
- A return value of 0 indicates success
- */
- TSRM_API int tsrm_mutex_lock(MUTEX_T mutexp)
- {/*{{{*/
- TSRM_ERROR((TSRM_ERROR_LEVEL_INFO, "Mutex locked thread: %ld", tsrm_thread_id()));
- #ifdef TSRM_WIN32
- EnterCriticalSection(mutexp);
- return 0;
- #else
- return pthread_mutex_lock(mutexp);
- #endif
- }/*}}}*/
- /*
- Unlock a mutex.
- A return value of 0 indicates success
- */
- TSRM_API int tsrm_mutex_unlock(MUTEX_T mutexp)
- {/*{{{*/
- TSRM_ERROR((TSRM_ERROR_LEVEL_INFO, "Mutex unlocked thread: %ld", tsrm_thread_id()));
- #ifdef TSRM_WIN32
- LeaveCriticalSection(mutexp);
- return 0;
- #else
- return pthread_mutex_unlock(mutexp);
- #endif
- }/*}}}*/
- /*
- Changes the signal mask of the calling thread
- */
- #ifdef HAVE_SIGPROCMASK
- TSRM_API int tsrm_sigmask(int how, const sigset_t *set, sigset_t *oldset)
- {/*{{{*/
- TSRM_ERROR((TSRM_ERROR_LEVEL_INFO, "Changed sigmask in thread: %ld", tsrm_thread_id()));
- return pthread_sigmask(how, set, oldset);
- }/*}}}*/
- #endif
- TSRM_API void *tsrm_set_new_thread_begin_handler(tsrm_thread_begin_func_t new_thread_begin_handler)
- {/*{{{*/
- void *retval = (void *) tsrm_new_thread_begin_handler;
- tsrm_new_thread_begin_handler = new_thread_begin_handler;
- return retval;
- }/*}}}*/
- TSRM_API void *tsrm_set_new_thread_end_handler(tsrm_thread_end_func_t new_thread_end_handler)
- {/*{{{*/
- void *retval = (void *) tsrm_new_thread_end_handler;
- tsrm_new_thread_end_handler = new_thread_end_handler;
- return retval;
- }/*}}}*/
- TSRM_API void *tsrm_set_shutdown_handler(tsrm_shutdown_func_t shutdown_handler)
- {/*{{{*/
- void *retval = (void *) tsrm_shutdown_handler;
- tsrm_shutdown_handler = shutdown_handler;
- return retval;
- }/*}}}*/
- /*
- * Debug support
- */
- #ifdef TSRM_DEBUG
- int tsrm_error(int level, const char *format, ...)
- {/*{{{*/
- if (level<=tsrm_error_level) {
- va_list args;
- int size;
- fprintf(tsrm_error_file, "TSRM: ");
- va_start(args, format);
- size = vfprintf(tsrm_error_file, format, args);
- va_end(args);
- fprintf(tsrm_error_file, "\n");
- fflush(tsrm_error_file);
- return size;
- } else {
- return 0;
- }
- }/*}}}*/
- #endif
- void tsrm_error_set(int level, const char *debug_filename)
- {/*{{{*/
- tsrm_error_level = level;
- #ifdef TSRM_DEBUG
- if (tsrm_error_file!=stderr) { /* close files opened earlier */
- fclose(tsrm_error_file);
- }
- if (debug_filename) {
- tsrm_error_file = fopen(debug_filename, "w");
- if (!tsrm_error_file) {
- tsrm_error_file = stderr;
- }
- } else {
- tsrm_error_file = stderr;
- }
- #endif
- }/*}}}*/
- TSRM_API void *tsrm_get_ls_cache(void)
- {/*{{{*/
- return tsrm_tls_get();
- }/*}}}*/
- /* Returns offset of tsrm_ls_cache slot from Thread Control Block address */
- TSRM_API size_t tsrm_get_ls_cache_tcb_offset(void)
- {/*{{{*/
- #if defined(__APPLE__) && defined(__x86_64__)
- // TODO: Implement support for fast JIT ZTS code ???
- return 0;
- #elif defined(__x86_64__) && defined(__GNUC__) && !defined(__FreeBSD__) && \
- !defined(__OpenBSD__) && !defined(__MUSL__) && !defined(__HAIKU__)
- size_t ret;
- asm ("movq _tsrm_ls_cache@gottpoff(%%rip),%0"
- : "=r" (ret));
- return ret;
- #elif defined(__i386__) && defined(__GNUC__) && !defined(__FreeBSD__) && \
- !defined(__OpenBSD__) && !defined(__MUSL__) && !defined(__HAIKU__)
- size_t ret;
- asm ("leal _tsrm_ls_cache@ntpoff,%0"
- : "=r" (ret));
- return ret;
- #elif defined(__aarch64__)
- size_t ret;
- # ifdef __APPLE__
- // Points to struct TLVDecriptor for _tsrm_ls_cache in macOS.
- asm("adrp %0, #__tsrm_ls_cache@TLVPPAGE\n\t"
- "ldr %0, [%0, #__tsrm_ls_cache@TLVPPAGEOFF]"
- : "=r" (ret));
- # else
- asm("mov %0, xzr\n\t"
- "add %0, %0, #:tprel_hi12:_tsrm_ls_cache, lsl #12\n\t"
- "add %0, %0, #:tprel_lo12_nc:_tsrm_ls_cache"
- : "=r" (ret));
- # endif
- return ret;
- #else
- return 0;
- #endif
- }/*}}}*/
- TSRM_API uint8_t tsrm_is_main_thread(void)
- {/*{{{*/
- return in_main_thread;
- }/*}}}*/
- TSRM_API uint8_t tsrm_is_shutdown(void)
- {/*{{{*/
- return is_thread_shutdown;
- }/*}}}*/
- TSRM_API const char *tsrm_api_name(void)
- {/*{{{*/
- #ifdef TSRM_WIN32
- return "Windows Threads";
- #else
- return "POSIX Threads";
- #endif
- }/*}}}*/
- #endif /* ZTS */
|