iliaa Thu, 02 Jun 2011 21:16:50 +0000 Revision: http://svn.php.net/viewvc?view=revision&revision=311740
Log: Zend Signal Handling (see RFC: https://wiki.php.net/rfc/zendsignals) This needs to go into 5.4 as well, but will wait for Pierre to review win32 situation # Patch by Lucas Nealan, Arnaud Le Blanc, Brian Shire & Ilia Alshanetsky Changed paths: U php/php-src/trunk/TSRM/TSRM.c U php/php-src/trunk/TSRM/TSRM.h U php/php-src/trunk/TSRM/tsrm.m4 U php/php-src/trunk/Zend/Makefile.am U php/php-src/trunk/Zend/Zend.m4 U php/php-src/trunk/Zend/zend.c U php/php-src/trunk/Zend/zend.h U php/php-src/trunk/Zend/zend_alloc.c U php/php-src/trunk/Zend/zend_execute_API.c U php/php-src/trunk/Zend/zend_hash.c A php/php-src/trunk/Zend/zend_signal.c A php/php-src/trunk/Zend/zend_signal.h U php/php-src/trunk/configure.in U php/php-src/trunk/ext/pcntl/php_signal.c U php/php-src/trunk/ext/standard/info.c U php/php-src/trunk/ext/standard/tests/general_functions/phpinfo.phpt U php/php-src/trunk/main/SAPI.c U php/php-src/trunk/main/main.c
Modified: php/php-src/trunk/TSRM/TSRM.c =================================================================== --- php/php-src/trunk/TSRM/TSRM.c 2011-06-02 20:01:40 UTC (rev 311739) +++ php/php-src/trunk/TSRM/TSRM.c 2011-06-02 21:16:50 UTC (rev 311740) @@ -710,7 +710,23 @@ #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())); + /* TODO: add support for other APIs */ +#ifdef PTHREADS + return pthread_sigmask(how, set, oldset); +#else + return sigprocmask(how, set, oldset); +#endif +} +#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; Modified: php/php-src/trunk/TSRM/TSRM.h =================================================================== --- php/php-src/trunk/TSRM/TSRM.h 2011-06-02 20:01:40 UTC (rev 311739) +++ php/php-src/trunk/TSRM/TSRM.h 2011-06-02 21:16:50 UTC (rev 311740) @@ -90,6 +90,10 @@ # define MUTEX_T beos_ben * #endif +#ifdef HAVE_SIGNAL_H +#include <signal.h> +#endif + typedef void (*ts_allocate_ctor)(void *, void ***); typedef void (*ts_allocate_dtor)(void *, void ***); @@ -138,6 +142,9 @@ TSRM_API void tsrm_mutex_free(MUTEX_T mutexp); TSRM_API int tsrm_mutex_lock(MUTEX_T mutexp); TSRM_API int tsrm_mutex_unlock(MUTEX_T mutexp); +#ifdef HAVE_SIGPROCMASK +TSRM_API int tsrm_sigmask(int how, const sigset_t *set, sigset_t *oldset); +#endif TSRM_API void *tsrm_set_new_thread_begin_handler(tsrm_thread_begin_func_t new_thread_begin_handler); TSRM_API void *tsrm_set_new_thread_end_handler(tsrm_thread_end_func_t new_thread_end_handler); Modified: php/php-src/trunk/TSRM/tsrm.m4 =================================================================== --- php/php-src/trunk/TSRM/tsrm.m4 2011-06-02 20:01:40 UTC (rev 311739) +++ php/php-src/trunk/TSRM/tsrm.m4 2011-06-02 21:16:50 UTC (rev 311740) @@ -30,6 +30,8 @@ AC_CHECK_HEADERS(stdarg.h) +AC_CHECK_FUNCS(sigprocmask) + ]) Modified: php/php-src/trunk/Zend/Makefile.am =================================================================== --- php/php-src/trunk/Zend/Makefile.am 2011-06-02 20:01:40 UTC (rev 311739) +++ php/php-src/trunk/Zend/Makefile.am 2011-06-02 21:16:50 UTC (rev 311740) @@ -17,7 +17,7 @@ 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@ Modified: php/php-src/trunk/Zend/Zend.m4 =================================================================== --- php/php-src/trunk/Zend/Zend.m4 2011-06-02 20:01:40 UTC (rev 311739) +++ php/php-src/trunk/Zend/Zend.m4 2011-06-02 21:16:50 UTC (rev 311740) @@ -392,9 +392,23 @@ 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],[ ]) Modified: php/php-src/trunk/Zend/zend.c =================================================================== --- php/php-src/trunk/Zend/zend.c 2011-06-02 20:01:40 UTC (rev 311739) +++ php/php-src/trunk/Zend/zend.c 2011-06-02 21:16:50 UTC (rev 311740) @@ -108,6 +108,9 @@ 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 @@ } 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_shutdown(TSRMLS_D) /* {{{ */ { +#ifdef ZEND_SIGNALS + zend_signal_shutdown(TSRMLS_C); +#endif #ifdef ZEND_WIN32 zend_shutdown_timeout_thread(); #endif Modified: php/php-src/trunk/Zend/zend.h =================================================================== --- php/php-src/trunk/Zend/zend.h 2011-06-02 20:01:40 UTC (rev 311739) +++ php/php-src/trunk/Zend/zend.h 2011-06-02 21:16:50 UTC (rev 311740) @@ -531,8 +531,10 @@ 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); @@ -678,8 +680,10 @@ 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); @@ -702,9 +706,16 @@ #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); Modified: php/php-src/trunk/Zend/zend_alloc.c =================================================================== --- php/php-src/trunk/Zend/zend_alloc.c 2011-06-02 20:01:40 UTC (rev 311739) +++ php/php-src/trunk/Zend/zend_alloc.c 2011-06-02 21:16:50 UTC (rev 311740) @@ -1882,7 +1882,12 @@ 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); size_t bitmap; @@ -1902,6 +1907,7 @@ 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 @@ 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 @@ #if ZEND_MM_CACHE zend_mm_free_cache(heap); #endif +out_of_memory: HANDLE_UNBLOCK_INTERRUPTIONS(); -out_of_memory: #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 @@ } 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 @@ 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 @@ 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,14 @@ size_t true_size; size_t orig_size; void *ptr; + TSRMLS_FETCH(); 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 +2146,6 @@ 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 +2161,9 @@ /* 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 +2206,7 @@ } #endif + HANDLE_UNBLOCK_INTERRUPTIONS(); return ptr; } } @@ -2211,7 +2221,6 @@ 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 +2251,6 @@ 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 +2261,6 @@ 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 +2293,8 @@ #if ZEND_MM_CACHE zend_mm_free_cache(heap); #endif +out_of_memory: HANDLE_UNBLOCK_INTERRUPTIONS(); -out_of_memory: #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 +2358,7 @@ 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 +2547,18 @@ 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 +2566,40 @@ { 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 +2607,22 @@ 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; } Modified: php/php-src/trunk/Zend/zend_execute_API.c =================================================================== --- php/php-src/trunk/Zend/zend_execute_API.c 2011-06-02 20:01:40 UTC (rev 311739) +++ php/php-src/trunk/Zend/zend_execute_API.c 2011-06-02 21:16:50 UTC (rev 311740) @@ -1469,7 +1469,7 @@ # 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 @@ # 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); + signo = SIGPROF; +# endif + + 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, SIGPROF); - } + sigaddset(&sigset, signo); + sigprocmask(SIG_UNBLOCK, &sigset, NULL); # endif - if(reset_signals) { - sigprocmask(SIG_UNBLOCK, &sigset, NULL); } } -# endif +# endif /* HAVE_SETITIMER */ #endif } /* }}} */ Modified: php/php-src/trunk/Zend/zend_hash.c =================================================================== --- php/php-src/trunk/Zend/zend_hash.c 2011-06-02 20:01:40 UTC (rev 311739) +++ php/php-src/trunk/Zend/zend_hash.c 2011-06-02 21:16:50 UTC (rev 311740) @@ -197,6 +197,9 @@ ulong h; uint nIndex; Bucket *p; +#ifdef ZEND_SIGNALS + TSRMLS_FETCH(); +#endif IS_CONSISTENT(ht); @@ -276,6 +279,9 @@ { uint nIndex; Bucket *p; +#ifdef ZEND_SIGNALS + TSRMLS_FETCH(); +#endif IS_CONSISTENT(ht); @@ -431,6 +437,9 @@ static int zend_hash_do_resize(HashTable *ht) { Bucket **t; +#ifdef ZEND_SIGNALS + TSRMLS_FETCH(); +#endif IS_CONSISTENT(ht); @@ -475,6 +484,9 @@ { uint nIndex; Bucket *p; +#ifdef ZEND_SIGNALS + TSRMLS_FETCH(); +#endif IS_CONSISTENT(ht); @@ -595,6 +607,9 @@ 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_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; Added: php/php-src/trunk/Zend/zend_signal.c =================================================================== --- php/php-src/trunk/Zend/zend_signal.c (rev 0) +++ php/php-src/trunk/Zend/zend_signal.c 2011-06-02 21:16:50 UTC (rev 311740) @@ -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 | + | lice...@php.net so we can mail you a copy immediately. | + +----------------------------------------------------------------------+ + | Authors: Lucas Nealan <lu...@php.net> | + | Arnaud Le Blanc <lbarn...@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 + */ Property changes on: php/php-src/trunk/Zend/zend_signal.c ___________________________________________________________________ Added: svn:keywords + Id Rev Revision Added: svn:eol-style + native Added: php/php-src/trunk/Zend/zend_signal.h =================================================================== --- php/php-src/trunk/Zend/zend_signal.h (rev 0) +++ php/php-src/trunk/Zend/zend_signal.h 2011-06-02 21:16:50 UTC (rev 311740) @@ -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 | + | lice...@php.net so we can mail you a copy immediately. | + +----------------------------------------------------------------------+ + | Authors: Lucas Nealan <lu...@php.net> | + | Arnaud Le Blanc <lbarn...@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: + */ Property changes on: php/php-src/trunk/Zend/zend_signal.h ___________________________________________________________________ Added: svn:keywords + Id Rev Revision Added: svn:eol-style + native Modified: php/php-src/trunk/configure.in =================================================================== --- php/php-src/trunk/configure.in 2011-06-02 20:01:40 UTC (rev 311739) +++ php/php-src/trunk/configure.in 2011-06-02 21:16:50 UTC (rev 311740) @@ -1473,7 +1473,7 @@ zend_list.c zend_indent.c zend_builtin_functions.c zend_sprintf.c \ zend_ini.c zend_qsort.c zend_multibyte.c zend_ts_hash.c zend_stream.c \ zend_iterators.c zend_interfaces.c zend_exceptions.c zend_strtod.c zend_gc.c \ - zend_closures.c zend_float.c zend_string.c) + zend_closures.c zend_float.c zend_string.c zend_signal.c) if test -r "$abs_srcdir/Zend/zend_objects.c"; then PHP_ADD_SOURCES(Zend, zend_objects.c zend_object_handlers.c zend_objects_API.c zend_default_classes.c) Modified: php/php-src/trunk/ext/pcntl/php_signal.c =================================================================== --- php/php-src/trunk/ext/pcntl/php_signal.c 2011-06-02 20:01:40 UTC (rev 311739) +++ php/php-src/trunk/ext/pcntl/php_signal.c 2011-06-02 21:16:50 UTC (rev 311740) @@ -41,8 +41,14 @@ act.sa_flags |= SA_RESTART; /* SVR4, 4.3+BSD */ #endif } +#ifdef ZEND_SIGNALS + if (zend_sigaction(signo, &act, &oact) < 0) +#else if (sigaction(signo, &act, &oact) < 0) +#endif + { return SIG_ERR; + } return oact.sa_handler; } Modified: php/php-src/trunk/ext/standard/info.c =================================================================== --- php/php-src/trunk/ext/standard/info.c 2011-06-02 20:01:40 UTC (rev 311739) +++ php/php-src/trunk/ext/standard/info.c 2011-06-02 21:16:50 UTC (rev 311740) @@ -747,6 +747,12 @@ php_info_print_table_row(2, "Thread Safety", "disabled" ); #endif +#ifdef ZEND_SIGNALS + php_info_print_table_row(2, "Zend Signal Handling", "enabled" ); +#else + php_info_print_table_row(2, "Zend Signal Handling", "disabled" ); +#endif + php_info_print_table_row(2, "Zend Memory Manager", is_zend_mm(TSRMLS_C) ? "enabled" : "disabled" ); { Modified: php/php-src/trunk/ext/standard/tests/general_functions/phpinfo.phpt =================================================================== --- php/php-src/trunk/ext/standard/tests/general_functions/phpinfo.phpt 2011-06-02 20:01:40 UTC (rev 311739) +++ php/php-src/trunk/ext/standard/tests/general_functions/phpinfo.phpt 2011-06-02 21:16:50 UTC (rev 311740) @@ -35,6 +35,7 @@ Debug Build => %s Thread Safety => %s Zend Memory Manager => %s +Zend Signal Handling => %s Zend Multibyte Support => %s IPv6 Support => %s DTrace Support => %s Modified: php/php-src/trunk/main/SAPI.c =================================================================== --- php/php-src/trunk/main/SAPI.c 2011-06-02 20:01:40 UTC (rev 311739) +++ php/php-src/trunk/main/SAPI.c 2011-06-02 21:16:50 UTC (rev 311740) @@ -75,6 +75,10 @@ SAPI_API void sapi_startup(sapi_module_struct *sf) { +#ifdef ZEND_SIGNALS + zend_signal_startup(); +#endif + sf->ini_entries = NULL; sapi_module = *sf; Modified: php/php-src/trunk/main/main.c =================================================================== --- php/php-src/trunk/main/main.c 2011-06-02 20:01:40 UTC (rev 311739) +++ php/php-src/trunk/main/main.c 2011-06-02 21:16:50 UTC (rev 311740) @@ -1371,8 +1371,12 @@ */ static void sigchld_handler(int apar) { + int errno_save = errno; + while (waitpid(-1, NULL, WNOHANG) > 0); signal(SIGCHLD, sigchld_handler); + + errno = errno_save; } /* }}} */ #endif @@ -1441,6 +1445,10 @@ zend_activate(TSRMLS_C); sapi_activate(TSRMLS_C); +#ifdef ZEND_SIGNALS + zend_signal_activate(TSRMLS_C); +#endif + if (PG(max_input_time) == -1) { zend_set_timeout(EG(timeout_seconds), 1); } else { @@ -1565,6 +1573,10 @@ } zend_try { + zend_unset_timeout(TSRMLS_C); + } zend_end_try(); + + zend_try { int i; for (i = 0; i < NUM_TRACK_VARS; i++) { @@ -1590,9 +1602,11 @@ zend_interned_strings_restore(TSRMLS_C); +#ifdef ZEND_SIGNALS zend_try { - zend_unset_timeout(TSRMLS_C); + zend_signal_deactivate(TSRMLS_C); } zend_end_try(); +#endif } /* }}} */ @@ -1647,13 +1661,18 @@ sapi_send_headers(TSRMLS_C); } zend_end_try(); - /* 5. Call all extensions RSHUTDOWN functions */ + /* 5. Reset max_execution_time (no longer executing php code after response sent) */ + zend_try { + zend_unset_timeout(TSRMLS_C); + } zend_end_try(); + + /* 6. Call all extensions RSHUTDOWN functions */ if (PG(modules_activated)) { zend_deactivate_modules(TSRMLS_C); php_free_shutdown_functions(TSRMLS_C); } - /* 6. Destroy super-globals */ + /* 7. Destroy super-globals */ zend_try { int i; @@ -1664,7 +1683,7 @@ } } zend_end_try(); - /* 6.5 free last error information */ + /* 7.5 free last error information */ if (PG(last_error_message)) { free(PG(last_error_message)); PG(last_error_message) = NULL; @@ -1889,8 +1908,10 @@ zuf.write_function = php_output_wrapper; zuf.fopen_function = php_fopen_wrapper_for_zend; zuf.message_handler = php_message_handler_for_zend; +#ifndef ZEND_SIGNALS zuf.block_interruptions = sapi_module.block_interruptions; zuf.unblock_interruptions = sapi_module.unblock_interruptions; +#endif zuf.get_configuration_directive = php_get_configuration_directive_for_zend; zuf.ticks_function = php_run_ticks; zuf.on_timeout = php_on_timeout;
-- PHP CVS Mailing List (http://www.php.net/) To unsubscribe, visit: http://www.php.net/unsub.php