#include <stdio.h>
#include <stdarg.h>
+#ifdef ZEND_DEBUG
+# include <assert.h>
+# define TSRM_ASSERT assert
+#else
+# define TSRM_ASSERT
+#endif
+
typedef struct _tsrm_tls_entry tsrm_tls_entry;
/* TSRMLS_CACHE_DEFINE; is already done in Zend, this is being always compiled statically. */
#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, char *debug_filename)
/* ensure singleton */
in_main_thread = 1;
+ is_thread_shutdown = 0;
tsrm_error_file = stderr;
tsrm_error_set(debug_level, debug_filename);
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 = (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);
- tsrm_tls_table = NULL;
return 0;
}
{/*{{{*/
int i;
+ if (is_thread_shutdown) {
+ /* shutdown must only occur once */
+ return;
+ }
+
+ is_thread_shutdown = 1;
+
if (!in_main_thread) {
- /* ensure singleton */
+ /* only the main thread may shutdown tsrm */
return;
}
- if (tsrm_tls_table) {
- for (i=0; i<tsrm_tls_table_size; i++) {
- tsrm_tls_entry *p = tsrm_tls_table[i], *next_p;
+ for (i=0; i<tsrm_tls_table_size; i++) {
+ tsrm_tls_entry *p = tsrm_tls_table[i], *next_p;
- while (p) {
- int j;
+ while (p) {
+ int j;
- next_p = p->next;
- for (j=0; j<p->count; j++) {
- if (p->storage[j]) {
- if (resource_types_table && !resource_types_table[j].done && resource_types_table[j].dtor) {
- resource_types_table[j].dtor(p->storage[j]);
- }
- if (!resource_types_table[j].fast_offset) {
- free(p->storage[j]);
- }
+ next_p = p->next;
+ for (j=0; j<p->count; j++) {
+ if (p->storage[j]) {
+ if (resource_types_table && !resource_types_table[j].done && 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(p->storage);
+ free(p);
+ p = next_p;
}
- free(tsrm_tls_table);
- tsrm_tls_table = NULL;
- }
- if (resource_types_table) {
- free(resource_types_table);
- resource_types_table=NULL;
}
+ free(tsrm_tls_table);
+ free(resource_types_table);
tsrm_mutex_free(tsmm_mutex);
- tsmm_mutex = NULL;
tsrm_mutex_free(tsrm_env_mutex);
- tsrm_env_mutex = NULL;
TSRM_ERROR((TSRM_ERROR_LEVEL_CORE, "Shutdown TSRM"));
if (tsrm_error_file!=stderr) {
fclose(tsrm_error_file);
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];
tsrm_mutex_unlock(tsmm_mutex);
}/*}}}*/
-
-/* frees all resources allocated for all threads except current */
-void ts_free_worker_threads(void)
-{/*{{{*/
- tsrm_tls_entry *thread_resources;
- int i;
- THREAD_T thread_id = tsrm_thread_id();
- int hash_value;
- tsrm_tls_entry *last=NULL;
-
- 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;
- }
- free(thread_resources);
- if (last) {
- thread_resources = last->next;
- } else {
- thread_resources = tsrm_tls_table[hash_value];
- }
- } else {
- 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)
{/*{{{*/
return in_main_thread;
}/*}}}*/
+TSRM_API uint8_t tsrm_is_shutdown(void)
+{/*{{{*/
+ return is_thread_shutdown;
+}/*}}}*/
+
TSRM_API const char *tsrm_api_name(void)
{/*{{{*/
#if defined(GNUPTH)
{
int errno_save = errno;
zend_signal_queue_t *queue, *qtmp;
- zend_bool is_handling_safe = 1;
#ifdef ZTS
/* A signal could hit after TSRM shutdown, in this case globals are already freed. */
- if (NULL == TSRMLS_CACHE || NULL == TSRMG_BULK_STATIC(zend_signal_globals_id, zend_signal_globals_t *)) {
- is_handling_safe = 0;
+ if (tsrm_is_shutdown()) {
+ /* Forward to default handler handler */
+ zend_signal_handler(signo, siginfo, context);
+ return;
}
#endif
- if (EXPECTED(is_handling_safe && SIGG(active))) {
+ if (EXPECTED(SIGG(active))) {
if (UNEXPECTED(SIGG(depth) == 0)) { /* try to handle signal */
if (UNEXPECTED(SIGG(blocked))) {
SIGG(blocked) = 0;
sigset_t sigset;
zend_signal_entry_t p_sig;
#ifdef ZTS
- if (NULL == TSRMLS_CACHE || NULL == TSRMG_BULK_STATIC(zend_signal_globals_id, zend_signal_globals_t *)) {
+ if (tsrm_is_shutdown()) {
p_sig.flags = 0;
p_sig.handler = SIG_DFL;
} else