diff options
Diffstat (limited to 'ext/pcntl/pcntl.c')
-rwxr-xr-x | ext/pcntl/pcntl.c | 104 |
1 files changed, 67 insertions, 37 deletions
diff --git a/ext/pcntl/pcntl.c b/ext/pcntl/pcntl.c index bd5badf5a..25b0b86a8 100755 --- a/ext/pcntl/pcntl.c +++ b/ext/pcntl/pcntl.c @@ -16,7 +16,7 @@ +----------------------------------------------------------------------+ */ -/* $Id: pcntl.c,v 1.44.2.2 2004/12/14 14:00:50 dmitry Exp $ */ +/* $Id: pcntl.c,v 1.44.2.3 2005/05/07 14:58:02 wez Exp $ */ #define PCNTL_DEBUG 0 @@ -162,17 +162,13 @@ void php_register_signal_constants(INIT_FUNC_ARGS) static void php_pcntl_init_globals(zend_pcntl_globals *pcntl_globals) { - /* Just in case ... */ - memset(&pcntl_globals->php_signal_queue,0,sizeof(pcntl_globals->php_signal_queue)); - - zend_llist_init(&pcntl_globals->php_signal_queue, sizeof (long), NULL, 1); - pcntl_globals->signal_queue_ready = 0; - pcntl_globals->processing_signal_queue = 0; + memset(pcntl_globals, 0, sizeof(*pcntl_globals)); } PHP_RINIT_FUNCTION(pcntl) { - zend_hash_init(&PCNTL_G(php_signal_table), 16, NULL, ZVAL_PTR_DTOR, 1); + zend_hash_init(&PCNTL_G(php_signal_table), 16, NULL, ZVAL_PTR_DTOR, 0); + PCNTL_G(head) = PCNTL_G(tail) = PCNTL_G(spares) = NULL; return SUCCESS; } @@ -187,13 +183,26 @@ PHP_MINIT_FUNCTION(pcntl) PHP_MSHUTDOWN_FUNCTION(pcntl) { - zend_llist_destroy(&PCNTL_G(php_signal_queue)); return SUCCESS; } PHP_RSHUTDOWN_FUNCTION(pcntl) { + struct php_pcntl_pending_signal *sig; + + /* FIXME: if a signal is delivered after this point, things will go pear shaped; + * need to remove signal handlers */ zend_hash_destroy(&PCNTL_G(php_signal_table)); + while (PCNTL_G(head)) { + sig = PCNTL_G(head); + PCNTL_G(head) = sig->next; + efree(sig); + } + while (PCNTL_G(spares)) { + sig = PCNTL_G(spares); + PCNTL_G(spares) = sig->next; + efree(sig); + } return SUCCESS; } @@ -520,6 +529,19 @@ PHP_FUNCTION(pcntl_signal) return; } + if (!PCNTL_G(spares)) { + /* since calling malloc() from within a signal handler is not portable, + * pre-allocate a few records for recording signals */ + int i; + for (i = 0; i < 32; i++) { + struct php_pcntl_pending_signal *psig; + + psig = emalloc(sizeof(*psig)); + psig->next = PCNTL_G(spares); + PCNTL_G(spares) = psig; + } + } + /* 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) { @@ -631,57 +653,63 @@ PHP_FUNCTION(pcntl_setpriority) /* Our custom signal handler that calls the appropriate php_function */ static void pcntl_signal_handler(int signo) { - long signal_num = signo; + struct php_pcntl_pending_signal *psig; TSRMLS_FETCH(); - IF_DEBUG(DEBUG_OUT("Caught signo %d\n", signo)); - if (! PCNTL_G(processing_signal_queue)) { - zend_llist_add_element(&PCNTL_G(php_signal_queue), &signal_num); - PCNTL_G(signal_queue_ready) = 1; - IF_DEBUG(DEBUG_OUT("Added queue entry\n")); + psig = PCNTL_G(spares); + if (!psig) { + /* oops, too many signals for us to track, so we'll forget about this one */ + return; + } + PCNTL_G(spares) = psig->next; + + psig->signo = signo; + psig->next = NULL; + + /* the head check is important, as the tick handler cannot atomically clear both + * the head and tail */ + if (PCNTL_G(head) && PCNTL_G(tail)) { + PCNTL_G(tail)->next = psig; + } else { + PCNTL_G(head) = psig; } - return; + PCNTL_G(tail) = psig; } void pcntl_tick_handler() { - zend_llist_element *element; zval *param, **handle, *retval; + struct php_pcntl_pending_signal *queue, *next; TSRMLS_FETCH(); /* Bail if the queue is empty or if we are already playing the queue*/ - if (! PCNTL_G(signal_queue_ready) || PCNTL_G(processing_signal_queue)) + if (! PCNTL_G(head) || PCNTL_G(processing_signal_queue)) return; - /* Mark our queue empty */ - PCNTL_G(signal_queue_ready) = 0; - - /* If for some reason our signal queue is empty then return */ - if (zend_llist_count(&PCNTL_G(php_signal_queue)) <= 0) { - return; - } - /* Prevent reentrant handler calls */ PCNTL_G(processing_signal_queue) = 1; + queue = PCNTL_G(head); + PCNTL_G(head) = NULL; /* simple stores are atomic */ + /* Allocate */ MAKE_STD_ZVAL(param); MAKE_STD_ZVAL(retval); - /* Traverse through our signal queue and call the appropriate php functions */ - for (element = (&PCNTL_G(php_signal_queue))->head; element; element = element->next) { - long *signal_num = (long *)&element->data; - if (zend_hash_index_find(&PCNTL_G(php_signal_table), *signal_num, (void **) &handle)==FAILURE) { - continue; + while (queue) { + if (zend_hash_index_find(&PCNTL_G(php_signal_table), queue->signo, (void **) &handle)==SUCCESS) { + ZVAL_LONG(param, queue->signo); + + /* Call php signal handler - Note that we do not report errors, and we ignore the return value */ + /* FIXME: this is probably broken when multiple signals are handled in this while loop (retval) */ + call_user_function(EG(function_table), NULL, *handle, retval, 1, ¶m TSRMLS_CC); } - ZVAL_LONG(param, *signal_num); - - /* Call php signal handler - Note that we do not report errors, and we ignore the return value */ - call_user_function(EG(function_table), NULL, *handle, retval, 1, ¶m TSRMLS_CC); + next = queue->next; + queue->next = PCNTL_G(spares); + PCNTL_G(spares) = queue; + queue = next; } - /* Clear */ - zend_llist_clean(&PCNTL_G(php_signal_queue)); /* Re-enable queue */ PCNTL_G(processing_signal_queue) = 0; @@ -691,6 +719,8 @@ void pcntl_tick_handler() efree(retval); } + + /* * Local variables: * tab-width: 4 |