- <?= 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)
#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)
{
# 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 ***);
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);
AC_CHECK_HEADERS(stdarg.h)
+AC_CHECK_FUNCS(sigprocmask)
+
])
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@
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],[
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()
}
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;
void zend_shutdown(TSRMLS_D) /* {{{ */
{
+#ifdef ZEND_SIGNALS
+ zend_signal_shutdown(TSRMLS_C);
+#endif
#ifdef ZEND_WIN32
zend_shutdown_timeout_thread();
#endif
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);
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);
#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);
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);
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
segment_size = heap->block_size;
}
- HANDLE_BLOCK_INTERRUPTIONS();
-
if (segment_size < true_size ||
heap->real_size + segment_size > heap->limit) {
/* Memory limit overflow */
#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
} 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);
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);
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);
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);
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);
/* 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;
}
}
#endif
+ HANDLE_UNBLOCK_INTERRUPTIONS();
return ptr;
}
}
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) {
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;
}
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)) {
#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
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;
}
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;
}
{
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;
}
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;
}
# ifdef HAVE_SETITIMER
{
struct itimerval t_r; /* timeout requested */
- sigset_t sigset;
+ int signo;
if(seconds) {
t_r.it_value.tv_sec = seconds;
# 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
}
/* }}} */
ulong h;
uint nIndex;
Bucket *p;
+#ifdef ZEND_SIGNALS
+ TSRMLS_FETCH();
+#endif
IS_CONSISTENT(ht);
{
uint nIndex;
Bucket *p;
+#ifdef ZEND_SIGNALS
+ TSRMLS_FETCH();
+#endif
IS_CONSISTENT(ht);
static int zend_hash_do_resize(HashTable *ht)
{
Bucket **t;
+#ifdef ZEND_SIGNALS
+ TSRMLS_FETCH();
+#endif
IS_CONSISTENT(ht);
{
uint nIndex;
Bucket *p;
+#ifdef ZEND_SIGNALS
+ TSRMLS_FETCH();
+#endif
IS_CONSISTENT(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) {
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;
--- /dev/null
+/*
+ +----------------------------------------------------------------------+
+ | 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
+ */
--- /dev/null
+/*
+ +----------------------------------------------------------------------+
+ | 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:
+ */
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)
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 */
/* 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;
/* $Id$ */
+#include "TSRM.h"
#include "php_signal.h"
/* php_signal using sigaction is derrived from Advanced Programing
{
struct sigaction act,oact;
act.sa_handler = func;
+#ifdef ZEND_SIGNALS
+ TSRMLS_FETCH();
+#endif
+
if (mask_all) {
sigfillset(&act.sa_mask);
} else {
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;
}
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
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" );
{
$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\"; "');
Debug Build => %s
Thread Safety => %s
Zend Memory Manager => %s
+Zend Signal Handling => %s
Zend Multibyte Support => %s
IPv6 Support => %s
DTrace Support => %s
SAPI_API void sapi_startup(sapi_module_struct *sf)
{
+#ifdef ZEND_SIGNALS
+ zend_signal_startup();
+#endif
+
sf->ini_entries = NULL;
sapi_module = *sf;
*/
static void sigchld_handler(int apar)
{
+ int errno_save = errno;
+
while (waitpid(-1, NULL, WNOHANG) > 0);
signal(SIGCHLD, sigchld_handler);
+
+ errno = errno_save;
}
/* }}} */
#endif
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 {
php_free_shutdown_functions(TSRMLS_C);
}
+ zend_try {
+ zend_unset_timeout(TSRMLS_C);
+ } zend_end_try();
+
zend_try {
int i;
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
}
/* }}} */
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;
}
} 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;
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;