@Made major improvents to the pcntl extension(Jason):

@ - Greatly improved performance, by switching the signal callback mechanism
@   to use ticks
@ - Implemented object signal callback ability by using array($obj, $method)
@ - Added a restart parameter to pcntl_signal, which allows you to disable
@   the default of system call restarting
Changed callback hash table to be initialized and destroyed per reqeust
(allows the ability to use request life zvals as handles)
Nuked warnings
Modified test script to adjust to new ticks backend
Some slight WS fixes
This commit is contained in:
Jason Greene 2002-08-22 04:20:10 +00:00
parent faff3a6e8a
commit 261a60a360
5 changed files with 74 additions and 177 deletions

View File

@ -22,8 +22,9 @@
#if PCNTL_DEBUG
#define DEBUG_OUT printf("DEBUG: ");printf
#define IF_DEBUG(z) z
#else
#define DEBUG_OUT
#define IF_DEBUG(z)
#endif
#ifdef HAVE_CONFIG_H
@ -37,9 +38,6 @@
ZEND_DECLARE_MODULE_GLOBALS(pcntl)
static int le_pcntl;
static int pcntl_zend_extension_active;
function_entry pcntl_functions[] = {
PHP_FE(pcntl_fork, NULL)
PHP_FE(pcntl_waitpid, second_arg_force_ref)
@ -61,8 +59,8 @@ zend_module_entry pcntl_module_entry = {
pcntl_functions,
PHP_MINIT(pcntl),
PHP_MSHUTDOWN(pcntl),
NULL,
NULL,
PHP_RINIT(pcntl),
PHP_RSHUTDOWN(pcntl),
PHP_MINFO(pcntl),
NO_VERSION_YET,
STANDARD_MODULE_PROPERTIES
@ -70,32 +68,8 @@ zend_module_entry pcntl_module_entry = {
#ifdef COMPILE_DL_PCNTL
ZEND_GET_MODULE(pcntl)
#define PCNTL_ZEND_EXT ZEND_DLEXPORT
#else
#define PCNTL_ZEND_EXT
#endif
PCNTL_ZEND_EXT zend_extension pcntl_extension_entry = {
"pcntl",
"1.0",
"Jason Greene",
"http://www.php.net",
"2001",
pcntl_zend_extension_startup,
pcntl_zend_extension_shutdown,
pcntl_zend_extension_activate,
pcntl_zend_extension_deactivate,
NULL,
NULL,
pcntl_zend_extension_statement_handler,
NULL,
NULL,
NULL,
NULL,
NULL
};
void php_register_signal_constants(INIT_FUNC_ARGS)
{
@ -159,9 +133,7 @@ void php_register_signal_constants(INIT_FUNC_ARGS)
}
static void php_pcntl_init_globals(zend_pcntl_globals *pcntl_globals)
{
zend_hash_init(&pcntl_globals->php_signal_table, 16, NULL, NULL, 1);
{
/* Just in case ... */
memset(&pcntl_globals->php_signal_queue,0,sizeof(pcntl_globals->php_signal_queue));
@ -170,30 +142,32 @@ static void php_pcntl_init_globals(zend_pcntl_globals *pcntl_globals)
pcntl_globals->processing_signal_queue = 0;
}
static void php_pcntl_shutdown_globals(zend_pcntl_globals *pcntl_globals)
PHP_RINIT_FUNCTION(pcntl)
{
zend_hash_destroy(&pcntl_globals->php_signal_table);
zend_llist_destroy(&pcntl_globals->php_signal_queue);
zend_hash_init(&PCNTL_G(php_signal_table), 16, NULL, ZVAL_PTR_DTOR, 1);
return SUCCESS;
}
PHP_MINIT_FUNCTION(pcntl)
{
php_register_signal_constants(INIT_FUNC_ARGS_PASSTHRU);
ZEND_INIT_MODULE_GLOBALS(pcntl, php_pcntl_init_globals, php_pcntl_shutdown_globals);
if (zend_register_extension(&pcntl_extension_entry, 0)==FAILURE)
return FAILURE;
ZEND_INIT_MODULE_GLOBALS(pcntl, php_pcntl_init_globals, NULL);
php_add_tick_function(pcntl_tick_handler);
return SUCCESS;
}
PHP_MSHUTDOWN_FUNCTION(pcntl)
{
zend_hash_destroy(&PCNTL_G(php_signal_table));
zend_llist_destroy(&PCNTL_G(php_signal_queue));
return SUCCESS;
}
PHP_RSHUTDOWN_FUNCTION(pcntl)
{
zend_hash_destroy(&PCNTL_G(php_signal_table));
return SUCCESS;
}
PHP_MINFO_FUNCTION(pcntl)
{
@ -475,141 +449,69 @@ PHP_FUNCTION(pcntl_exec)
}
/* }}} */
/* {{{ proto bool pcntl_signal(long signo, mixed handle)
/* {{{ proto bool pcntl_signal(long signo, mixed handle, [bool restart_syscalls])
Assigns a system signal handler to a PHP function */
PHP_FUNCTION(pcntl_signal)
{
zval **signo, **handle;
zval *handle, **dest_handle = NULL;
char *func_name;
long signo;
zend_bool restart_syscalls = 1;
if (ZEND_NUM_ARGS() != 2 || zend_get_parameters_ex(2, &signo, &handle) == FAILURE) {
WRONG_PARAM_COUNT;
if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "lz|b", &signo, &handle, &restart_syscalls) == FAILURE) {
return;
}
convert_to_long_ex(signo);
/* 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) {
if (Z_TYPE_P(handle)==IS_LONG) {
if (Z_LVAL_P(handle)!= (long) SIG_DFL && Z_LVAL_P(handle) != (long) SIG_IGN) {
php_error(E_WARNING, "Invalid value for handle argument specifEied in %s", get_active_function_name(TSRMLS_C));
}
if (php_signal(Z_LVAL_PP(signo), (Sigfunc *) Z_LVAL_PP(handle))==SIG_ERR) {
if (php_signal(signo, (Sigfunc *) Z_LVAL_P(handle), (int) restart_syscalls) == SIG_ERR) {
php_error(E_WARNING, "Error assigning singal in %s", get_active_function_name(TSRMLS_C));
RETURN_FALSE;
}
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)) {
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);
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);
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;
/* Add the function name to our signal table */
zend_hash_index_update(&PCNTL_G(php_signal_table), signo, (void **) &handle, sizeof(zval *), (void **) &dest_handle);
if (dest_handle) zval_add_ref(dest_handle);
if (php_signal(signo, pcntl_signal_handler, (int) restart_syscalls) == SIG_ERR) {
php_error(E_WARNING, "Error assigning singal in %s", get_active_function_name(TSRMLS_C));
RETURN_FALSE;
}
RETURN_TRUE;
}
/* }}} */
/* 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, &param 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);
if (! PCNTL_G(processing_signal_queue) && pcntl_zend_extension_active ) {
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;
DEBUG_OUT("Added queue entry\n");
IF_DEBUG(DEBUG_OUT("Added queue entry\n"));
}
return;
}
/* Pcntl Zend Extension Hooks */
int pcntl_zend_extension_startup(zend_extension *extension)
{
TSRMLS_FETCH();
DEBUG_OUT("Statup Called\n");
pcntl_zend_extension_active = 1;
CG(extended_info) = 1;
return SUCCESS;
}
void pcntl_zend_extension_shutdown(zend_extension *extension)
{
DEBUG_OUT("Shutdown Called\n");
return;
}
void pcntl_zend_extension_activate(void)
{
TSRMLS_FETCH();
DEBUG_OUT("Activate Called\n");
pcntl_zend_extension_active = 1;
CG(extended_info) = 1;
return;
}
void pcntl_zend_extension_deactivate(void)
{
DEBUG_OUT("Deactivate Called\n");
pcntl_zend_extension_active = 0;
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)
void pcntl_tick_handler()
{
zend_llist_element *element;
zval *param, *call_name, *retval;
char *func_name;
zval *param, **handle, *retval;
TSRMLS_FETCH();
/* Bail if the queue is empty or if we are already playing the queue*/
@ -624,26 +526,24 @@ void pcntl_zend_extension_statement_handler(zend_op_array *op_array)
return;
}
/* Disable queue so this function is not infinate */
/* Prevent reentrant handler calls */
PCNTL_G(processing_signal_queue) = 1;
/* Allocate */
MAKE_STD_ZVAL(param);
MAKE_STD_ZVAL(call_name);
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) {
if (zend_hash_index_find(&PCNTL_G(php_signal_table), *signal_num, (void **) &handle)==FAILURE) {
continue;
}
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, &param TSRMLS_CC);
/* Call php singal handler - Note that we do not report errors, and we ignore the eturn value */
call_user_function(EG(function_table), NULL, *handle, retval, 1, &param TSRMLS_CC);
}
/* Clear */
zend_llist_clean(&PCNTL_G(php_signal_queue));
@ -653,7 +553,6 @@ void pcntl_zend_extension_statement_handler(zend_op_array *op_array)
/* Clean up */
efree(param);
efree(call_name);
efree(retval);
}

