mirror of
https://github.com/php/php-src.git
synced 2024-10-13 20:42:38 +00:00
261a60a360
@ - 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
566 lines
17 KiB
C
Executable File
566 lines
17 KiB
C
Executable File
/*
|
|
+----------------------------------------------------------------------+
|
|
| PHP Version 4 |
|
|
+----------------------------------------------------------------------+
|
|
| Copyright (c) 1997-2002 The PHP Group |
|
|
+----------------------------------------------------------------------+
|
|
| This source file is subject to version 2.02 of the PHP license, |
|
|
| that is bundled with this package in the file LICENSE, and is |
|
|
| available at through the world-wide-web at |
|
|
| http://www.php.net/license/2_02.txt. |
|
|
| If you did not receive a copy of the PHP license and are unable to |
|
|
| obtain it through the world-wide-web, please send a note to |
|
|
| license@php.net so we can mail you a copy immediately. |
|
|
+----------------------------------------------------------------------+
|
|
| Author: Jason Greene <jason@inetgurus.net> |
|
|
+----------------------------------------------------------------------+
|
|
*/
|
|
|
|
/* $Id$ */
|
|
|
|
#define PCNTL_DEBUG 0
|
|
|
|
#if PCNTL_DEBUG
|
|
#define DEBUG_OUT printf("DEBUG: ");printf
|
|
#define IF_DEBUG(z) z
|
|
#else
|
|
#define IF_DEBUG(z)
|
|
#endif
|
|
|
|
#ifdef HAVE_CONFIG_H
|
|
#include "config.h"
|
|
#endif
|
|
|
|
#include "php.h"
|
|
#include "php_ini.h"
|
|
#include "ext/standard/info.h"
|
|
#include "php_pcntl.h"
|
|
|
|
ZEND_DECLARE_MODULE_GLOBALS(pcntl)
|
|
|
|
function_entry pcntl_functions[] = {
|
|
PHP_FE(pcntl_fork, NULL)
|
|
PHP_FE(pcntl_waitpid, second_arg_force_ref)
|
|
PHP_FE(pcntl_signal, NULL)
|
|
PHP_FE(pcntl_wifexited, NULL)
|
|
PHP_FE(pcntl_wifstopped, NULL)
|
|
PHP_FE(pcntl_wifsignaled, NULL)
|
|
PHP_FE(pcntl_wexitstatus, NULL)
|
|
PHP_FE(pcntl_wtermsig, NULL)
|
|
PHP_FE(pcntl_wstopsig, NULL)
|
|
PHP_FE(pcntl_exec, NULL)
|
|
PHP_FE(pcntl_alarm, NULL)
|
|
{NULL, NULL, NULL}
|
|
};
|
|
|
|
zend_module_entry pcntl_module_entry = {
|
|
STANDARD_MODULE_HEADER,
|
|
"pcntl",
|
|
pcntl_functions,
|
|
PHP_MINIT(pcntl),
|
|
PHP_MSHUTDOWN(pcntl),
|
|
PHP_RINIT(pcntl),
|
|
PHP_RSHUTDOWN(pcntl),
|
|
PHP_MINFO(pcntl),
|
|
NO_VERSION_YET,
|
|
STANDARD_MODULE_PROPERTIES
|
|
};
|
|
|
|
#ifdef COMPILE_DL_PCNTL
|
|
ZEND_GET_MODULE(pcntl)
|
|
#endif
|
|
|
|
void php_register_signal_constants(INIT_FUNC_ARGS)
|
|
{
|
|
|
|
/* Wait Constants */
|
|
#ifdef WNOHANG
|
|
REGISTER_LONG_CONSTANT("WNOHANG", (long) WNOHANG, CONST_CS | CONST_PERSISTENT);
|
|
#endif
|
|
#ifdef WUNTRACED
|
|
REGISTER_LONG_CONSTANT("WUNTRACED", (long) WUNTRACED, CONST_CS | CONST_PERSISTENT);
|
|
#endif
|
|
|
|
/* Signal Constants */
|
|
REGISTER_LONG_CONSTANT("SIG_IGN", (long) SIG_IGN, CONST_CS | CONST_PERSISTENT);
|
|
REGISTER_LONG_CONSTANT("SIG_DFL", (long) SIG_DFL, CONST_CS | CONST_PERSISTENT);
|
|
REGISTER_LONG_CONSTANT("SIG_ERR", (long) SIG_ERR, CONST_CS | CONST_PERSISTENT);
|
|
REGISTER_LONG_CONSTANT("SIGHUP", (long) SIGHUP, CONST_CS | CONST_PERSISTENT);
|
|
REGISTER_LONG_CONSTANT("SIGINT", (long) SIGINT, CONST_CS | CONST_PERSISTENT);
|
|
REGISTER_LONG_CONSTANT("SIGQUIT", (long) SIGQUIT, CONST_CS | CONST_PERSISTENT);
|
|
REGISTER_LONG_CONSTANT("SIGILL", (long) SIGILL, CONST_CS | CONST_PERSISTENT);
|
|
REGISTER_LONG_CONSTANT("SIGTRAP", (long) SIGTRAP, CONST_CS | CONST_PERSISTENT);
|
|
REGISTER_LONG_CONSTANT("SIGABRT", (long) SIGABRT, CONST_CS | CONST_PERSISTENT);
|
|
REGISTER_LONG_CONSTANT("SIGIOT", (long) SIGIOT, CONST_CS | CONST_PERSISTENT);
|
|
REGISTER_LONG_CONSTANT("SIGBUS", (long) SIGBUS, CONST_CS | CONST_PERSISTENT);
|
|
REGISTER_LONG_CONSTANT("SIGFPE", (long) SIGFPE, CONST_CS | CONST_PERSISTENT);
|
|
REGISTER_LONG_CONSTANT("SIGKILL", (long) SIGKILL, CONST_CS | CONST_PERSISTENT);
|
|
REGISTER_LONG_CONSTANT("SIGUSR1", (long) SIGUSR1, CONST_CS | CONST_PERSISTENT);
|
|
REGISTER_LONG_CONSTANT("SIGSEGV", (long) SIGSEGV, CONST_CS | CONST_PERSISTENT);
|
|
REGISTER_LONG_CONSTANT("SIGUSR2", (long) SIGUSR2, CONST_CS | CONST_PERSISTENT);
|
|
REGISTER_LONG_CONSTANT("SIGPIPE", (long) SIGPIPE, CONST_CS | CONST_PERSISTENT);
|
|
REGISTER_LONG_CONSTANT("SIGALRM", (long) SIGALRM, CONST_CS | CONST_PERSISTENT);
|
|
REGISTER_LONG_CONSTANT("SIGTERM", (long) SIGTERM, CONST_CS | CONST_PERSISTENT);
|
|
#ifdef SIGSTKFLT
|
|
REGISTER_LONG_CONSTANT("SIGSTKFLT",(long) SIGSTKFLT, CONST_CS | CONST_PERSISTENT);
|
|
#endif
|
|
#ifdef SIGCLD
|
|
REGISTER_LONG_CONSTANT("SIGCLD", (long) SIGCLD, CONST_CS | CONST_PERSISTENT);
|
|
#endif
|
|
#ifdef SIGCHLD
|
|
REGISTER_LONG_CONSTANT("SIGCHLD", (long) SIGCHLD, CONST_CS | CONST_PERSISTENT);
|
|
#endif
|
|
REGISTER_LONG_CONSTANT("SIGCONT", (long) SIGCONT, CONST_CS | CONST_PERSISTENT);
|
|
REGISTER_LONG_CONSTANT("SIGSTOP", (long) SIGSTOP, CONST_CS | CONST_PERSISTENT);
|
|
REGISTER_LONG_CONSTANT("SIGTSTP", (long) SIGTSTP, CONST_CS | CONST_PERSISTENT);
|
|
REGISTER_LONG_CONSTANT("SIGTTIN", (long) SIGTTIN, CONST_CS | CONST_PERSISTENT);
|
|
REGISTER_LONG_CONSTANT("SIGTTOU", (long) SIGTTOU, CONST_CS | CONST_PERSISTENT);
|
|
REGISTER_LONG_CONSTANT("SIGURG", (long) SIGURG , CONST_CS | CONST_PERSISTENT);
|
|
REGISTER_LONG_CONSTANT("SIGXCPU", (long) SIGXCPU, CONST_CS | CONST_PERSISTENT);
|
|
REGISTER_LONG_CONSTANT("SIGXFSZ", (long) SIGXFSZ, CONST_CS | CONST_PERSISTENT);
|
|
REGISTER_LONG_CONSTANT("SIGVTALRM",(long) SIGVTALRM, CONST_CS | CONST_PERSISTENT);
|
|
REGISTER_LONG_CONSTANT("SIGPROF", (long) SIGPROF, CONST_CS | CONST_PERSISTENT);
|
|
REGISTER_LONG_CONSTANT("SIGWINCH", (long) SIGWINCH, CONST_CS | CONST_PERSISTENT);
|
|
#ifdef SIGPOLL
|
|
REGISTER_LONG_CONSTANT("SIGPOLL", (long) SIGPOLL, CONST_CS | CONST_PERSISTENT);
|
|
#endif
|
|
REGISTER_LONG_CONSTANT("SIGIO", (long) SIGIO, CONST_CS | CONST_PERSISTENT);
|
|
#ifdef SIGPWR
|
|
REGISTER_LONG_CONSTANT("SIGPWR", (long) SIGPWR, CONST_CS | CONST_PERSISTENT);
|
|
#endif
|
|
REGISTER_LONG_CONSTANT("SIGSYS", (long) SIGSYS, CONST_CS | CONST_PERSISTENT);
|
|
REGISTER_LONG_CONSTANT("SIGBABY", (long) SIGSYS, CONST_CS | CONST_PERSISTENT);
|
|
}
|
|
|
|
static void php_pcntl_init_globals(zend_pcntl_globals *pcntl_globals)
|
|
{
|
|
/* Just in case ... */
|
|
memset(&pcntl_globals->php_signal_queue,0,sizeof(pcntl_globals->php_signal_queue));
|
|
|
|
zend_llist_init(&pcntl_globals->php_signal_queue, sizeof (long), NULL, 1);
|
|
pcntl_globals->signal_queue_ready = 0;
|
|
pcntl_globals->processing_signal_queue = 0;
|
|
}
|
|
|
|
PHP_RINIT_FUNCTION(pcntl)
|
|
{
|
|
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, NULL);
|
|
php_add_tick_function(pcntl_tick_handler);
|
|
|
|
return SUCCESS;
|
|
}
|
|
|
|
PHP_MSHUTDOWN_FUNCTION(pcntl)
|
|
{
|
|
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)
|
|
{
|
|
php_info_print_table_start();
|
|
php_info_print_table_header(2, "pcntl support", "enabled");
|
|
php_info_print_table_end();
|
|
}
|
|
|
|
/* {{{ proto int pcntl_fork(void)
|
|
Forks the currently running process following the same behavior as the UNIX fork() system call*/
|
|
PHP_FUNCTION(pcntl_fork)
|
|
{
|
|
pid_t id;
|
|
|
|
id = fork();
|
|
if (id == -1) {
|
|
php_error(E_ERROR, "Error %d in %s", errno, get_active_function_name(TSRMLS_C));
|
|
}
|
|
|
|
RETURN_LONG((long) id);
|
|
}
|
|
/* }}} */
|
|
|
|
/* {{{ proto int pcntl_alarm(int seconds)
|
|
Set an alarm clock for delivery of a signal*/
|
|
PHP_FUNCTION(pcntl_alarm)
|
|
{
|
|
long seconds;
|
|
|
|
if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "l", &seconds) == FAILURE)
|
|
return;
|
|
|
|
RETURN_LONG ((long) alarm(seconds));
|
|
}
|
|
/* }}} */
|
|
|
|
/* {{{ proto int pcntl_waitpid(long pid, long status, long options)
|
|
Waits on or returns the status of a forked child as defined by the waitpid() system call */
|
|
PHP_FUNCTION(pcntl_waitpid)
|
|
{
|
|
long pid, options = 0;
|
|
zval *z_status = NULL;
|
|
int status;
|
|
pid_t child_id;
|
|
|
|
if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "lz|l", &pid, &z_status, &options) == FAILURE)
|
|
return;
|
|
|
|
convert_to_long_ex(&z_status);
|
|
|
|
status = Z_LVAL_P(z_status);
|
|
|
|
child_id = waitpid((pid_t) pid, &status, options);
|
|
|
|
Z_LVAL_P(z_status) = status;
|
|
|
|
RETURN_LONG((long) child_id);
|
|
}
|
|
/* }}} */
|
|
|
|
/* {{{ proto bool pcntl_wifexited(long status)
|
|
Returns true if the child status code represents a successful exit */
|
|
PHP_FUNCTION(pcntl_wifexited)
|
|
{
|
|
#ifdef WIFEXITED
|
|
zval **status;
|
|
int status_word;
|
|
|
|
if (ZEND_NUM_ARGS() != 1 || zend_get_parameters_ex(ZEND_NUM_ARGS(), &status) == FAILURE) {
|
|
WRONG_PARAM_COUNT;
|
|
}
|
|
|
|
status_word = (int) Z_LVAL_PP(status);
|
|
|
|
if (WIFEXITED(status_word)) RETURN_TRUE;
|
|
#endif
|
|
RETURN_FALSE;
|
|
}
|
|
/* }}} */
|
|
|
|
/* {{{ proto bool pcntl_wifstopped(long status)
|
|
Returns true if the child status code represents a stopped process (WUNTRACED must have been used with waitpid) */
|
|
PHP_FUNCTION(pcntl_wifstopped)
|
|
{
|
|
#ifdef WIFSTOPPED
|
|
zval **status;
|
|
int status_word;
|
|
|
|
if (ZEND_NUM_ARGS() != 1 || zend_get_parameters_ex(ZEND_NUM_ARGS(), &status) == FAILURE) {
|
|
WRONG_PARAM_COUNT;
|
|
}
|
|
|
|
status_word = (int) Z_LVAL_PP(status);
|
|
|
|
if (WIFSTOPPED(status_word)) RETURN_TRUE;
|
|
#endif
|
|
RETURN_FALSE;
|
|
}
|
|
/* }}} */
|
|
|
|
/* {{{ proto bool pcntl_wifsignaled(long status)
|
|
Returns true if the child status code represents a process that was terminated due to a signal */
|
|
PHP_FUNCTION(pcntl_wifsignaled)
|
|
{
|
|
#ifdef WIFSIGNALED
|
|
zval **status;
|
|
int status_word;
|
|
|
|
if (ZEND_NUM_ARGS() != 1 || zend_get_parameters_ex(ZEND_NUM_ARGS(), &status) == FAILURE) {
|
|
WRONG_PARAM_COUNT;
|
|
}
|
|
|
|
status_word = (int) Z_LVAL_PP(status);
|
|
|
|
if (WIFSIGNALED(status_word)) RETURN_TRUE;
|
|
#endif
|
|
RETURN_FALSE;
|
|
}
|
|
/* }}} */
|
|
|
|
/* {{{ proto int pcntl_wexitstatus(long status)
|
|
Returns the status code of a child's exit */
|
|
PHP_FUNCTION(pcntl_wexitstatus)
|
|
{
|
|
#ifdef WEXITSTATUS
|
|
zval **status;
|
|
int status_word;
|
|
|
|
if (ZEND_NUM_ARGS() != 1 || zend_get_parameters_ex(ZEND_NUM_ARGS(), &status) == FAILURE) {
|
|
WRONG_PARAM_COUNT;
|
|
}
|
|
|
|
status_word = (int) Z_LVAL_PP(status);
|
|
|
|
/* WEXITSTATUS only returns 8 bits so we *MUST* cast this to signed char
|
|
if you want to have valid negative exit codes */
|
|
RETURN_LONG((signed char) WEXITSTATUS(status_word));
|
|
#else
|
|
RETURN_FALSE;
|
|
#endif
|
|
}
|
|
/* }}} */
|
|
|
|
/* {{{ proto int pcntl_wtermsig(long status)
|
|
Returns the number of the signal that terminated the process who's status code is passed */
|
|
PHP_FUNCTION(pcntl_wtermsig)
|
|
{
|
|
#ifdef WTERMSIG
|
|
zval **status;
|
|
int status_word;
|
|
|
|
if (ZEND_NUM_ARGS() != 1 || zend_get_parameters_ex(ZEND_NUM_ARGS(), &status) == FAILURE) {
|
|
WRONG_PARAM_COUNT;
|
|
}
|
|
|
|
status_word = (int) Z_LVAL_PP(status);
|
|
|
|
RETURN_LONG(WTERMSIG(status_word));
|
|
#else
|
|
RETURN_FALSE;
|
|
#endif
|
|
}
|
|
/* }}} */
|
|
|
|
/* {{{ proto int pcntl_wstopsig(long status)
|
|
Returns the number of the signal that caused the process to stop who's status code is passed */
|
|
PHP_FUNCTION(pcntl_wstopsig)
|
|
{
|
|
#ifdef WSTOPSIG
|
|
zval **status;
|
|
int status_word;
|
|
|
|
if (ZEND_NUM_ARGS() != 1 || zend_get_parameters_ex(ZEND_NUM_ARGS(), &status) == FAILURE) {
|
|
WRONG_PARAM_COUNT;
|
|
}
|
|
|
|
status_word = (int) Z_LVAL_PP(status);
|
|
|
|
RETURN_LONG(WSTOPSIG(status_word));
|
|
#else
|
|
RETURN_FALSE;
|
|
#endif
|
|
}
|
|
/* }}} */
|
|
|
|
/* {{{ proto bool pcntl_exec(string path [, array args [, array envs]])
|
|
Executes specified program in current process space as defined by exec(2) */
|
|
PHP_FUNCTION(pcntl_exec)
|
|
{
|
|
zval *args, *envs;
|
|
zval **element;
|
|
HashTable *args_hash, *envs_hash;
|
|
int argc = 0, argi = 0;
|
|
int envc = 0, envi = 0;
|
|
int return_val = 0;
|
|
char **argv = NULL, **envp = NULL;
|
|
char **current_arg, **pair;
|
|
int pair_length;
|
|
char *key;
|
|
int key_length;
|
|
char *path;
|
|
int path_len;
|
|
long key_num;
|
|
|
|
if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "s|aa", &path, &path_len, &args, &envs) == FAILURE) {
|
|
return;
|
|
}
|
|
|
|
if (ZEND_NUM_ARGS() > 1) {
|
|
/* Build argumnent list */
|
|
args_hash = HASH_OF(args);
|
|
argc = zend_hash_num_elements(args_hash);
|
|
|
|
argv = alloca((argc+2) * sizeof(char *));
|
|
*argv = path;
|
|
for ( zend_hash_internal_pointer_reset(args_hash), current_arg = argv+1;
|
|
(argi < argc && (zend_hash_get_current_data(args_hash, (void **) &element) == SUCCESS));
|
|
(argi++, current_arg++, zend_hash_move_forward(args_hash)) ) {
|
|
|
|
convert_to_string_ex(element);
|
|
*current_arg = Z_STRVAL_PP(element);
|
|
}
|
|
*(current_arg) = NULL;
|
|
} else {
|
|
argv = alloca(2 * sizeof(char *));
|
|
*argv = path;
|
|
*(argv+1) = NULL;
|
|
}
|
|
|
|
if ( ZEND_NUM_ARGS() == 3 ) {
|
|
/* Build environment pair list */
|
|
envs_hash = HASH_OF(envs);
|
|
envc = zend_hash_num_elements(envs_hash);
|
|
|
|
envp = alloca((envc+1) * sizeof(char *));
|
|
for ( zend_hash_internal_pointer_reset(envs_hash), pair = envp;
|
|
(envi < envc && (zend_hash_get_current_data(envs_hash, (void **) &element) == SUCCESS));
|
|
(envi++, pair++, zend_hash_move_forward(envs_hash)) ) {
|
|
switch (return_val = zend_hash_get_current_key_ex(envs_hash, &key, &key_length, &key_num, 0, NULL)) {
|
|
case HASH_KEY_IS_LONG:
|
|
key = alloca(101);
|
|
snprintf(key, 100, "%ld", key_num);
|
|
key_length = strlen(key);
|
|
break;
|
|
case HASH_KEY_NON_EXISTANT:
|
|
pair--;
|
|
continue;
|
|
}
|
|
|
|
convert_to_string_ex(element);
|
|
|
|
/* Length of element + equal sign + length of key + null */
|
|
pair_length = Z_STRLEN_PP(element) + key_length + 2;
|
|
*pair = emalloc(pair_length);
|
|
strlcpy(*pair, key, key_length);
|
|
strlcat(*pair, "=", pair_length);
|
|
strlcat(*pair, Z_STRVAL_PP(element), pair_length);
|
|
|
|
/* Cleanup */
|
|
if (return_val == HASH_KEY_IS_LONG) free_alloca(key);
|
|
}
|
|
*(pair) = NULL;
|
|
}
|
|
|
|
if (execve(path, argv, envp) == -1) {
|
|
php_error(E_WARNING, "Error has occured in %s: (errno %d) %s",
|
|
get_active_function_name(TSRMLS_C), errno, strerror(errno));
|
|
}
|
|
|
|
/* Cleanup */
|
|
if (envp != NULL) {
|
|
for (pair = envp; *pair != NULL; pair++) efree(*pair);
|
|
free_alloca(envp);
|
|
}
|
|
|
|
free_alloca(argv);
|
|
|
|
RETURN_FALSE;
|
|
}
|
|
/* }}} */
|
|
|
|
/* {{{ 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 *handle, **dest_handle = NULL;
|
|
char *func_name;
|
|
long signo;
|
|
zend_bool restart_syscalls = 1;
|
|
|
|
if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "lz|b", &signo, &handle, &restart_syscalls) == FAILURE) {
|
|
return;
|
|
}
|
|
|
|
/* Special long value case for SIG_DFL and 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(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 (!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), 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;
|
|
}
|
|
/* }}} */
|
|
|
|
/* Our custom signal handler that calls the appropriate php_function */
|
|
static void pcntl_signal_handler(int signo)
|
|
{
|
|
long signal_num = signo;
|
|
TSRMLS_FETCH();
|
|
|
|
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;
|
|
IF_DEBUG(DEBUG_OUT("Added queue entry\n"));
|
|
}
|
|
return;
|
|
}
|
|
|
|
void pcntl_tick_handler()
|
|
{
|
|
zend_llist_element *element;
|
|
zval *param, **handle, *retval;
|
|
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;
|
|
}
|
|
|
|
/* Prevent reentrant handler calls */
|
|
PCNTL_G(processing_signal_queue) = 1;
|
|
|
|
/* Allocate */
|
|
MAKE_STD_ZVAL(param);
|
|
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 **) &handle)==FAILURE) {
|
|
continue;
|
|
}
|
|
|
|
ZVAL_LONG(param, *signal_num);
|
|
|
|
/* 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));
|
|
|
|
/* Re-enable queue */
|
|
PCNTL_G(processing_signal_queue) = 0;
|
|
|
|
/* Clean up */
|
|
efree(param);
|
|
efree(retval);
|
|
}
|
|
|
|
/*
|
|
* Local variables:
|
|
* tab-width: 4
|
|
* c-basic-offset: 4
|
|
* indent-tabs-mode: t
|
|
* End:
|
|
*/
|