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]