]> granicus.if.org Git - php/commitdiff
Zend Signal Handling
authorIlia Alshanetsky <iliaa@php.net>
Wed, 22 Jun 2011 14:23:21 +0000 (14:23 +0000)
committerIlia Alshanetsky <iliaa@php.net>
Wed, 22 Jun 2011 14:23:21 +0000 (14:23 +0000)
22 files changed:
NEWS
TSRM/TSRM.c
TSRM/TSRM.h
TSRM/tsrm.m4
Zend/Makefile.am
Zend/Zend.m4
Zend/zend.c
Zend/zend.h
Zend/zend_alloc.c
Zend/zend_execute_API.c
Zend/zend_hash.c
Zend/zend_signal.c [new file with mode: 0644]
Zend/zend_signal.h [new file with mode: 0644]
configure.in
ext/pcntl/pcntl.c
ext/pcntl/php_signal.c
ext/pcntl/tests/pcntl_signal.phpt
ext/standard/info.c
ext/standard/tests/file/bug22414.phpt
ext/standard/tests/general_functions/phpinfo.phpt
main/SAPI.c
main/main.c

diff --git a/NEWS b/NEWS
index c18d1508aca07717ac2ef537870151b44cf3308a..49e029237b225241ae02aa5ed70ea33670f9c160 100644 (file)
--- a/NEWS
+++ b/NEWS
@@ -33,6 +33,7 @@ PHP                                                                        NEWS
 - <?= is now always available regardless of the short_tags setting (Rasmus)
 
 - General improvements:
+  . Zend Signal Handling. (Lucas Nealan,Arnaud Le Blanc,Brian Shire, Ilia)
   . Added multibyte support by default. Previously php had to be compiled
     with --enable-zend-multibyte. Now it can be enabled or disabled through
     zend.multibyte directive in php.ini. (Dmitry)
index 41368a4987d135f3514c33c499487622ffc743dd..efdea5c880a9ee10086519378bcbbd6d12f79fd3 100644 (file)
@@ -710,6 +710,22 @@ TSRM_API int tsrm_mutex_unlock(MUTEX_T 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()));
+       /* 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)
 {
index d3d6f9b2d79915a0ee396a56f2b8b732971505ad..b232429d4d89e07dcf87a6a9e983e6d8046b64cb 100644 (file)
@@ -90,6 +90,10 @@ typedef struct {
 # 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 MUTEX_T tsrm_mutex_alloc(void);
 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);
index 85e6a83a833176a03726a2269852b27c910f8386..b53a4bb805fffc168a26fd05aae11a7bf7656fe0 100644 (file)
@@ -30,6 +30,8 @@ AC_REQUIRE([AC_PROG_RANLIB])dnl
 
 AC_CHECK_HEADERS(stdarg.h)
 
+AC_CHECK_FUNCS(sigprocmask)
+
 ])
 
 
index 04b51081bfb5b8cbd50a739098698390b478db4e..5ec4590fefe199ab97523634de03255820a4452a 100644 (file)
@@ -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@
index ececf783b5c5685240032ff5015ceaed258cc363..67b9ba09d76bb9f3742dc8599910b330bff2f273 100644 (file)
@@ -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],[
 
index 638de824b11bc1c594b2fceb67f31643c9fc613b..8fe185660fe5f07c77473dc70414a3cad184f3f4 100644 (file)
@@ -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
index 8fe005398f1d94ad99e78dd5d172d812fcfc8019..8caa382326e9a64150ac4c93d1ce5a8dbf8d6be0 100644 (file)
@@ -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);
index 108309c1d7097af3bbd45bd1e34904c8d3c0f1de..e7e7ee9d22b943036b85826fced1ed31853b7de6 100644 (file)
@@ -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;
 }
 
index e15344a4f0c3729133ccf9f8f102dfe83980efa9..f7594d9be1b92e80e41c8505f494ac99a2799a6f 100644 (file)
@@ -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
 }
 /* }}} */
index 73c45a286cce806b4f02922b5febe27d7f772414..44313c55b6677cb5654c6f532828d801854a6d02 100644 (file)
@@ -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 (file)
index 0000000..8fe8ebc
--- /dev/null
@@ -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 (file)
index 0000000..bc10132
--- /dev/null
@@ -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:
+ */
index c1d37f281a997e957a6e7f08f40e5144904ab8c1..364e80a09ccea91a3880699b12aec13e3dd7b524 100644 (file)
@@ -1473,7 +1473,7 @@ PHP_ADD_SOURCES(Zend, \
     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)
index d07b9ea047b0ead234708618aa853d8768603d32..866106c44a5a31208b1cc1c6eac051f336bbc83e 100755 (executable)
@@ -849,6 +849,11 @@ PHP_FUNCTION(pcntl_signal)
                return;
        }
 
