diff options
Diffstat (limited to 'Zend')
-rw-r--r-- | Zend/Makefile.am | 2 | ||||
-rw-r--r-- | Zend/Zend.m4 | 14 | ||||
-rw-r--r-- | Zend/zend.c | 8 | ||||
-rw-r--r-- | Zend/zend.h | 11 | ||||
-rw-r--r-- | Zend/zend_alloc.c | 64 | ||||
-rw-r--r-- | Zend/zend_execute_API.c | 28 | ||||
-rw-r--r-- | Zend/zend_hash.c | 18 | ||||
-rw-r--r-- | Zend/zend_signal.c | 414 | ||||
-rw-r--r-- | Zend/zend_signal.h | 104 |
9 files changed, 635 insertions, 28 deletions
diff --git a/Zend/Makefile.am b/Zend/Makefile.am index 04b51081bf..5ec4590fef 100644 --- a/Zend/Makefile.am +++ b/Zend/Makefile.am @@ -17,7 +17,7 @@ libZend_la_SOURCES=\ zend_objects_API.c zend_ts_hash.c zend_stream.c \ zend_default_classes.c \ zend_iterators.c zend_interfaces.c zend_exceptions.c \ - zend_strtod.c zend_closures.c zend_float.c zend_string.c + zend_strtod.c zend_closures.c zend_float.c zend_string.c zend_signal.c libZend_la_LDFLAGS = libZend_la_LIBADD = @ZEND_EXTRA_LIBS@ diff --git a/Zend/Zend.m4 b/Zend/Zend.m4 index ececf783b5..67b9ba09d7 100644 --- a/Zend/Zend.m4 +++ b/Zend/Zend.m4 @@ -392,8 +392,22 @@ int main() AC_CHECK_FUNCS(mremap) + +AC_CHECK_FUNC(sigaction, [ + ZEND_SIGNALS=yes + AC_DEFINE(ZEND_SIGNALS, 1, [Use zend signal handling]) + AC_DEFINE(HAVE_SIGACTION, 1, [Whether sigaction() is available]) +], [ + ZEND_SIGNALS=no ]) +if test "$ZEND_SIGNALS" = "yes"; then + CFLAGS="$CFLAGS -DZEND_SIGNALS" +fi +AC_MSG_CHECKING(whether to enable zend signal handling) +AC_MSG_RESULT($ZEND_SIGNALS) + +]) AC_DEFUN([LIBZEND_CPLUSPLUS_CHECKS],[ diff --git a/Zend/zend.c b/Zend/zend.c index 638de824b1..8fe185660f 100644 --- a/Zend/zend.c +++ b/Zend/zend.c @@ -108,6 +108,9 @@ ZEND_INI_BEGIN() STD_ZEND_INI_BOOLEAN("zend.multibyte", "0", ZEND_INI_PERDIR, OnUpdateBool, multibyte, zend_compiler_globals, compiler_globals) ZEND_INI_ENTRY("zend.script_encoding", NULL, ZEND_INI_ALL, OnUpdateScriptEncoding) STD_ZEND_INI_BOOLEAN("zend.detect_unicode", "1", ZEND_INI_ALL, OnUpdateBool, detect_unicode, zend_compiler_globals, compiler_globals) +#ifdef ZEND_SIGNALS + STD_ZEND_INI_BOOLEAN("zend.signal_check", "0", ZEND_INI_SYSTEM, OnUpdateBool, check, zend_signal_globals_t, zend_signal_globals) +#endif ZEND_INI_END() @@ -659,8 +662,10 @@ int zend_startup(zend_utility_functions *utility_functions, char **extensions TS } zend_stream_open_function = utility_functions->stream_open_function; zend_message_dispatcher_p = utility_functions->message_handler; +#ifndef ZEND_SIGNALS zend_block_interruptions = utility_functions->block_interruptions; zend_unblock_interruptions = utility_functions->unblock_interruptions; +#endif zend_get_configuration_directive_p = utility_functions->get_configuration_directive; zend_ticks_function = utility_functions->ticks_function; zend_on_timeout = utility_functions->on_timeout; @@ -791,6 +796,9 @@ void zend_post_startup(TSRMLS_D) /* {{{ */ void zend_shutdown(TSRMLS_D) /* {{{ */ { +#ifdef ZEND_SIGNALS + zend_signal_shutdown(TSRMLS_C); +#endif #ifdef ZEND_WIN32 zend_shutdown_timeout_thread(); #endif diff --git a/Zend/zend.h b/Zend/zend.h index 8fe005398f..8caa382326 100644 --- a/Zend/zend.h +++ b/Zend/zend.h @@ -531,8 +531,10 @@ typedef struct _zend_utility_functions { int (*write_function)(const char *str, uint str_length); FILE *(*fopen_function)(const char *filename, char **opened_path TSRMLS_DC); void (*message_handler)(long message, void *data TSRMLS_DC); +#ifndef ZEND_SIGNALS void (*block_interruptions)(void); void (*unblock_interruptions)(void); +#endif int (*get_configuration_directive)(const char *name, uint name_length, zval *contents); void (*ticks_function)(int ticks); void (*on_timeout)(int seconds TSRMLS_DC); @@ -674,8 +676,10 @@ BEGIN_EXTERN_C() extern ZEND_API int (*zend_printf)(const char *format, ...) ZEND_ATTRIBUTE_PTR_FORMAT(printf, 1, 2); extern ZEND_API zend_write_func_t zend_write; extern ZEND_API FILE *(*zend_fopen)(const char *filename, char **opened_path TSRMLS_DC); +#ifndef ZEND_SIGNALS extern ZEND_API void (*zend_block_interruptions)(void); extern ZEND_API void (*zend_unblock_interruptions)(void); +#endif extern ZEND_API void (*zend_ticks_function)(int ticks); extern ZEND_API void (*zend_error_cb)(int type, const char *error_filename, const uint error_lineno, const char *format, va_list args) ZEND_ATTRIBUTE_PTR_FORMAT(printf, 4, 0); extern void (*zend_on_timeout)(int seconds TSRMLS_DC); @@ -698,8 +702,15 @@ END_EXTERN_C() #define ZEND_UV(name) (zend_uv.name) +#ifndef ZEND_SIGNALS #define HANDLE_BLOCK_INTERRUPTIONS() if (zend_block_interruptions) { zend_block_interruptions(); } #define HANDLE_UNBLOCK_INTERRUPTIONS() if (zend_unblock_interruptions) { zend_unblock_interruptions(); } +#else +#include "zend_signal.h" + +#define HANDLE_BLOCK_INTERRUPTIONS() SIGG(depth)++; +#define HANDLE_UNBLOCK_INTERRUPTIONS() if (UNEXPECTED((--SIGG(depth))==SIGG(blocked))) { zend_signal_handler_unblock(TSRMLS_C); } +#endif BEGIN_EXTERN_C() ZEND_API void zend_message_dispatcher(long message, void *data TSRMLS_DC); diff --git a/Zend/zend_alloc.c b/Zend/zend_alloc.c index 108309c1d7..e7e7ee9d22 100644 --- a/Zend/zend_alloc.c +++ b/Zend/zend_alloc.c @@ -1882,6 +1882,11 @@ static void *_zend_mm_alloc_int(zend_mm_heap *heap, size_t size ZEND_FILE_LINE_D size_t segment_size; zend_mm_segment *segment; int keep_rest = 0; +#ifdef ZEND_SIGNALS + TSRMLS_FETCH(); +#endif + + HANDLE_BLOCK_INTERRUPTIONS(); if (EXPECTED(ZEND_MM_SMALL_SIZE(true_size))) { size_t index = ZEND_MM_BUCKET_INDEX(true_size); @@ -1902,6 +1907,7 @@ static void *_zend_mm_alloc_int(zend_mm_heap *heap, size_t size ZEND_FILE_LINE_D heap->cached -= true_size; ZEND_MM_CHECK_MAGIC(best_fit, MEM_BLOCK_CACHED); ZEND_MM_SET_DEBUG_INFO(best_fit, size, 1, 0); + HANDLE_UNBLOCK_INTERRUPTIONS(); return ZEND_MM_DATA_OF(best_fit); } #if ZEND_MM_CACHE_STAT @@ -1955,8 +1961,6 @@ static void *_zend_mm_alloc_int(zend_mm_heap *heap, size_t size ZEND_FILE_LINE_D segment_size = heap->block_size; } - HANDLE_BLOCK_INTERRUPTIONS(); - if (segment_size < true_size || heap->real_size + segment_size > heap->limit) { /* Memory limit overflow */ @@ -1978,8 +1982,8 @@ static void *_zend_mm_alloc_int(zend_mm_heap *heap, size_t size ZEND_FILE_LINE_D #if ZEND_MM_CACHE zend_mm_free_cache(heap); #endif - HANDLE_UNBLOCK_INTERRUPTIONS(); out_of_memory: + HANDLE_UNBLOCK_INTERRUPTIONS(); #if ZEND_DEBUG zend_mm_safe_error(heap, "Out of memory (allocated %ld) at %s:%d (tried to allocate %lu bytes)", heap->real_size, __zend_filename, __zend_lineno, size); #else @@ -2007,7 +2011,6 @@ out_of_memory: } else { zend_mm_finished_searching_for_block: /* remove from free list */ - HANDLE_BLOCK_INTERRUPTIONS(); ZEND_MM_CHECK_MAGIC(best_fit, MEM_BLOCK_FREED); ZEND_MM_CHECK_COOKIE(best_fit); ZEND_MM_CHECK_BLOCK_LINKAGE(best_fit); @@ -2055,11 +2058,15 @@ static void _zend_mm_free_int(zend_mm_heap *heap, void *p ZEND_FILE_LINE_DC ZEND zend_mm_block *mm_block; zend_mm_block *next_block; size_t size; - +#ifdef ZEND_SIGNALS + TSRMLS_FETCH(); +#endif if (!ZEND_MM_VALID_PTR(p)) { return; } + HANDLE_BLOCK_INTERRUPTIONS(); + mm_block = ZEND_MM_HEADER_OF(p); size = ZEND_MM_BLOCK_SIZE(mm_block); ZEND_MM_CHECK_PROTECTION(mm_block); @@ -2082,12 +2089,11 @@ static void _zend_mm_free_int(zend_mm_heap *heap, void *p ZEND_FILE_LINE_DC ZEND heap->cache_stat[index].max_count = heap->cache_stat[index].count; } #endif + HANDLE_UNBLOCK_INTERRUPTIONS(); return; } #endif - HANDLE_BLOCK_INTERRUPTIONS(); - heap->size -= size; next_block = ZEND_MM_BLOCK_AT(mm_block, size); @@ -2117,10 +2123,15 @@ static void *_zend_mm_realloc_int(zend_mm_heap *heap, void *p, size_t size ZEND_ size_t true_size; size_t orig_size; void *ptr; - +#ifdef ZEND_SIGNALS + TSRMLS_FETCH(); +#endif if (UNEXPECTED(!p) || !ZEND_MM_VALID_PTR(p)) { return _zend_mm_alloc_int(heap, size ZEND_FILE_LINE_RELAY_CC ZEND_FILE_LINE_ORIG_RELAY_CC); } + + HANDLE_BLOCK_INTERRUPTIONS(); + mm_block = ZEND_MM_HEADER_OF(p); true_size = ZEND_MM_TRUE_SIZE(size); orig_size = ZEND_MM_BLOCK_SIZE(mm_block); @@ -2136,7 +2147,6 @@ static void *_zend_mm_realloc_int(zend_mm_heap *heap, void *p, size_t size ZEND_ if (remaining_size >= ZEND_MM_ALIGNED_MIN_HEADER_SIZE) { zend_mm_free_block *new_free_block; - HANDLE_BLOCK_INTERRUPTIONS(); next_block = ZEND_MM_BLOCK_AT(mm_block, orig_size); if (ZEND_MM_IS_FREE_BLOCK(next_block)) { remaining_size += ZEND_MM_FREE_BLOCK_SIZE(next_block); @@ -2152,9 +2162,9 @@ static void *_zend_mm_realloc_int(zend_mm_heap *heap, void *p, size_t size ZEND_ /* add the new free block to the free list */ zend_mm_add_to_free_list(heap, new_free_block); heap->size += (true_size - orig_size); - HANDLE_UNBLOCK_INTERRUPTIONS(); } ZEND_MM_SET_DEBUG_INFO(mm_block, size, 0, 0); + HANDLE_UNBLOCK_INTERRUPTIONS(); return p; } @@ -2197,6 +2207,7 @@ static void *_zend_mm_realloc_int(zend_mm_heap *heap, void *p, size_t size ZEND_ } #endif + HANDLE_UNBLOCK_INTERRUPTIONS(); return ptr; } } @@ -2211,7 +2222,6 @@ static void *_zend_mm_realloc_int(zend_mm_heap *heap, void *p, size_t size ZEND_ size_t block_size = orig_size + ZEND_MM_FREE_BLOCK_SIZE(next_block); size_t remaining_size = block_size - true_size; - HANDLE_BLOCK_INTERRUPTIONS(); zend_mm_remove_from_free_list(heap, (zend_mm_free_block *) next_block); if (remaining_size < ZEND_MM_ALIGNED_MIN_HEADER_SIZE) { @@ -2242,7 +2252,6 @@ static void *_zend_mm_realloc_int(zend_mm_heap *heap, void *p, size_t size ZEND_ return p; } else if (ZEND_MM_IS_FIRST_BLOCK(mm_block) && ZEND_MM_IS_GUARD_BLOCK(ZEND_MM_BLOCK_AT(next_block, ZEND_MM_FREE_BLOCK_SIZE(next_block)))) { - HANDLE_BLOCK_INTERRUPTIONS(); zend_mm_remove_from_free_list(heap, (zend_mm_free_block *) next_block); goto realloc_segment; } @@ -2253,7 +2262,6 @@ static void *_zend_mm_realloc_int(zend_mm_heap *heap, void *p, size_t size ZEND_ size_t block_size; size_t remaining_size; - HANDLE_BLOCK_INTERRUPTIONS(); realloc_segment: /* segment size, size of block and size of guard block */ if (true_size > heap->block_size - (ZEND_MM_ALIGNED_SEGMENT_SIZE + ZEND_MM_ALIGNED_HEADER_SIZE)) { @@ -2286,8 +2294,8 @@ realloc_segment: #if ZEND_MM_CACHE zend_mm_free_cache(heap); #endif - HANDLE_UNBLOCK_INTERRUPTIONS(); out_of_memory: + HANDLE_UNBLOCK_INTERRUPTIONS(); #if ZEND_DEBUG zend_mm_safe_error(heap, "Out of memory (allocated %ld) at %s:%d (tried to allocate %ld bytes)", heap->real_size, __zend_filename, __zend_lineno, size); #else @@ -2351,6 +2359,7 @@ out_of_memory: memcpy(ptr, p, orig_size - ZEND_MM_ALIGNED_HEADER_SIZE); #endif _zend_mm_free_int(heap, p ZEND_FILE_LINE_RELAY_CC ZEND_FILE_LINE_ORIG_RELAY_CC); + HANDLE_UNBLOCK_INTERRUPTIONS(); return ptr; } @@ -2539,12 +2548,18 @@ ZEND_API void *_safe_realloc(void *ptr, size_t nmemb, size_t size, size_t offset ZEND_API void *_ecalloc(size_t nmemb, size_t size ZEND_FILE_LINE_DC ZEND_FILE_LINE_ORIG_DC) { void *p; +#ifdef ZEND_SIGNALS + TSRMLS_FETCH(); +#endif + HANDLE_BLOCK_INTERRUPTIONS(); p = _safe_emalloc(nmemb, size, 0 ZEND_FILE_LINE_RELAY_CC ZEND_FILE_LINE_ORIG_RELAY_CC); if (UNEXPECTED(p == NULL)) { + HANDLE_UNBLOCK_INTERRUPTIONS(); return p; } memset(p, 0, size * nmemb); + HANDLE_UNBLOCK_INTERRUPTIONS(); return p; } @@ -2552,26 +2567,40 @@ ZEND_API char *_estrdup(const char *s ZEND_FILE_LINE_DC ZEND_FILE_LINE_ORIG_DC) { int length; char *p; +#ifdef ZEND_SIGNALS + TSRMLS_FETCH(); +#endif + + HANDLE_BLOCK_INTERRUPTIONS(); length = strlen(s)+1; p = (char *) _emalloc(length ZEND_FILE_LINE_RELAY_CC ZEND_FILE_LINE_ORIG_RELAY_CC); if (UNEXPECTED(p == NULL)) { + HANDLE_UNBLOCK_INTERRUPTIONS(); return p; } memcpy(p, s, length); + HANDLE_UNBLOCK_INTERRUPTIONS(); return p; } ZEND_API char *_estrndup(const char *s, uint length ZEND_FILE_LINE_DC ZEND_FILE_LINE_ORIG_DC) { char *p; +#ifdef ZEND_SIGNALS + TSRMLS_FETCH(); +#endif + + HANDLE_BLOCK_INTERRUPTIONS(); p = (char *) _emalloc(length+1 ZEND_FILE_LINE_RELAY_CC ZEND_FILE_LINE_ORIG_RELAY_CC); if (UNEXPECTED(p == NULL)) { + HANDLE_UNBLOCK_INTERRUPTIONS(); return p; } memcpy(p, s, length); p[length] = 0; + HANDLE_UNBLOCK_INTERRUPTIONS(); return p; } @@ -2579,15 +2608,22 @@ ZEND_API char *_estrndup(const char *s, uint length ZEND_FILE_LINE_DC ZEND_FILE_ ZEND_API char *zend_strndup(const char *s, uint length) { char *p; +#ifdef ZEND_SIGNALS + TSRMLS_FETCH(); +#endif + + HANDLE_BLOCK_INTERRUPTIONS(); p = (char *) malloc(length+1); if (UNEXPECTED(p == NULL)) { + HANDLE_UNBLOCK_INTERRUPTIONS(); return p; } if (length) { memcpy(p, s, length); } p[length] = 0; + HANDLE_UNBLOCK_INTERRUPTIONS(); return p; } diff --git a/Zend/zend_execute_API.c b/Zend/zend_execute_API.c index e15344a4f0..f7594d9be1 100644 --- a/Zend/zend_execute_API.c +++ b/Zend/zend_execute_API.c @@ -1469,7 +1469,7 @@ void zend_set_timeout(long seconds, int reset_signals) /* {{{ */ # ifdef HAVE_SETITIMER { struct itimerval t_r; /* timeout requested */ - sigset_t sigset; + int signo; if(seconds) { t_r.it_value.tv_sec = seconds; @@ -1478,25 +1478,27 @@ void zend_set_timeout(long seconds, int reset_signals) /* {{{ */ # ifdef __CYGWIN__ setitimer(ITIMER_REAL, &t_r, NULL); } - if(reset_signals) { - signal(SIGALRM, zend_timeout); - sigemptyset(&sigset); - sigaddset(&sigset, SIGALRM); - } + signo = SIGALRM; # else setitimer(ITIMER_PROF, &t_r, NULL); } - if(reset_signals) { - signal(SIGPROF, zend_timeout); - sigemptyset(&sigset); - sigaddset(&sigset, SIGPROF); - } + signo = SIGPROF; # endif - if(reset_signals) { + + if (reset_signals) { +# ifdef ZEND_SIGNALS + zend_signal(signo, zend_timeout TSRMLS_CC); +# else + sigset_t sigset; + + signal(signo, zend_timeout); + sigemptyset(&sigset); + sigaddset(&sigset, signo); sigprocmask(SIG_UNBLOCK, &sigset, NULL); +# endif } } -# endif +# endif /* HAVE_SETITIMER */ #endif } /* }}} */ diff --git a/Zend/zend_hash.c b/Zend/zend_hash.c index 73c45a286c..44313c55b6 100644 --- a/Zend/zend_hash.c +++ b/Zend/zend_hash.c @@ -197,6 +197,9 @@ ZEND_API int _zend_hash_add_or_update(HashTable *ht, const char *arKey, uint nKe ulong h; uint nIndex; Bucket *p; +#ifdef ZEND_SIGNALS + TSRMLS_FETCH(); +#endif IS_CONSISTENT(ht); @@ -276,6 +279,9 @@ ZEND_API int _zend_hash_quick_add_or_update(HashTable *ht, const char *arKey, ui { uint nIndex; Bucket *p; +#ifdef ZEND_SIGNALS + TSRMLS_FETCH(); +#endif IS_CONSISTENT(ht); @@ -431,6 +437,9 @@ ZEND_API int _zend_hash_index_update_or_next_insert(HashTable *ht, ulong h, void static int zend_hash_do_resize(HashTable *ht) { Bucket **t; +#ifdef ZEND_SIGNALS + TSRMLS_FETCH(); +#endif IS_CONSISTENT(ht); @@ -475,6 +484,9 @@ ZEND_API int zend_hash_del_key_or_index(HashTable *ht, const char *arKey, uint n { uint nIndex; Bucket *p; +#ifdef ZEND_SIGNALS + TSRMLS_FETCH(); +#endif IS_CONSISTENT(ht); @@ -595,6 +607,9 @@ ZEND_API void zend_hash_clean(HashTable *ht) static Bucket *zend_hash_apply_deleter(HashTable *ht, Bucket *p) { Bucket *retval; +#ifdef ZEND_SIGNALS + TSRMLS_FETCH(); +#endif HANDLE_BLOCK_INTERRUPTIONS(); if (p->pLast) { @@ -1194,6 +1209,9 @@ ZEND_API int zend_hash_get_current_data_ex(HashTable *ht, void **pData, HashPosi ZEND_API int zend_hash_update_current_key_ex(HashTable *ht, int key_type, const char *str_index, uint str_length, ulong num_index, int mode, HashPosition *pos) { Bucket *p; +#ifdef ZEND_SIGNALS + TSRMLS_FETCH(); +#endif p = pos ? (*pos) : ht->pInternalPointer; diff --git a/Zend/zend_signal.c b/Zend/zend_signal.c new file mode 100644 index 0000000000..8fe8ebc515 --- /dev/null +++ b/Zend/zend_signal.c @@ -0,0 +1,414 @@ +/* + +----------------------------------------------------------------------+ + | Zend Signal Handling | + +----------------------------------------------------------------------+ + | Copyright (c) 2008 The PHP Group | + +----------------------------------------------------------------------+ + | This source file is subject to version 3.01 of the PHP license, | + | that is bundled with this package in the file LICENSE, and is | + | available through the world-wide-web at the following url: | + | http://www.php.net/license/3_01.txt | + | If you did not receive a copy of the PHP license and are unable to | + | obtain it through the world-wide-web, please send a note to | + | license@php.net so we can mail you a copy immediately. | + +----------------------------------------------------------------------+ + | Authors: Lucas Nealan <lucas@php.net> | + | Arnaud Le Blanc <lbarnaud@php.net> | + +----------------------------------------------------------------------+ + + This software was contributed to PHP by Facebook Inc. in 2008. + + Future revisions and derivatives of this source code must acknowledge + Facebook Inc. as the original contributor of this module by leaving + this note intact in the source code. + + All other licensing and usage conditions are those of the PHP Group. +*/ + + /* $Id$ */ + +#define _GNU_SOURCE +#include <string.h> + +#include "zend.h" +#include "zend_globals.h" + +#ifdef HAVE_SIGNAL_H +#include <signal.h> +#endif + +#ifdef HAVE_UNISTD_H +#include <unistd.h> +#endif + +#ifdef ZEND_SIGNALS + +#include "zend_signal.h" + +#ifdef ZTS +ZEND_API int zend_signal_globals_id; +#else +zend_signal_globals_t zend_signal_globals; +#endif + +static void zend_signal_handler(int signo, siginfo_t *siginfo, void *context TSRMLS_DC); +static int zend_signal_register(int signo, void (*handler)(int, siginfo_t*, void*) TSRMLS_DC); + +#ifdef __CYGWIN__ +#define TIMEOUT_SIG SIGALRM +#else +#define TIMEOUT_SIG SIGPROF +#endif + +static int zend_sigs[] = { TIMEOUT_SIG, SIGHUP, SIGINT, SIGQUIT, SIGTERM, SIGUSR1, SIGUSR2 }; + +#define SA_FLAGS_MASK ~(SA_NODEFER | SA_RESETHAND) + +/* True globals, written only at process startup */ +static zend_signal_entry_t global_orig_handlers[NSIG]; +static sigset_t global_sigmask; + +/* {{{ zend_signal_handler_defer + * Blocks signals if in critical section */ +void zend_signal_handler_defer(int signo, siginfo_t *siginfo, void *context) +{ + int errno_save = errno; + zend_signal_queue_t *queue, *qtmp; + TSRMLS_FETCH(); + + if (SIGG(active)) { + if (SIGG(depth) == 0) { /* try to handle signal */ + if (SIGG(blocked) != -1) { /* inverse */ + SIGG(blocked) = -1; /* signal is not blocked */ + } + if (SIGG(running) == 0) { + SIGG(running) = 1; + zend_signal_handler(signo, siginfo, context TSRMLS_CC); + + queue = SIGG(phead); + SIGG(phead) = NULL; + + while (queue) { + zend_signal_handler(queue->zend_signal.signo, queue->zend_signal.siginfo, queue->zend_signal.context TSRMLS_CC); + qtmp = queue->next; + queue->next = SIGG(pavail); + queue->zend_signal.signo = 0; + SIGG(pavail) = queue; + queue = qtmp; + } + SIGG(running) = 0; + } + } else { /* delay signal handling */ + SIGG(blocked) = 0; /* signal is blocked */ + + if ((queue = SIGG(pavail))) { /* if none available it's simply forgotton */ + SIGG(pavail) = queue->next; + queue->zend_signal.signo = signo; + queue->zend_signal.siginfo = siginfo; + queue->zend_signal.context = context; + queue->next = NULL; + + if (SIGG(phead) && SIGG(ptail)) { + SIGG(ptail)->next = queue; + } else { + SIGG(phead) = queue; + } + SIGG(ptail) = queue; + } +#if ZEND_DEBUG + else { /* this may not be safe to do, but could work and be useful */ + zend_output_debug_string(0, "zend_signal: not enough queue storage, lost signal (%d)", signo); + } +#endif + } + } else { + /* need to just run handler if we're inactive and getting a signal */ + zend_signal_handler(signo, siginfo, context TSRMLS_CC); + } + + errno = errno_save; +} /* }}} */ + +/* {{{ zend_signal_handler_unblock + * Handle deferred signal from HANDLE_UNBLOCK_ALARMS */ +void zend_signal_handler_unblock(TSRMLS_D) +{ + zend_signal_queue_t *queue; + zend_signal_t zend_signal; + + if (SIGG(active)) { + SIGNAL_BEGIN_CRITICAL(); /* procmask to protect handler_defer as if it were called by the kernel */ + queue = SIGG(phead); + SIGG(phead) = queue->next; + zend_signal = queue->zend_signal; + queue->next = SIGG(pavail); + queue->zend_signal.signo = 0; + SIGG(pavail) = queue; + + zend_signal_handler_defer(zend_signal.signo, zend_signal.siginfo, zend_signal.context); + SIGNAL_END_CRITICAL(); + } +} +/* }}} */ + +/* {{{ zend_signal_handler + * Call the previously registered handler for a signal + */ +static void zend_signal_handler(int signo, siginfo_t *siginfo, void *context TSRMLS_DC) +{ + int errno_save = errno; + struct sigaction sa = {{0}}; + sigset_t sigset; + zend_signal_entry_t p_sig = SIGG(handlers)[signo-1]; + + if (p_sig.handler == SIG_DFL) { /* raise default handler */ + if (sigaction(signo, NULL, &sa) == 0) { + sa.sa_handler = SIG_DFL; + sigemptyset(&sa.sa_mask); + + sigemptyset(&sigset); + sigaddset(&sigset, signo); + + if (sigaction(signo, &sa, NULL) == 0) { + /* throw away any blocked signals */ + sigprocmask(SIG_UNBLOCK, &sigset, NULL); + raise(signo); + } + } + } else if (p_sig.handler != SIG_IGN) { /* ignore SIG_IGN */ + if (p_sig.flags & SA_SIGINFO) { + if (p_sig.flags & SA_RESETHAND) { + SIGG(handlers)[signo-1].flags = 0; + SIGG(handlers)[signo-1].handler = SIG_DFL; + } + (*(void (*)(int, siginfo_t*, void*))p_sig.handler)(signo, siginfo, context); + } else { + (*(void (*)(int))p_sig.handler)(signo); + } + } + + errno = errno_save; +} /* }}} */ + +/* {{{ zend_sigaction + * Register a signal handler that will be deferred in critical sections */ +ZEND_API int zend_sigaction(int signo, const struct sigaction *act, struct sigaction *oldact TSRMLS_DC) +{ + struct sigaction sa = {{0}}; + sigset_t sigset; + + if (oldact != NULL) { + oldact->sa_flags = SIGG(handlers)[signo-1].flags; + oldact->sa_handler = (void *) SIGG(handlers)[signo-1].handler; + oldact->sa_mask = global_sigmask; + } + if (act != NULL) { + SIGG(handlers)[signo-1].flags = act->sa_flags; + if (act->sa_flags & SA_SIGINFO) { + SIGG(handlers)[signo-1].handler = (void *) act->sa_sigaction; + } else { + SIGG(handlers)[signo-1].handler = (void *) act->sa_handler; + } + + sa.sa_flags = SA_SIGINFO | (act->sa_flags & SA_FLAGS_MASK); + sa.sa_sigaction = zend_signal_handler_defer; + sa.sa_mask = global_sigmask; + + if (sigaction(signo, &sa, NULL) < 0) { + zend_error(E_ERROR, "Error installing signal handler for %d", signo); + } + + /* unsure this signal is not blocked */ + sigemptyset(&sigset); + sigaddset(&sigset, signo); + zend_sigprocmask(SIG_UNBLOCK, &sigset, NULL); + } + + return SUCCESS; +} +/* }}} */ + +/* {{{ zend_signal + * Register a signal handler that will be deferred in critical sections */ +ZEND_API int zend_signal(int signo, void (*handler)(int) TSRMLS_DC) +{ + struct sigaction sa = {{0}}; + + sa.sa_flags = 0; + sa.sa_handler = handler; + sa.sa_mask = global_sigmask; + + return zend_sigaction(signo, &sa, NULL TSRMLS_CC); +} +/* }}} */ + +/* {{{ zend_signal_register + * Set a handler for a signal we want to defer. + * Previously set handler must have been saved before. + */ +static int zend_signal_register(int signo, void (*handler)(int, siginfo_t*, void*) TSRMLS_DC) +{ + struct sigaction sa = {{0}}; + + if (sigaction(signo, NULL, &sa) == 0) { + if ((sa.sa_flags & SA_SIGINFO) && sa.sa_sigaction == handler) { + return FAILURE; + } + + SIGG(handlers)[signo-1].flags = sa.sa_flags; + if (sa.sa_flags & SA_SIGINFO) { + SIGG(handlers)[signo-1].handler = (void *)sa.sa_sigaction; + } else { + SIGG(handlers)[signo-1].handler = (void *)sa.sa_handler; + } + + sa.sa_flags = SA_SIGINFO; /* we'll use a siginfo handler */ + sa.sa_sigaction = handler; + sa.sa_mask = global_sigmask; + + if (sigaction(signo, &sa, NULL) < 0) { + zend_error(E_ERROR, "Error installing signal handler for %d", signo); + } + + return SUCCESS; + } + return FAILURE; +} /* }}} */ + +/* {{{ zend_signal_activate + * Install our signal handlers, per request */ +void zend_signal_activate(TSRMLS_D) +{ + int x; + + memcpy(&SIGG(handlers), &global_orig_handlers, sizeof(global_orig_handlers)); + + for (x=0; x < sizeof(zend_sigs) / sizeof(*zend_sigs); x++) { + zend_signal_register(zend_sigs[x], zend_signal_handler_defer TSRMLS_CC); + } + + SIGG(active) = 1; + SIGG(depth) = 0; +} /* }}} */ + +/* {{{ zend_signal_deactivate + * */ +void zend_signal_deactivate(TSRMLS_D) +{ + int x; + struct sigaction sa = {{0}}; + + if (SIGG(check)) { + if (SIGG(depth) != 0) { + zend_error(E_CORE_WARNING, "zend_signal: shutdown with non-zero blocking depth (%d)", SIGG(depth)); + } + /* did anyone steal our installed handler */ + for (x=0; x < sizeof(zend_sigs) / sizeof(*zend_sigs); x++) { + sigaction(zend_sigs[x], NULL, &sa); + if (sa.sa_sigaction != zend_signal_handler_defer) { + zend_error(E_CORE_WARNING, "zend_signal: handler was replaced for signal (%d) after startup", zend_sigs[x]); + } + } + } + + SIGNAL_BEGIN_CRITICAL(); + SIGG(active) = 0; + SIGG(running) = 0; + SIGG(blocked) = -1; + SIGG(depth) = 0; + SIGNAL_END_CRITICAL(); +} +/* }}} */ + +static void zend_signal_globals_ctor(zend_signal_globals_t *zend_signal_globals TSRMLS_DC) +{ + size_t x; + + memset(zend_signal_globals, 0, sizeof(*zend_signal_globals)); + zend_signal_globals->blocked = -1; + + for (x = 0; x < sizeof(zend_signal_globals->pstorage) / sizeof(*zend_signal_globals->pstorage); ++x) { + zend_signal_queue_t *queue = &zend_signal_globals->pstorage[x]; + queue->zend_signal.signo = 0; + queue->next = zend_signal_globals->pavail; + zend_signal_globals->pavail = queue; + } +} + +static void zend_signal_globals_dtor(zend_signal_globals_t *zend_signal_globals TSRMLS_DC) +{ + zend_signal_globals->blocked = -1; +} + +/* {{{ zend_signal_startup + * alloc zend signal globals */ +void zend_signal_startup() +{ + int signo; + struct sigaction sa = {{0}}; + +#ifdef ZTS + ts_allocate_id(&zend_signal_globals_id, sizeof(zend_signal_globals_t), (ts_allocate_ctor) zend_signal_globals_ctor, (ts_allocate_dtor) zend_signal_globals_dtor); +#else + zend_signal_globals_ctor(&zend_signal_globals); +#endif + + /* Used to block signals during execution of signal handlers */ + sigfillset(&global_sigmask); + sigdelset(&global_sigmask, SIGILL); + sigdelset(&global_sigmask, SIGABRT); + sigdelset(&global_sigmask, SIGFPE); + sigdelset(&global_sigmask, SIGKILL); + sigdelset(&global_sigmask, SIGSEGV); + sigdelset(&global_sigmask, SIGCONT); + sigdelset(&global_sigmask, SIGSTOP); + sigdelset(&global_sigmask, SIGTSTP); + sigdelset(&global_sigmask, SIGTTIN); + sigdelset(&global_sigmask, SIGTTOU); +#ifdef SIGBUS + sigdelset(&global_sigmask, SIGBUS); +#endif +#ifdef SIGSYS + sigdelset(&global_sigmask, SIGSYS); +#endif +#ifdef SIGTRAP + sigdelset(&global_sigmask, SIGTRAP); +#endif + + /* Save previously registered signal handlers into orig_handlers */ + memset(&global_orig_handlers, 0, sizeof(global_orig_handlers)); + for (signo = 1; signo < NSIG; ++signo) { + if (sigaction(signo, NULL, &sa) == 0) { + global_orig_handlers[signo-1].flags = sa.sa_flags; + if (sa.sa_flags & SA_SIGINFO) { + global_orig_handlers[signo-1].handler = (void *) sa.sa_sigaction; + } else { + global_orig_handlers[signo-1].handler = (void *) sa.sa_handler; + } + } + } +} +/* }}} */ + +/* {{{ zend_signal_shutdown + * called by zend_shutdown */ +void zend_signal_shutdown(TSRMLS_D) +{ +#ifndef ZTS + zend_signal_globals_dtor(&zend_signal_globals); +#endif +} +/* }}} */ + + +#endif /* ZEND_SIGNALS */ + +/* + * Local variables: + * tab-width: 4 + * c-basic-offset: 4 + * indent-tabs-mode: t + * End: + * vim600: fdm=marker + * vim: noet sw=4 ts=4 + */ diff --git a/Zend/zend_signal.h b/Zend/zend_signal.h new file mode 100644 index 0000000000..bc10132091 --- /dev/null +++ b/Zend/zend_signal.h @@ -0,0 +1,104 @@ +/* + +----------------------------------------------------------------------+ + | Zend Signal Handling | + +----------------------------------------------------------------------+ + | Copyright (c) 2008 The PHP Group | + +----------------------------------------------------------------------+ + | This source file is subject to version 3.01 of the PHP license, | + | that is bundled with this package in the file LICENSE, and is | + | available through the world-wide-web at the following url: | + | http://www.php.net/license/3_01.txt | + | If you did not receive a copy of the PHP license and are unable to | + | obtain it through the world-wide-web, please send a note to | + | license@php.net so we can mail you a copy immediately. | + +----------------------------------------------------------------------+ + | Authors: Lucas Nealan <lucas@php.net> | + | Arnaud Le Blanc <lbarnaud@php.net> | + +----------------------------------------------------------------------+ + + */ + +/* $Id$ */ + +#ifndef ZEND_SIGNAL_H +#define ZEND_SIGNAL_H + +#ifdef HAVE_SIGNAL_H +#include <signal.h> +#endif + +#ifndef NSIG +#define NSIG 65 +#endif + +#ifndef ZEND_SIGNAL_QUEUE_SIZE +#define ZEND_SIGNAL_QUEUE_SIZE 32 +#endif + +/* Signal structs */ +typedef struct _zend_signal_entry_t { + int flags; /* sigaction style flags */ + void* handler; /* signal handler or context */ +} zend_signal_entry_t; + +typedef struct _zend_signal_t { + int signo; + siginfo_t *siginfo; + void* context; +} zend_signal_t; + +typedef struct _zend_signal_queue_t { + zend_signal_t zend_signal; + struct _zend_signal_queue_t *next; +} zend_signal_queue_t; + +/* Signal Globals */ +typedef struct _zend_signal_globals_t { + int depth; + int blocked; /* 0==TRUE, -1==FALSE */ + int running; /* in signal handler execution */ + int active; /* internal signal handling is enabled */ + int initialized; /* memory initialized */ + zend_bool check; /* check for replaced handlers on shutdown */ + zend_signal_entry_t handlers[NSIG]; + zend_signal_queue_t pstorage[ZEND_SIGNAL_QUEUE_SIZE], *phead, *ptail, *pavail; /* pending queue */ +} zend_signal_globals_t; + +#ifdef ZTS +# define SIGG(v) TSRMG(zend_signal_globals_id, zend_signal_globals_t *, v) +BEGIN_EXTERN_C() +ZEND_API extern int zend_signal_globals_id; +END_EXTERN_C() +#else /* ZTS */ +# define SIGG(v) (zend_signal_globals.v) +extern ZEND_API zend_signal_globals_t zend_signal_globals; +#endif /* not ZTS */ + +# define SIGNAL_BEGIN_CRITICAL() sigset_t oldmask; \ + zend_sigprocmask(SIG_BLOCK, &global_sigmask, &oldmask); +# define SIGNAL_END_CRITICAL() zend_sigprocmask(SIG_SETMASK, &oldmask, NULL); + +void zend_signal_handler_defer(int signo, siginfo_t *siginfo, void *context); +void zend_signal_handler_unblock(); +void zend_signal_activate(TSRMLS_D); +void zend_signal_deactivate(TSRMLS_D); +void zend_signal_startup(); +void zend_signal_shutdown(TSRMLS_D); +ZEND_API int zend_signal(int signo, void (*handler)(int) TSRMLS_DC); +ZEND_API int zend_sigaction(int signo, const struct sigaction *act, struct sigaction *oldact TSRMLS_DC); + +#ifdef ZTS +#define zend_sigprocmask(signo, set, oldset) tsrm_sigmask((signo), (set), (oldset)) +#else +#define zend_sigprocmask(signo, set, oldset) sigprocmask((signo), (set), (oldset)) +#endif + +#endif /* ZEND_SIGNAL_H */ + +/* + * Local variables: + * tab-width: 4 + * c-basic-offset: 4 + * indent-tabs-mode: t + * End: + */ |