View File

@ -23,7 +23,7 @@
#include <sys/wait.h>
#include "php_signal.h"
#include "zend_extensions.h"
#include "php_ticks.h"
extern zend_module_entry pcntl_module_entry;
#define phpext_pcntl_ptr &pcntl_module_entry
@ -52,13 +52,7 @@ PHP_FUNCTION(pcntl_signal);
PHP_FUNCTION(pcntl_exec);
static void pcntl_signal_handler(int);
/* Zend extension prototypes */
int pcntl_zend_extension_startup(zend_extension *extension);
void pcntl_zend_extension_shutdown(zend_extension *extension);
void pcntl_zend_extension_activate(void);
void pcntl_zend_extension_deactivate(void);
void pcntl_zend_extension_statement_handler(zend_op_array *op_array);
static void pcntl_tick_handler();
ZEND_BEGIN_MODULE_GLOBALS(pcntl)

View File

@ -20,16 +20,16 @@
#include "php_signal.h"
/* php_signal using sigaction is taken verbatim from Advanced Programing
/* php_signal using sigaction is derrived from Advanced Programing
* in the Unix Environment by W. Richard Stevens p 298. */
Sigfunc *php_signal(int signo, Sigfunc *func)
Sigfunc *php_signal(int signo, Sigfunc *func, int restart)
{
struct sigaction act,oact;
act.sa_handler = func;
sigemptyset(&act.sa_mask);
act.sa_flags = 0;
if (signo == SIGALRM) {
if (signo == SIGALRM || (! restart)) {
#ifdef SA_INTERRUPT
act.sa_flags |= SA_INTERRUPT; /* SunOS */
#endif

View File

@ -23,6 +23,6 @@
#define PHP_SIGNAL_H
typedef void Sigfunc(int);
Sigfunc *php_signal(int signo, Sigfunc *func);
Sigfunc *php_signal(int signo, Sigfunc *func, int restart);
#endif

View File

@ -1,35 +1,39 @@
#!/opt/devel/php4/php -q
#!../../php -q
<?
declare(ticks=1);
function alarm_handle($signal){
if ($signal==SIGALRM) print "Caught SIGALRM!!!\n";
}
function usr1_handle($signal){
if ($signal==SIGUSR1) print "Caught SIGUSR1!!!\n";
if ($signal==SIGUSR1) print "Caught SIGUSR1!!!\n";
}
print "This test will demonstrate a fork followed by ipc via signals.\n";
$pid=pcntl_fork();
if ($pid==0) {
pcntl_signal(SIGUSR1, "usr1_handle");
pcntl_signal(SIGALRM, "alarm_handle");
print "Child: Waiting for alarm.....\n";
sleep(100);
print "Child: Waiting for usr1......\n";
sleep(100);
print "Child: Resetting Alarm handler to Ignore....\n";
pcntl_signal(SIGALRM, SIG_IGN);
sleep(10);
print "Done\n";
pcntl_signal(SIGUSR1, "usr1_handle");
pcntl_signal(SIGALRM, "alarm_handle");
print "Child: Waiting for alarm.....\n";
sleep(100);
print "Child: Waiting for usr1......\n";
sleep(100);
print "Child: Resetting Alarm handler to Ignore....\n";
pcntl_signal(SIGALRM, SIG_IGN);
sleep(10);
print "Done\n";
} else {
print "Parent: Waiting 10 seconds....\n";
sleep(10);
print "Parent: Sending SIGALRM to Child\n";
posix_kill($pid,SIGALRM);
sleep(1);
print "Parent: Senging SIGUSR1 to Child\n";
posix_kill($pid,SIGUSR1);
sleep(1);
print "Parent: Sending SIGALRM to Child\n";
pcntl_waitpid($pid, &$status, $options);
print "Parent: Waiting 10 seconds....\n";
sleep(10);
print "Parent: Sending SIGALRM to Child\n";
posix_kill($pid,SIGALRM);
sleep(1);
print "Parent: Senging SIGUSR1 to Child\n";
posix_kill($pid,SIGUSR1);
sleep(1);
print "Parent: Sending SIGALRM to Child\n";
pcntl_waitpid($pid, &$status, $options);
}