+       if (signo < 1 || signo > 32) {
+               php_error_docref(NULL TSRMLS_CC, E_WARNING, "Invalid signal");
+               RETURN_FALSE;
+       }
+
        if (!PCNTL_G(spares)) {
                /* since calling malloc() from within a signal handler is not portable,
                 * pre-allocate a few records for recording signals */
@@ -864,8 +869,9 @@ PHP_FUNCTION(pcntl_signal)
 
        /* Special long value case for SIG_DFL and SIG_IGN */
        if (Z_TYPE_P(handle)==IS_LONG) {
-               if (Z_LVAL_P(handle)!= (long) SIG_DFL && Z_LVAL_P(handle) != (long) SIG_IGN) {
+               if (Z_LVAL_P(handle) != (long) SIG_DFL && Z_LVAL_P(handle) != (long) SIG_IGN) {
                        php_error_docref(NULL TSRMLS_CC, E_WARNING, "Invalid value for handle argument specified");
+                       RETURN_FALSE;
                }
                if (php_signal(signo, (Sigfunc *) Z_LVAL_P(handle), (int) restart_syscalls) == SIG_ERR) {
                        PCNTL_G(last_error) = errno;
index 00ab6b425f0a82b46b17624b0d1a64981a2cc725..92ec411314ab13b9e419bfb440b97733291bb17c 100644 (file)
@@ -18,6 +18,7 @@
 
 /* $Id$ */
 
+#include "TSRM.h"
 #include "php_signal.h"
 
 /* php_signal using sigaction is derrived from Advanced Programing
@@ -26,6 +27,10 @@ Sigfunc *php_signal4(int signo, Sigfunc *func, int restart, int mask_all)
 {
        struct sigaction act,oact;
        act.sa_handler = func;
+#ifdef ZEND_SIGNALS
+       TSRMLS_FETCH();
+#endif
+
        if (mask_all) {
                sigfillset(&act.sa_mask);
        } else {
@@ -41,9 +46,15 @@ Sigfunc *php_signal4(int signo, Sigfunc *func, int restart, int mask_all)
                act.sa_flags |= SA_RESTART; /* SVR4, 4.3+BSD */
 #endif
        }
+#ifdef ZEND_SIGNALS
+       if (zend_sigaction(signo, &act, &oact TSRMLS_CC) < 0)
+#else
        if (sigaction(signo, &act, &oact) < 0)
+#endif
+       {
                return SIG_ERR;
+       }
+
        return oact.sa_handler;
 }
 
index 977f26fbcc2f5252002131f49c2210f986b9effc..efd4bba953e00d529f50f1e645b554d772912a0b 100644 (file)
@@ -28,12 +28,10 @@ Warning: pcntl_signal() expects at least 2 parameters, 0 given in %s
 NULL
 bool(true)
 
-Warning: pcntl_signal(): Invalid value for handle argument specified in %s
-
-Warning: pcntl_signal(): Error assigning signal %s
+Warning: pcntl_signal(): Invalid signal %s
 bool(false)
 
-Warning: pcntl_signal(): Error assigning signal %s
+Warning: pcntl_signal(): Invalid signal %s
 bool(false)
 
 Warning: pcntl_signal(): not callable is not a callable function name error in %s
index 18a1e947dadb799f4c023c55dbee6a61b852e2ee..2bee7e9803838a08c22d3d642065e2fb92411299 100644 (file)
@@ -747,6 +747,12 @@ PHPAPI void php_print_info(int flag TSRMLS_DC)
                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" );
 
                {
index fcd85489f32a0252bbc4ff605ad3722494ce35c9..9538c8ede8d3358d5330c2237e27268718f8592c 100644 (file)
@@ -7,7 +7,7 @@ output_handler=
 
        $php = getenv('TEST_PHP_EXECUTABLE');
        $tmpfile = tempnam(__DIR__, 'phpt');
-       $args = ' -n -dsafe_mode=off ';
+       $args = ' -n ';
        
        /* Regular Data Test */
        passthru($php . $args . ' -r " echo \"HELLO\"; "');
index 1e2494ccb93fa96fe7db00cb96b8d34eea844d67..df6aef832e5b8174b2519df28fc091b722cfa3a9 100644 (file)
@@ -35,6 +35,7 @@ PHP Extension Build => API%s
 Debug Build => %s
 Thread Safety => %s
 Zend Memory Manager => %s
+Zend Signal Handling => %s
 Zend Multibyte Support => %s
 IPv6 Support => %s
 DTrace Support => %s
index 250b796562ee9e1ec89ee51222553fc6a0d30183..a0d58805fbcd34fe481e35c72837bc9af73f88d6 100644 (file)
@@ -75,6 +75,10 @@ SAPI_API sapi_module_struct sapi_module;
 
 SAPI_API void sapi_startup(sapi_module_struct *sf)
 {
+#ifdef ZEND_SIGNALS
+       zend_signal_startup();
+#endif
+
        sf->ini_entries = NULL;
        sapi_module = *sf;
 
index 6f8c3688eaa20f96e8919c2a74edbd1aac7761f3..f4a70cb11358519a654c730635f9879385238047 100644 (file)
@@ -1372,8 +1372,12 @@ void php_on_timeout(int seconds TSRMLS_DC)
  */
 static void sigchld_handler(int apar)
 {
+       int errno_save = errno;
+
        while (waitpid(-1, NULL, WNOHANG) > 0);
        signal(SIGCHLD, sigchld_handler);
+
+       errno = errno_save;
 }
 /* }}} */
 #endif
@@ -1442,6 +1446,10 @@ int php_request_startup(TSRMLS_D)
                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 @@ void php_request_shutdown_for_hook(void *dummy)
                php_free_shutdown_functions(TSRMLS_C);
        }
 
+       zend_try {
+               zend_unset_timeout(TSRMLS_C);
+       } zend_end_try();
+
        zend_try {
                int i;
 
@@ -1591,9 +1603,11 @@ void php_request_shutdown_for_hook(void *dummy)
 
        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
 }
 
 /* }}} */
@@ -1648,13 +1662,18 @@ void php_request_shutdown(void *dummy)
                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;
 
@@ -1665,7 +1684,7 @@ void php_request_shutdown(void *dummy)
                }
        } 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;
@@ -1894,8 +1913,10 @@ int php_module_startup(sapi_module_struct *sf, zend_module_entry *additional_mod
        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;