Alan, First of all, thanks for submitting a patch. I alwyas like getting patches : )
I need to spend some time reviewing this, unfortunately my time has been very limited lately (working 90-100 hour weeks with my current employer). I should be able to get to this sometime tonight. I do have some initital questions: On Mon, 2002-01-21 at 02:59, Alan Knowles wrote: > 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 Can you explain what you mean by modules, are you refering to building as a dynamic .so? > 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) > Yes, that was the unsafe async callback : ) I should remove it, but I left it there for reference. > 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. Can you explain how you are/would be using this function. The reason why pcntl_zend_extension_statement_handler is set to s zend_statement_handle is becuase there is the possibiilty that PHP/Zend could be in the process of chaging an internal datastructure when a signal is recieved, and if another php routine is executed at that state of time, corruption could possibly occur, resulting in a segfault. Insuring that a php signal handle is only executed between opcodes makes pcntl async safe. > > 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); > > > > > > > > > > -- Jason T. Greene Internet Software Engineer <[EMAIL PROTECTED]> <[EMAIL PROTECTED]> <[EMAIL PROTECTED]> Use PHP: http://www.php.net -- 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]