mirror of
https://github.com/php/php-src.git
synced 2025-08-15 21:48:51 +02:00
Zend Signal Handling
This commit is contained in:
parent
512be854e5
commit
34d93f0c06
22 changed files with 721 additions and 41 deletions
1
NEWS
1
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)
|
||||
|
|
16
TSRM/TSRM.c
16
TSRM/TSRM.c
|
@ -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)
|
||||
{
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -30,6 +30,8 @@ AC_REQUIRE([AC_PROG_RANLIB])dnl
|
|||
|
||||
AC_CHECK_HEADERS(stdarg.h)
|
||||
|
||||
AC_CHECK_FUNCS(sigprocmask)
|
||||
|
||||
])
|
||||
|
||||
|
||||
|
|
|
@ -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@
|
||||
|
|
16
Zend/Zend.m4
16
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],[
|
||||
|
||||
|
|
|
@ -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
|
||||
|
|
11
Zend/zend.h
11
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);
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
||||
|
|
|
@ -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
|
||||
}
|
||||
/* }}} */
|
||||
|
|
|
@ -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;
|
||||
|
||||
|
|
414
Zend/zend_signal.c
Normal file
414
Zend/zend_signal.c
Normal file
|
@ -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
|
||||
*/
|
104
Zend/zend_signal.h
Normal file
104
Zend/zend_signal.h
Normal file
|
@ -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:
|
||||
*/
|
|
@ -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)
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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" );
|
||||
|
||||
{
|
||||
|
|
|
@ -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\"; "');
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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;
|
||||
|
||||
|
|
29
main/main.c
29
main/main.c
|
@ -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;
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue