Well, after half a dozen bug reports that didnt actually work... - this one should, could somebody comment/commit etc.
The patch includes a number of changes... - pcntl_zend_extension_active does not appear to be getting set when using modules this little magic trick to get the zval stored in the hash table for callbacks + MAKE_STD_ZVAL(handle_copy); + *handle_copy = **handle; + zval_copy_ctor(handle_copy); I deleted this as it was confusing me alot :) - obviously not essential to the patch old_pcntl_signal_handler(int signo) added a new function pcntl_doevents = works a bit like gtk::do_events(); basically calls any pending signal callbacks. - as the pcntl_zend_extension_statement_handler did not appear to get called when running from a module. best regards alan Index: pcntl.c =================================================================== RCS file: /repository/php4/ext/pcntl/pcntl.c,v retrieving revision 1.18 diff -u -r1.18 pcntl.c --- pcntl.c 4 Jan 2002 14:08:25 -0000 1.18 +++ pcntl.c 21 Jan 2002 08:36:05 -0000 @@ -18,7 +18,7 @@ /* $Id: pcntl.c,v 1.18 2002/01/04 14:08:25 hholzgra Exp $ */ -#define PCNTL_DEBUG 0 +#define PCNTL_DEBUG 0 #if PCNTL_DEBUG #define DEBUG_OUT printf("DEBUG: ");printf @@ -51,6 +51,7 @@ PHP_FE(pcntl_wtermsig, NULL) PHP_FE(pcntl_wstopsig, NULL) PHP_FE(pcntl_exec, NULL) + PHP_FE(pcntl_doevents, NULL) {NULL, NULL, NULL} }; @@ -208,7 +209,7 @@ PHP_FUNCTION(pcntl_fork) { pid_t id; - + pcntl_zend_extension_active=1; id=fork(); if (id == -1) { php_error(E_ERROR, "Error %d in %s", errno, get_active_function_name(TSRMLS_C)); @@ -463,8 +464,9 @@ PHP_FUNCTION(pcntl_signal) { zval **signo, **handle; + zval *handle_copy; char *func_name; - + if (ZEND_NUM_ARGS() != 2 || zend_get_parameters_ex(2, &signo, &handle) == FAILURE) { WRONG_PARAM_COUNT; } @@ -474,7 +476,7 @@ /* Special long value case for SIG_DFL and SIG_IGN */ if (Z_TYPE_PP(handle)==IS_LONG) { if (Z_LVAL_PP(handle)!= (long) SIG_DFL && Z_LVAL_PP(handle) != (long) SIG_IGN) { - php_error(E_WARNING, "Invalid value for handle argument specifEied in %s", get_active_function_name(TSRMLS_C)); + php_error(E_WARNING, "Invalid value for handle argument specified in %s", get_active_function_name(TSRMLS_C)); } if (php_signal(Z_LVAL_PP(signo), (Sigfunc *) Z_LVAL_PP(handle))==SIG_ERR) { php_error(E_WARNING, "Error assigning singal in %s", get_active_function_name(TSRMLS_C)); @@ -483,22 +485,18 @@ RETURN_TRUE; } - if (Z_TYPE_PP(handle)!=IS_STRING) { - php_error(E_WARNING, "Invalid type specified for handle argument in %s", get_active_function_name(TSRMLS_C)); - RETURN_FALSE; - } - - convert_to_string_ex(handle); /* Just in case */ - if (!zend_is_callable(*handle, 0, &func_name)) { - php_error(E_WARNING, "%s: %s is not a callable function name error", get_active_function_name(TSRMLS_C), func_name); + if (!zend_is_callable(*handle, 0, &func_name)) { + php_error(E_WARNING, "%s: Argument is not a callable function or method", get_active_function_name(TSRMLS_C), func_name); efree(func_name); RETURN_FALSE; } efree(func_name); - - /* Add the function name to our signal table */ - zend_hash_index_update(&PCNTL_G(php_signal_table), Z_LVAL_PP(signo), Z_STRVAL_PP(handle), (Z_STRLEN_PP(handle) + 1) * sizeof(char), NULL); - + MAKE_STD_ZVAL(handle_copy); + *handle_copy = **handle; + zval_copy_ctor(handle_copy); + + zend_hash_index_update(&PCNTL_G(php_signal_table), Z_LVAL_PP(signo), &handle_copy , sizeof(zval *), NULL); + if (php_signal(Z_LVAL_PP(signo), pcntl_signal_handler)==SIG_ERR) { php_error(E_WARNING, "Error assigning singal in %s", get_active_function_name(TSRMLS_C)); RETURN_FALSE; @@ -507,43 +505,14 @@ } /* }}} */ -/* Note Old */ -static void old_pcntl_signal_handler(int signo) -{ - char *func_name; - zval *param, *call_name, *retval; - TSRMLS_FETCH(); - - DEBUG_OUT("Caught signal: %d\n", signo); - if (zend_hash_index_find(&PCNTL_G(php_signal_table), (long) signo, (void *) &func_name)==FAILURE) { - DEBUG_OUT("Signl handler not fount"); - return; - } - /* DEBUG_OUT("Signal handler found, Calling %s\n", func_name); */ - MAKE_STD_ZVAL(param); - MAKE_STD_ZVAL(call_name); - MAKE_STD_ZVAL(retval); - ZVAL_LONG(param, signo); - ZVAL_STRING(call_name, func_name, 1); - - /* Call php singal handler - Note that we do not report errors, and we ignore the return value */ - call_user_function(EG(function_table), NULL, call_name, retval, 1, ¶m TSRMLS_CC); - - zval_dtor(call_name); - efree(call_name); - efree(param); - efree(retval); - - return; -} - + /* Our custom signal handler that calls the appropriate php_function */ static void pcntl_signal_handler(int signo) { long signal_num=signo; TSRMLS_FETCH(); - DEBUG_OUT("Caught signo %d\n", signo); + DEBUG_OUT("Caught signo %d,%d,%d\n", signo,PCNTL_G(processing_signal_queue),pcntl_zend_extension_active); if (! PCNTL_G(processing_signal_queue) && pcntl_zend_extension_active ) { zend_llist_add_element(&PCNTL_G(php_signal_queue), &signal_num); PCNTL_G(signal_queue_ready)=1; @@ -588,59 +557,91 @@ return; } + /* Custom hook to ensure signals only get called at a safe poing in Zend's execute process */ void pcntl_zend_extension_statement_handler(zend_op_array *op_array) { zend_llist_element *element; - zval *param, *call_name, *retval; + zval *param, *retval; + zval **callback; char *func_name; + int error; 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)) 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; } - + /* Disable queue so this function is not infinate */ PCNTL_G(processing_signal_queue)=1; /* Allocate */ MAKE_STD_ZVAL(param); - MAKE_STD_ZVAL(call_name); - MAKE_STD_ZVAL(retval); + 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 *) &func_name)==FAILURE) { + DEBUG_OUT("sig %d\n",*signal_num); + + + if (zend_hash_index_find(&PCNTL_G(php_signal_table), *signal_num, (void **) &callback)==FAILURE) { + php_error(E_WARNING, "%s: Signal callback for %d Not found", get_active_function_name(TSRMLS_C),*signal_num); + DEBUG_OUT("NOT FOUND"); continue; } + if (!zend_is_callable( *callback, 0, &func_name)) { + php_error(E_WARNING, "%s: %s is not a callable function or method", func_name, get_active_function_name(TSRMLS_C)); + continue; + } + convert_to_long_ex(¶m); - convert_to_string_ex(&call_name); - ZVAL_LONG(param, *signal_num); - ZVAL_STRING(call_name, func_name, 0); - - /* Call php singal handler - Note that we do not report errors, and we ignore the return value */ - call_user_function(EG(function_table), NULL, call_name, retval, 1, ¶m TSRMLS_CC); + ZVAL_LONG(param, *signal_num); + + /* Call php singal handler - Note that we do not report errors, and we ignore the return value */ + error = call_user_function(EG(function_table), NULL, *callback, retval, 1, ¶m TSRMLS_CC); + if (error == FAILURE) { + php_error(E_WARNING, "Couldn't call the SIGNAL FUNCTION"); + + } } + + + /* Clear */ - zend_llist_clean(&PCNTL_G(php_signal_queue)); - + zend_llist_clean(&PCNTL_G(php_signal_queue)); + /* Re-enable queue */ PCNTL_G(processing_signal_queue)=0; /* Clean up */ efree(param); - efree(call_name); + //efree(callback); efree(retval); + + +} + + +/* {{{ proto bool pcntl_doevents() + Calls any pending events - if you compile pcntl as a module, the + statement handler does not work, you have to do it manually */ +PHP_FUNCTION(pcntl_doevents) +{ + zend_op_array *op_array=NULL; + TSRMLS_FETCH(); + + pcntl_zend_extension_statement_handler(op_array); + + RETURN_TRUE; } +/* }}} */ /* * Local variables: -------------------------- Class example -------------------- #!/opt/devel/php4/php -q <? dl("pcntl.so"); class test { var $run=1; function alarm_handle($signal){ if ($signal==SIGALRM) { print "Caught SIGALRM!!!\n"; } } function usr1_handle($signal){ if ($signal==SIGUSR1) { print "Caught SIGUSR1!!!\n"; $this->run = 0; } } function start() { //$options=NULL; //$status=NULL; print "This test will demonstrate a fork followed by ipc via signals.\n"; $pid=pcntl_fork(); if ($pid==0) { pcntl_signal(SIGUSR1, array(&$this,"usr1_handle")); pcntl_signal(SIGALRM, array(&$this,"alarm_handle")); $this->run =1; while($this->run) { echo $this->run; usleep(1); pcntl_doevents(); } print "ChildDone\n"; pcntl_signal(SIGALRM, SIG_IGN); // kill parent! posix_kill($pid,SIGTERM); // kill myself } else { print "Parent: Waiting 10 seconds....\n"; usleep(2); print "Parent: Sending SIGALRM to Child\n"; posix_kill($pid,SIGALRM); sleep(2); print "Parent: Senging SIGUSR1 to Child\n"; posix_kill($pid,SIGUSR1); sleep(2); print "Parent: Sending SIGALRM to Child\n"; @pcntl_waitpid($pid, $status, $options); } } } $test = new test(); $test->start(); posix_kill(posix_getpid(),SIGTERM); -- PHP Development Mailing List <http://www.php.net/> To unsubscribe, e-mail: [EMAIL PROTECTED] For additional commands, e-mail: [EMAIL PROTECTED] To contact the list administrators, e-mail: [EMAIL PROTECTED]