mirror of
https://github.com/php/php-src.git
synced 2024-11-23 18:04:36 +08:00
@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:
parent
faff3a6e8a
commit
261a60a360
@ -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, ¶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);
|
||||
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, ¶m 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, ¶m 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);
|
||||
}
|
||||
|
||||
|
@ -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)
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
@ -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);
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user