1206 lines
35 KiB
C
Executable File
1206 lines
35 KiB
C
Executable File
/*
|
|
+----------------------------------------------------------------------+
|
|
| Swoole |
|
|
+----------------------------------------------------------------------+
|
|
| This source file is subject to version 2.0 of the Apache license, |
|
|
| that is bundled with this package in the file LICENSE, and is |
|
|
| available through the world-wide-web at the following url: |
|
|
| http://www.apache.org/licenses/LICENSE-2.0.html |
|
|
| If you did not receive a copy of the Apache2.0 license and are unable|
|
|
| to obtain it through the world-wide-web, please send a note to |
|
|
| license@swoole.com so we can mail you a copy immediately. |
|
|
+----------------------------------------------------------------------+
|
|
| Author: Tianfeng Han <mikan.tenny@gmail.com> |
|
|
+----------------------------------------------------------------------+
|
|
*/
|
|
|
|
#if __APPLE__
|
|
// Fix warning: 'daemon' is deprecated: first deprecated in macOS 10.5 - Use posix_spawn APIs instead. [-Wdeprecated-declarations]
|
|
#define daemon yes_we_know_that_daemon_is_deprecated_in_os_x_10_5_thankyou
|
|
#endif
|
|
#include "php_swoole.h"
|
|
#include "php_streams.h"
|
|
#include "php_network.h"
|
|
|
|
#if __APPLE__
|
|
#undef daemon
|
|
extern int daemon(int, int);
|
|
#endif
|
|
static PHP_METHOD(swoole_process, __construct);
|
|
static PHP_METHOD(swoole_process, __destruct);
|
|
static PHP_METHOD(swoole_process, useQueue);
|
|
static PHP_METHOD(swoole_process, statQueue);
|
|
static PHP_METHOD(swoole_process, freeQueue);
|
|
static PHP_METHOD(swoole_process, pop);
|
|
static PHP_METHOD(swoole_process, push);
|
|
static PHP_METHOD(swoole_process, kill);
|
|
static PHP_METHOD(swoole_process, signal);
|
|
static PHP_METHOD(swoole_process, alarm);
|
|
static PHP_METHOD(swoole_process, wait);
|
|
static PHP_METHOD(swoole_process, daemon);
|
|
#ifdef HAVE_CPU_AFFINITY
|
|
static PHP_METHOD(swoole_process, setaffinity);
|
|
#endif
|
|
static PHP_METHOD(swoole_process, setTimeout);
|
|
static PHP_METHOD(swoole_process, setBlocking);
|
|
static PHP_METHOD(swoole_process, start);
|
|
static PHP_METHOD(swoole_process, write);
|
|
static PHP_METHOD(swoole_process, read);
|
|
static PHP_METHOD(swoole_process, close);
|
|
static PHP_METHOD(swoole_process, exit);
|
|
static PHP_METHOD(swoole_process, exec);
|
|
|
|
static void php_swoole_onSignal(int signo);
|
|
static void free_signal_callback(void* data);
|
|
|
|
static uint32_t php_swoole_worker_round_id = 0;
|
|
static zval *signal_callback[SW_SIGNO_MAX];
|
|
static zend_class_entry swoole_process_ce;
|
|
zend_class_entry *swoole_process_class_entry_ptr;
|
|
|
|
ZEND_BEGIN_ARG_INFO_EX(arginfo_swoole_process_construct, 0, 0, 1)
|
|
ZEND_ARG_INFO(0, callback)
|
|
ZEND_ARG_INFO(0, redirect_stdin_and_stdout)
|
|
ZEND_ARG_INFO(0, pipe_type)
|
|
ZEND_END_ARG_INFO()
|
|
|
|
ZEND_BEGIN_ARG_INFO_EX(arginfo_swoole_process_void, 0, 0, 0)
|
|
ZEND_END_ARG_INFO()
|
|
|
|
ZEND_BEGIN_ARG_INFO_EX(arginfo_swoole_process_wait, 0, 0, 0)
|
|
ZEND_ARG_INFO(0, blocking)
|
|
ZEND_END_ARG_INFO()
|
|
|
|
ZEND_BEGIN_ARG_INFO_EX(arginfo_swoole_process_signal, 0, 0, 2)
|
|
ZEND_ARG_INFO(0, signal_no)
|
|
ZEND_ARG_INFO(0, callback)
|
|
ZEND_END_ARG_INFO()
|
|
|
|
ZEND_BEGIN_ARG_INFO_EX(arginfo_swoole_process_alarm, 0, 0, 1)
|
|
ZEND_ARG_INFO(0, usec)
|
|
ZEND_END_ARG_INFO()
|
|
|
|
ZEND_BEGIN_ARG_INFO_EX(arginfo_swoole_process_kill, 0, 0, 1)
|
|
ZEND_ARG_INFO(0, pid)
|
|
ZEND_ARG_INFO(0, signal_no)
|
|
ZEND_END_ARG_INFO()
|
|
|
|
ZEND_BEGIN_ARG_INFO_EX(arginfo_swoole_process_daemon, 0, 0, 0)
|
|
ZEND_ARG_INFO(0, nochdir)
|
|
ZEND_ARG_INFO(0, noclose)
|
|
ZEND_END_ARG_INFO()
|
|
|
|
#ifdef HAVE_CPU_AFFINITY
|
|
ZEND_BEGIN_ARG_INFO_EX(arginfo_swoole_process_setaffinity, 0, 0, 1)
|
|
ZEND_ARG_ARRAY_INFO(0, cpu_settings, 0)
|
|
ZEND_END_ARG_INFO()
|
|
#endif
|
|
|
|
ZEND_BEGIN_ARG_INFO_EX(arginfo_swoole_process_setTimeout, 0, 0, 1)
|
|
ZEND_ARG_INFO(0, seconds)
|
|
ZEND_END_ARG_INFO()
|
|
|
|
ZEND_BEGIN_ARG_INFO_EX(arginfo_swoole_process_setBlocking, 0, 0, 1)
|
|
ZEND_ARG_INFO(0, blocking)
|
|
ZEND_END_ARG_INFO()
|
|
|
|
ZEND_BEGIN_ARG_INFO_EX(arginfo_swoole_process_useQueue, 0, 0, 0)
|
|
ZEND_ARG_INFO(0, key)
|
|
ZEND_ARG_INFO(0, mode)
|
|
ZEND_END_ARG_INFO()
|
|
|
|
ZEND_BEGIN_ARG_INFO_EX(arginfo_swoole_process_write, 0, 0, 1)
|
|
ZEND_ARG_INFO(0, data)
|
|
ZEND_END_ARG_INFO()
|
|
|
|
ZEND_BEGIN_ARG_INFO_EX(arginfo_swoole_process_read, 0, 0, 0)
|
|
ZEND_ARG_INFO(0, size)
|
|
ZEND_END_ARG_INFO()
|
|
|
|
ZEND_BEGIN_ARG_INFO_EX(arginfo_swoole_process_push, 0, 0, 1)
|
|
ZEND_ARG_INFO(0, data)
|
|
ZEND_END_ARG_INFO()
|
|
|
|
ZEND_BEGIN_ARG_INFO_EX(arginfo_swoole_process_pop, 0, 0, 0)
|
|
ZEND_ARG_INFO(0, size)
|
|
ZEND_END_ARG_INFO()
|
|
|
|
ZEND_BEGIN_ARG_INFO_EX(arginfo_swoole_process_exit, 0, 0, 0)
|
|
ZEND_ARG_INFO(0, exit_code)
|
|
ZEND_END_ARG_INFO()
|
|
|
|
ZEND_BEGIN_ARG_INFO_EX(arginfo_swoole_process_exec, 0, 0, 2)
|
|
ZEND_ARG_INFO(0, exec_file)
|
|
ZEND_ARG_INFO(0, args)
|
|
ZEND_END_ARG_INFO()
|
|
|
|
ZEND_BEGIN_ARG_INFO_EX(arginfo_swoole_process_name, 0, 0, 1)
|
|
ZEND_ARG_INFO(0, process_name)
|
|
ZEND_END_ARG_INFO()
|
|
|
|
#define MSGQUEUE_NOWAIT (1 << 8)
|
|
|
|
static const zend_function_entry swoole_process_methods[] =
|
|
{
|
|
PHP_ME(swoole_process, __construct, arginfo_swoole_process_construct, ZEND_ACC_PUBLIC | ZEND_ACC_CTOR)
|
|
PHP_ME(swoole_process, __destruct, arginfo_swoole_process_void, ZEND_ACC_PUBLIC | ZEND_ACC_DTOR)
|
|
PHP_ME(swoole_process, wait, arginfo_swoole_process_wait, ZEND_ACC_PUBLIC | ZEND_ACC_STATIC)
|
|
PHP_ME(swoole_process, signal, arginfo_swoole_process_signal, ZEND_ACC_PUBLIC | ZEND_ACC_STATIC)
|
|
PHP_ME(swoole_process, alarm, arginfo_swoole_process_alarm, ZEND_ACC_PUBLIC | ZEND_ACC_STATIC)
|
|
PHP_ME(swoole_process, kill, arginfo_swoole_process_kill, ZEND_ACC_PUBLIC | ZEND_ACC_STATIC)
|
|
PHP_ME(swoole_process, daemon, arginfo_swoole_process_daemon, ZEND_ACC_PUBLIC | ZEND_ACC_STATIC)
|
|
#ifdef HAVE_CPU_AFFINITY
|
|
PHP_ME(swoole_process, setaffinity, arginfo_swoole_process_setaffinity, ZEND_ACC_PUBLIC | ZEND_ACC_STATIC)
|
|
#endif
|
|
PHP_ME(swoole_process, setTimeout, arginfo_swoole_process_setTimeout, ZEND_ACC_PUBLIC)
|
|
PHP_ME(swoole_process, setBlocking, arginfo_swoole_process_setBlocking, ZEND_ACC_PUBLIC)
|
|
PHP_ME(swoole_process, useQueue, arginfo_swoole_process_useQueue, ZEND_ACC_PUBLIC)
|
|
PHP_ME(swoole_process, statQueue, arginfo_swoole_process_void, ZEND_ACC_PUBLIC)
|
|
PHP_ME(swoole_process, freeQueue, arginfo_swoole_process_void, ZEND_ACC_PUBLIC)
|
|
PHP_ME(swoole_process, start, arginfo_swoole_process_void, ZEND_ACC_PUBLIC)
|
|
PHP_ME(swoole_process, write, arginfo_swoole_process_write, ZEND_ACC_PUBLIC)
|
|
PHP_ME(swoole_process, close, arginfo_swoole_process_void, ZEND_ACC_PUBLIC)
|
|
PHP_ME(swoole_process, read, arginfo_swoole_process_read, ZEND_ACC_PUBLIC)
|
|
PHP_ME(swoole_process, push, arginfo_swoole_process_push, ZEND_ACC_PUBLIC)
|
|
PHP_ME(swoole_process, pop, arginfo_swoole_process_pop, ZEND_ACC_PUBLIC)
|
|
PHP_ME(swoole_process, exit, arginfo_swoole_process_exit, ZEND_ACC_PUBLIC)
|
|
PHP_ME(swoole_process, exec, arginfo_swoole_process_exec, ZEND_ACC_PUBLIC)
|
|
PHP_FALIAS(name, swoole_set_process_name, arginfo_swoole_process_name)
|
|
PHP_FE_END
|
|
};
|
|
|
|
void swoole_process_init(int module_number TSRMLS_DC)
|
|
{
|
|
SWOOLE_INIT_CLASS_ENTRY(swoole_process_ce, "swoole_process", "Swoole\\Process", swoole_process_methods);
|
|
swoole_process_class_entry_ptr = zend_register_internal_class(&swoole_process_ce TSRMLS_CC);
|
|
SWOOLE_CLASS_ALIAS(swoole_process, "Swoole\\Process");
|
|
|
|
zend_declare_class_constant_long(swoole_process_class_entry_ptr, SW_STRL("IPC_NOWAIT")-1, MSGQUEUE_NOWAIT TSRMLS_CC);
|
|
zend_declare_class_constant_long(swoole_process_class_entry_ptr, SW_STRL("PIPE_MASTER")-1, SW_PIPE_CLOSE_MASTER TSRMLS_CC);
|
|
zend_declare_class_constant_long(swoole_process_class_entry_ptr, SW_STRL("PIPE_WORKER")-1, SW_PIPE_CLOSE_WORKER TSRMLS_CC);
|
|
zend_declare_class_constant_long(swoole_process_class_entry_ptr, SW_STRL("PIPE_READ")-1, SW_PIPE_CLOSE_READ TSRMLS_CC);
|
|
zend_declare_class_constant_long(swoole_process_class_entry_ptr, SW_STRL("PIPE_WRITE")-1, SW_PIPE_CLOSE_WRITE TSRMLS_CC);
|
|
bzero(signal_callback, sizeof(signal_callback));
|
|
|
|
zend_declare_property_null(swoole_process_class_entry_ptr, SW_STRL("pipe")-1, ZEND_ACC_PUBLIC TSRMLS_CC);
|
|
zend_declare_property_null(swoole_process_class_entry_ptr, SW_STRL("callback")-1, ZEND_ACC_PUBLIC TSRMLS_CC);
|
|
zend_declare_property_null(swoole_process_class_entry_ptr, SW_STRL("msgQueueId")-1, ZEND_ACC_PUBLIC TSRMLS_CC);
|
|
zend_declare_property_null(swoole_process_class_entry_ptr, SW_STRL("msgQueueKey")-1, ZEND_ACC_PUBLIC TSRMLS_CC);
|
|
zend_declare_property_null(swoole_process_class_entry_ptr, SW_STRL("pid")-1, ZEND_ACC_PUBLIC TSRMLS_CC);
|
|
zend_declare_property_null(swoole_process_class_entry_ptr, SW_STRL("id")-1, ZEND_ACC_PUBLIC TSRMLS_CC);
|
|
|
|
/**
|
|
* 31 signal constants
|
|
*/
|
|
zval *zpcntl;
|
|
if (sw_zend_hash_find(&module_registry, ZEND_STRS("pcntl"), (void **) &zpcntl) == FAILURE)
|
|
{
|
|
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("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
|
|
REGISTER_LONG_CONSTANT("SIGCHLD", (long) SIGCHLD, CONST_CS | CONST_PERSISTENT);
|
|
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);
|
|
REGISTER_LONG_CONSTANT("SIGIO", (long) SIGIO, CONST_CS | CONST_PERSISTENT);
|
|
#ifdef SIGPWR
|
|
REGISTER_LONG_CONSTANT("SIGPWR", (long) SIGPWR, CONST_CS | CONST_PERSISTENT);
|
|
#endif
|
|
#ifdef SIGSYS
|
|
REGISTER_LONG_CONSTANT("SIGSYS", (long) SIGSYS, CONST_CS | CONST_PERSISTENT);
|
|
#endif
|
|
REGISTER_LONG_CONSTANT("SIG_IGN", (long) SIG_IGN, CONST_CS | CONST_PERSISTENT);
|
|
}
|
|
}
|
|
|
|
static PHP_METHOD(swoole_process, __construct)
|
|
{
|
|
zend_bool redirect_stdin_and_stdout = 0;
|
|
long pipe_type = 2;
|
|
zval *callback;
|
|
|
|
//only cli env
|
|
if (!SWOOLE_G(cli))
|
|
{
|
|
swoole_php_fatal_error(E_ERROR, "swoole_process only can be used in PHP CLI mode.");
|
|
RETURN_FALSE;
|
|
}
|
|
|
|
if (SwooleG.serv && SwooleG.serv->gs->start == 1 && swIsMaster())
|
|
{
|
|
swoole_php_fatal_error(E_ERROR, "swoole_process can't be used in master process.");
|
|
RETURN_FALSE;
|
|
}
|
|
|
|
if (SwooleAIO.init)
|
|
{
|
|
swoole_php_fatal_error(E_ERROR, "unable to create process with async-io threads.");
|
|
RETURN_FALSE;
|
|
}
|
|
|
|
if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "z|bl", &callback, &redirect_stdin_and_stdout, &pipe_type) == FAILURE)
|
|
{
|
|
RETURN_FALSE;
|
|
}
|
|
|
|
char *func_name = NULL;
|
|
if (!sw_zend_is_callable(callback, 0, &func_name TSRMLS_CC))
|
|
{
|
|
swoole_php_fatal_error(E_ERROR, "function '%s' is not callable", func_name);
|
|
efree(func_name);
|
|
RETURN_FALSE;
|
|
}
|
|
efree(func_name);
|
|
|
|
swWorker *process = emalloc(sizeof(swWorker));
|
|
bzero(process, sizeof(swWorker));
|
|
|
|
int base = 1;
|
|
if (SwooleG.serv && SwooleG.serv->gs->start)
|
|
{
|
|
base = SwooleG.serv->worker_num + SwooleG.serv->task_worker_num + SwooleG.serv->user_worker_num;
|
|
}
|
|
if (php_swoole_worker_round_id == 0)
|
|
{
|
|
php_swoole_worker_round_id = base;
|
|
}
|
|
process->id = php_swoole_worker_round_id++;
|
|
|
|
if (redirect_stdin_and_stdout)
|
|
{
|
|
process->redirect_stdin = 1;
|
|
process->redirect_stdout = 1;
|
|
process->redirect_stderr = 1;
|
|
/**
|
|
* Forced to use stream pipe
|
|
*/
|
|
pipe_type = 1;
|
|
}
|
|
|
|
if (pipe_type > 0)
|
|
{
|
|
swPipe *_pipe = emalloc(sizeof(swWorker));
|
|
int socket_type = pipe_type == 1 ? SOCK_STREAM : SOCK_DGRAM;
|
|
if (swPipeUnsock_create(_pipe, 1, socket_type) < 0)
|
|
{
|
|
RETURN_FALSE;
|
|
}
|
|
|
|
process->pipe_object = _pipe;
|
|
process->pipe_master = _pipe->getFd(_pipe, SW_PIPE_MASTER);
|
|
process->pipe_worker = _pipe->getFd(_pipe, SW_PIPE_WORKER);
|
|
process->pipe = process->pipe_master;
|
|
|
|
zend_update_property_long(swoole_process_class_entry_ptr, getThis(), ZEND_STRL("pipe"), process->pipe_master TSRMLS_CC);
|
|
}
|
|
|
|
swoole_set_object(getThis(), process);
|
|
zend_update_property(swoole_process_class_entry_ptr, getThis(), ZEND_STRL("callback"), callback TSRMLS_CC);
|
|
}
|
|
|
|
static PHP_METHOD(swoole_process, __destruct)
|
|
{
|
|
swWorker *process = swoole_get_object(getThis());
|
|
swPipe *_pipe = process->pipe_object;
|
|
if (_pipe)
|
|
{
|
|
_pipe->close(_pipe);
|
|
efree(_pipe);
|
|
}
|
|
if (process->queue)
|
|
{
|
|
efree(process->queue);
|
|
}
|
|
efree(process);
|
|
}
|
|
|
|
static PHP_METHOD(swoole_process, wait)
|
|
{
|
|
int status;
|
|
zend_bool blocking = 1;
|
|
|
|
if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "|b", &blocking) == FAILURE)
|
|
{
|
|
RETURN_FALSE;
|
|
}
|
|
|
|
int options = 0;
|
|
if (!blocking)
|
|
{
|
|
options |= WNOHANG;
|
|
}
|
|
|
|
pid_t pid = swWaitpid(-1, &status, options);
|
|
if (pid > 0)
|
|
{
|
|
array_init(return_value);
|
|
add_assoc_long(return_value, "pid", pid);
|
|
add_assoc_long(return_value, "code", WEXITSTATUS(status));
|
|
add_assoc_long(return_value, "signal", WTERMSIG(status));
|
|
}
|
|
else
|
|
{
|
|
RETURN_FALSE;
|
|
}
|
|
}
|
|
|
|
static PHP_METHOD(swoole_process, useQueue)
|
|
{
|
|
long msgkey = 0;
|
|
long mode = 2;
|
|
|
|
if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "|ll", &msgkey, &mode) == FAILURE)
|
|
{
|
|
RETURN_FALSE;
|
|
}
|
|
|
|
swWorker *process = swoole_get_object(getThis());
|
|
|
|
if (msgkey <= 0)
|
|
{
|
|
msgkey = ftok(sw_zend_get_executed_filename(), 1);
|
|
}
|
|
|
|
swMsgQueue *queue = emalloc(sizeof(swMsgQueue));
|
|
if (swMsgQueue_create(queue, 1, msgkey, 0) < 0)
|
|
{
|
|
RETURN_FALSE;
|
|
}
|
|
if (mode & MSGQUEUE_NOWAIT)
|
|
{
|
|
swMsgQueue_set_blocking(queue, 0);
|
|
mode = mode & (~MSGQUEUE_NOWAIT);
|
|
}
|
|
process->queue = queue;
|
|
process->ipc_mode = mode;
|
|
zend_update_property_long(swoole_process_class_entry_ptr, getThis(), ZEND_STRL("msgQueueId"), queue->msg_id TSRMLS_CC);
|
|
zend_update_property_long(swoole_process_class_entry_ptr, getThis(), ZEND_STRL("msgQueueKey"), msgkey TSRMLS_CC);
|
|
RETURN_TRUE;
|
|
}
|
|
|
|
static PHP_METHOD(swoole_process, statQueue)
|
|
{
|
|
swWorker *process = swoole_get_object(getThis());
|
|
if (!process->queue)
|
|
{
|
|
swoole_php_fatal_error(E_WARNING, "no queue, can't get stats of the queue.");
|
|
RETURN_FALSE;
|
|
}
|
|
|
|
int queue_num = -1;
|
|
int queue_bytes = -1;
|
|
if (swMsgQueue_stat(process->queue, &queue_num, &queue_bytes) == 0)
|
|
{
|
|
array_init(return_value);
|
|
sw_add_assoc_long_ex(return_value, ZEND_STRS("queue_num"), queue_num);
|
|
sw_add_assoc_long_ex(return_value, ZEND_STRS("queue_bytes"), queue_bytes);
|
|
}
|
|
else
|
|
{
|
|
RETURN_FALSE;
|
|
}
|
|
}
|
|
|
|
static PHP_METHOD(swoole_process, freeQueue)
|
|
{
|
|
swWorker *process = swoole_get_object(getThis());
|
|
if (process->queue && swMsgQueue_free(process->queue) == SW_OK)
|
|
{
|
|
efree(process->queue);
|
|
process->queue = NULL;
|
|
RETURN_TRUE;
|
|
}
|
|
else
|
|
{
|
|
RETURN_FALSE;
|
|
}
|
|
}
|
|
|
|
static PHP_METHOD(swoole_process, kill)
|
|
{
|
|
long pid;
|
|
long sig = SIGTERM;
|
|
|
|
if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "l|l", &pid, &sig) == FAILURE)
|
|
{
|
|
RETURN_FALSE;
|
|
}
|
|
|
|
int ret = kill((int) pid, (int) sig);
|
|
if (ret < 0)
|
|
{
|
|
if (!(sig == 0 && errno == ESRCH))
|
|
{
|
|
swoole_php_error(E_WARNING, "kill(%d, %d) failed. Error: %s[%d]", (int) pid, (int) sig, strerror(errno), errno);
|
|
}
|
|
RETURN_FALSE;
|
|
}
|
|
RETURN_TRUE;
|
|
}
|
|
|
|
static PHP_METHOD(swoole_process, signal)
|
|
{
|
|
zval *callback = NULL;
|
|
long signo = 0;
|
|
|
|
if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "lz", &signo, &callback) == FAILURE)
|
|
{
|
|
return;
|
|
}
|
|
|
|
if (!SWOOLE_G(cli))
|
|
{
|
|
swoole_php_fatal_error(E_ERROR, "cannot use swoole_process::signal here.");
|
|
RETURN_FALSE;
|
|
}
|
|
|
|
if (SwooleG.serv && SwooleG.serv->gs->start)
|
|
{
|
|
if ((swIsWorker() || swIsTaskWorker()) && signo == SIGTERM)
|
|
{
|
|
swoole_php_fatal_error(E_WARNING, "unable to register SIGTERM in worker/task process.");
|
|
RETURN_FALSE;
|
|
}
|
|
else if (swIsManager() && (signo == SIGTERM || signo == SIGUSR1 || signo == SIGUSR2 || signo == SIGALRM))
|
|
{
|
|
swoole_php_fatal_error(E_WARNING, "unable to register SIGTERM/SIGUSR1/SIGUSR2/SIGALRM in manager process.");
|
|
RETURN_FALSE;
|
|
}
|
|
else if (swIsMaster() && (signo == SIGTERM || signo == SIGUSR1 || signo == SIGUSR2 || signo == SIGALRM || signo == SIGCHLD))
|
|
{
|
|
swoole_php_fatal_error(E_WARNING, "unable to register SIGTERM/SIGUSR1/SIGUSR2/SIGALRM/SIGCHLD in manager process.");
|
|
RETURN_FALSE;
|
|
}
|
|
}
|
|
|
|
php_swoole_check_reactor();
|
|
swSignalHander handler;
|
|
|
|
if (callback == NULL || ZVAL_IS_NULL(callback))
|
|
{
|
|
callback = signal_callback[signo];
|
|
if (callback)
|
|
{
|
|
swSignal_add(signo, NULL);
|
|
SwooleG.main_reactor->defer(SwooleG.main_reactor, free_signal_callback, callback);
|
|
signal_callback[signo] = NULL;
|
|
RETURN_TRUE;
|
|
}
|
|
else
|
|
{
|
|
swoole_php_error(E_WARNING, "no callback.");
|
|
RETURN_FALSE;
|
|
}
|
|
}
|
|
else if (Z_TYPE_P(callback) == IS_LONG && Z_LVAL_P(callback) == (long) SIG_IGN)
|
|
{
|
|
handler = NULL;
|
|
}
|
|
else
|
|
{
|
|
char *func_name;
|
|
if (!sw_zend_is_callable(callback, 0, &func_name TSRMLS_CC))
|
|
{
|
|
swoole_php_error(E_WARNING, "function '%s' is not callable", func_name);
|
|
efree(func_name);
|
|
RETURN_FALSE;
|
|
}
|
|
efree(func_name);
|
|
|
|
callback = sw_zval_dup(callback);
|
|
sw_zval_add_ref(&callback);
|
|
|
|
handler = php_swoole_onSignal;
|
|
}
|
|
|
|
/**
|
|
* for swSignalfd_setup
|
|
*/
|
|
SwooleG.main_reactor->check_signalfd = 1;
|
|
|
|
//free the old callback
|
|
if (signal_callback[signo])
|
|
{
|
|
SwooleG.main_reactor->defer(SwooleG.main_reactor, free_signal_callback, signal_callback[signo]);
|
|
}
|
|
signal_callback[signo] = callback;
|
|
|
|
#if PHP_MAJOR_VERSION >= 7 || (PHP_MAJOR_VERSION >= 5 && PHP_MINOR_VERSION >= 4)
|
|
/**
|
|
* use user settings
|
|
*/
|
|
SwooleG.use_signalfd = SwooleG.enable_signalfd;
|
|
#else
|
|
SwooleG.use_signalfd = 0;
|
|
#endif
|
|
|
|
swSignal_add(signo, handler);
|
|
|
|
RETURN_TRUE;
|
|
}
|
|
|
|
static PHP_METHOD(swoole_process, alarm)
|
|
{
|
|
long usec = 0;
|
|
long type = ITIMER_REAL;
|
|
|
|
if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "l|l", &usec, &type) == FAILURE)
|
|
{
|
|
return;
|
|
}
|
|
|
|
if (!SWOOLE_G(cli))
|
|
{
|
|
swoole_php_fatal_error(E_ERROR, "cannot use swoole_process::alarm here.");
|
|
RETURN_FALSE;
|
|
}
|
|
|
|
if (SwooleG.timer.fd != 0)
|
|
{
|
|
swoole_php_fatal_error(E_WARNING, "cannot use both 'timer' and 'alarm' at the same time.");
|
|
RETURN_FALSE;
|
|
}
|
|
|
|
struct timeval now;
|
|
if (gettimeofday(&now, NULL) < 0)
|
|
{
|
|
swoole_php_error(E_WARNING, "gettimeofday() failed. Error: %s[%d]", strerror(errno), errno);
|
|
RETURN_FALSE;
|
|
}
|
|
|
|
struct itimerval timer_set;
|
|
bzero(&timer_set, sizeof(timer_set));
|
|
|
|
if (usec > 0)
|
|
{
|
|
long _sec = usec / 1000000;
|
|
long _usec = usec - (_sec * 1000000);
|
|
|
|
timer_set.it_interval.tv_sec = _sec;
|
|
timer_set.it_interval.tv_usec = _usec;
|
|
|
|
timer_set.it_value.tv_sec = _sec;
|
|
timer_set.it_value.tv_usec = _usec;
|
|
|
|
if (timer_set.it_value.tv_usec > 1e6)
|
|
{
|
|
timer_set.it_value.tv_usec = timer_set.it_value.tv_usec - 1e6;
|
|
timer_set.it_value.tv_sec += 1;
|
|
}
|
|
}
|
|
|
|
if (setitimer(type, &timer_set, NULL) < 0)
|
|
{
|
|
swoole_php_error(E_WARNING, "setitimer() failed. Error: %s[%d]", strerror(errno), errno);
|
|
RETURN_FALSE;
|
|
}
|
|
|
|
RETURN_TRUE;
|
|
}
|
|
|
|
static void free_signal_callback(void* data)
|
|
{
|
|
zval *callback = (zval*) data;
|
|
sw_zval_free(callback);
|
|
}
|
|
|
|
/**
|
|
* safe signal
|
|
*/
|
|
static void php_swoole_onSignal(int signo)
|
|
{
|
|
zval *retval = NULL;
|
|
zval **args[1];
|
|
zval *callback = signal_callback[signo];
|
|
|
|
#if PHP_MAJOR_VERSION < 7
|
|
TSRMLS_FETCH_FROM_CTX(sw_thread_ctx ? sw_thread_ctx : NULL);
|
|
#endif
|
|
|
|
zval *zsigno;
|
|
SW_MAKE_STD_ZVAL(zsigno);
|
|
ZVAL_LONG(zsigno, signo);
|
|
|
|
args[0] = &zsigno;
|
|
|
|
if (sw_call_user_function_ex(EG(function_table), NULL, callback, &retval, 1, args, 0, NULL TSRMLS_CC) == FAILURE)
|
|
{
|
|
swoole_php_fatal_error(E_WARNING, "user_signal handler error");
|
|
}
|
|
if (EG(exception))
|
|
{
|
|
zend_exception_error(EG(exception), E_ERROR TSRMLS_CC);
|
|
}
|
|
if (retval != NULL)
|
|
{
|
|
sw_zval_ptr_dtor(&retval);
|
|
}
|
|
sw_zval_ptr_dtor(&zsigno);
|
|
}
|
|
|
|
int php_swoole_process_start(swWorker *process, zval *object TSRMLS_DC)
|
|
{
|
|
process->pipe = process->pipe_worker;
|
|
process->pid = getpid();
|
|
|
|
if (process->redirect_stdin)
|
|
{
|
|
if (dup2(process->pipe, STDIN_FILENO) < 0)
|
|
{
|
|
swoole_php_fatal_error(E_WARNING, "dup2() failed. Error: %s[%d]", strerror(errno), errno);
|
|
}
|
|
}
|
|
|
|
if (process->redirect_stdout)
|
|
{
|
|
if (dup2(process->pipe, STDOUT_FILENO) < 0)
|
|
{
|
|
swoole_php_fatal_error(E_WARNING, "dup2() failed. Error: %s[%d]", strerror(errno), errno);
|
|
}
|
|
}
|
|
|
|
if (process->redirect_stderr)
|
|
{
|
|
if (dup2(process->pipe, STDERR_FILENO) < 0)
|
|
{
|
|
swoole_php_fatal_error(E_WARNING, "dup2() failed. Error: %s[%d]", strerror(errno), errno);
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Close EventLoop
|
|
*/
|
|
if (SwooleG.main_reactor)
|
|
{
|
|
SwooleG.main_reactor->free(SwooleG.main_reactor);
|
|
SwooleG.main_reactor = NULL;
|
|
swTraceLog(SW_TRACE_PHP, "destroy reactor");
|
|
}
|
|
|
|
#ifdef SW_COROUTINE
|
|
swLinkedList *coro_timeout_list = SwooleWG.coro_timeout_list;
|
|
#endif
|
|
|
|
bzero(&SwooleWG, sizeof(SwooleWG));
|
|
SwooleG.pid = process->pid;
|
|
if (SwooleG.process_type != SW_PROCESS_USERWORKER)
|
|
{
|
|
SwooleG.process_type = 0;
|
|
}
|
|
SwooleWG.id = process->id;
|
|
|
|
#ifdef SW_COROUTINE
|
|
SwooleWG.coro_timeout_list = coro_timeout_list;
|
|
#endif
|
|
|
|
if (SwooleG.timer.fd)
|
|
{
|
|
swTimer_free(&SwooleG.timer);
|
|
bzero(&SwooleG.timer, sizeof(SwooleG.timer));
|
|
}
|
|
|
|
swSignal_clear();
|
|
|
|
zend_update_property_long(swoole_process_class_entry_ptr, object, ZEND_STRL("pid"), process->pid TSRMLS_CC);
|
|
zend_update_property_long(swoole_process_class_entry_ptr, object, ZEND_STRL("pipe"), process->pipe_worker TSRMLS_CC);
|
|
|
|
zval *zcallback = sw_zend_read_property(swoole_process_class_entry_ptr, object, ZEND_STRL("callback"), 0 TSRMLS_CC);
|
|
zval **args[1];
|
|
|
|
if (zcallback == NULL || ZVAL_IS_NULL(zcallback))
|
|
{
|
|
swoole_php_fatal_error(E_ERROR, "no callback.");
|
|
return SW_ERR;
|
|
}
|
|
|
|
zval *retval = NULL;
|
|
args[0] = &object;
|
|
sw_zval_add_ref(&object);
|
|
|
|
if (sw_call_user_function_ex(EG(function_table), NULL, zcallback, &retval, 1, args, 0, NULL TSRMLS_CC) == FAILURE)
|
|
{
|
|
swoole_php_fatal_error(E_ERROR, "callback function error");
|
|
return SW_ERR;
|
|
}
|
|
if (EG(exception))
|
|
{
|
|
zend_exception_error(EG(exception), E_ERROR TSRMLS_CC);
|
|
}
|
|
if (retval)
|
|
{
|
|
sw_zval_ptr_dtor(&retval);
|
|
}
|
|
|
|
if (SwooleG.main_reactor)
|
|
{
|
|
php_swoole_event_wait();
|
|
}
|
|
SwooleG.running = 0;
|
|
|
|
zend_bailout();
|
|
return SW_OK;
|
|
}
|
|
|
|
static PHP_METHOD(swoole_process, start)
|
|
{
|
|
swWorker *process = swoole_get_object(getThis());
|
|
|
|
if (process->pid > 0 && kill(process->pid, 0) == 0)
|
|
{
|
|
swoole_php_fatal_error(E_WARNING, "process has already been started.");
|
|
RETURN_FALSE;
|
|
}
|
|
|
|
pid_t pid = fork();
|
|
if (pid < 0)
|
|
{
|
|
swoole_php_fatal_error(E_WARNING, "fork() failed. Error: %s[%d]", strerror(errno), errno);
|
|
RETURN_FALSE;
|
|
}
|
|
else if (pid > 0)
|
|
{
|
|
process->pid = pid;
|
|
process->child_process = 0;
|
|
zend_update_property_long(swoole_server_class_entry_ptr, getThis(), ZEND_STRL("pid"), process->pid TSRMLS_CC);
|
|
RETURN_LONG(pid);
|
|
}
|
|
else
|
|
{
|
|
process->child_process = 1;
|
|
SW_CHECK_RETURN(php_swoole_process_start(process, getThis() TSRMLS_CC));
|
|
}
|
|
RETURN_TRUE;
|
|
}
|
|
|
|
static PHP_METHOD(swoole_process, read)
|
|
{
|
|
long buf_size = 8192;
|
|
|
|
if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "|l", &buf_size) == FAILURE)
|
|
{
|
|
RETURN_FALSE;
|
|
}
|
|
|
|
if (buf_size > 65536)
|
|
{
|
|
buf_size = 65536;
|
|
}
|
|
|
|
swWorker *process = swoole_get_object(getThis());
|
|
|
|
if (process->pipe == 0)
|
|
{
|
|
swoole_php_fatal_error(E_WARNING, "no pipe, can not read from pipe.");
|
|
RETURN_FALSE;
|
|
}
|
|
|
|
char *buf = emalloc(buf_size + 1);
|
|
int ret = read(process->pipe, buf, buf_size);;
|
|
if (ret < 0)
|
|
{
|
|
efree(buf);
|
|
if (errno != EINTR)
|
|
{
|
|
swoole_php_error(E_WARNING, "read() failed. Error: %s[%d]", strerror(errno), errno);
|
|
}
|
|
RETURN_FALSE;
|
|
}
|
|
buf[ret] = 0;
|
|
SW_ZVAL_STRINGL(return_value, buf, ret, 0);
|
|
#if PHP_MAJOR_VERSION >= 7
|
|
efree(buf);
|
|
#endif
|
|
}
|
|
|
|
static PHP_METHOD(swoole_process, write)
|
|
{
|
|
char *data = NULL;
|
|
zend_size_t data_len = 0;
|
|
|
|
if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "s", &data, &data_len) == FAILURE)
|
|
{
|
|
RETURN_FALSE;
|
|
}
|
|
|
|
if (data_len < 1)
|
|
{
|
|
swoole_php_fatal_error(E_WARNING, "the data to send is empty.");
|
|
RETURN_FALSE;
|
|
}
|
|
|
|
swWorker *process = swoole_get_object(getThis());
|
|
if (process->pipe == 0)
|
|
{
|
|
swoole_php_fatal_error(E_WARNING, "no pipe, can not write into pipe.");
|
|
RETURN_FALSE;
|
|
}
|
|
|
|
int ret;
|
|
|
|
//async write
|
|
if (SwooleG.main_reactor)
|
|
{
|
|
swConnection *_socket = swReactor_get(SwooleG.main_reactor, process->pipe);
|
|
if (_socket && _socket->nonblock)
|
|
{
|
|
ret = SwooleG.main_reactor->write(SwooleG.main_reactor, process->pipe, data, (size_t) data_len);
|
|
}
|
|
else
|
|
{
|
|
goto _blocking_read;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
_blocking_read: ret = swSocket_write_blocking(process->pipe, data, data_len);
|
|
}
|
|
|
|
if (ret < 0)
|
|
{
|
|
swoole_php_error(E_WARNING, "write() failed. Error: %s[%d]", strerror(errno), errno);
|
|
RETURN_FALSE;
|
|
}
|
|
ZVAL_LONG(return_value, ret);
|
|
}
|
|
|
|
static PHP_METHOD(swoole_process, push)
|
|
{
|
|
char *data;
|
|
zend_size_t length;
|
|
|
|
struct
|
|
{
|
|
long type;
|
|
char data[SW_MSGMAX];
|
|
} message;
|
|
|
|
if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "s", &data, &length) == FAILURE)
|
|
{
|
|
RETURN_FALSE;
|
|
}
|
|
|
|
if (length <= 0)
|
|
{
|
|
swoole_php_fatal_error(E_WARNING, "the data to push is empty.");
|
|
RETURN_FALSE;
|
|
}
|
|
else if (length >= sizeof(message.data))
|
|
{
|
|
swoole_php_fatal_error(E_WARNING, "the data to push is too big.");
|
|
RETURN_FALSE;
|
|
}
|
|
|
|
swWorker *process = swoole_get_object(getThis());
|
|
|
|
if (!process->queue)
|
|
{
|
|
swoole_php_fatal_error(E_WARNING, "no msgqueue, can not use push()");
|
|
RETURN_FALSE;
|
|
}
|
|
|
|
message.type = process->id;
|
|
memcpy(message.data, data, length);
|
|
|
|
if (swMsgQueue_push(process->queue, (swQueue_data *)&message, length) < 0)
|
|
{
|
|
RETURN_FALSE;
|
|
}
|
|
RETURN_TRUE;
|
|
}
|
|
|
|
static PHP_METHOD(swoole_process, pop)
|
|
{
|
|
long maxsize = SW_MSGMAX;
|
|
|
|
if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "|l", &maxsize) == FAILURE)
|
|
{
|
|
RETURN_FALSE;
|
|
}
|
|
|
|
if (maxsize > SW_MSGMAX || maxsize <= 0)
|
|
{
|
|
maxsize = SW_MSGMAX;
|
|
}
|
|
|
|
swWorker *process = swoole_get_object(getThis());
|
|
if (!process->queue)
|
|
{
|
|
swoole_php_fatal_error(E_WARNING, "no msgqueue, can not use pop()");
|
|
RETURN_FALSE;
|
|
}
|
|
|
|
struct
|
|
{
|
|
long type;
|
|
char data[SW_MSGMAX];
|
|
} message;
|
|
|
|
if (process->ipc_mode == 2)
|
|
{
|
|
message.type = 0;
|
|
}
|
|
else
|
|
{
|
|
message.type = process->id;
|
|
}
|
|
|
|
int n = swMsgQueue_pop(process->queue, (swQueue_data *) &message, maxsize);
|
|
if (n < 0)
|
|
{
|
|
RETURN_FALSE;
|
|
}
|
|
SW_RETURN_STRINGL(message.data, n, 1);
|
|
}
|
|
|
|
static PHP_METHOD(swoole_process, exec)
|
|
{
|
|
char *execfile = NULL;
|
|
zend_size_t execfile_len = 0;
|
|
zval *args;
|
|
|
|
if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "sa", &execfile, &execfile_len, &args) == FAILURE)
|
|
{
|
|
RETURN_FALSE;
|
|
}
|
|
|
|
if (execfile_len < 1)
|
|
{
|
|
swoole_php_fatal_error(E_WARNING, "exec file name is empty.");
|
|
RETURN_FALSE;
|
|
}
|
|
|
|
int exec_argc = php_swoole_array_length(args);
|
|
char **exec_args = emalloc(sizeof(char*) * (exec_argc + 2));
|
|
|
|
zval *value = NULL;
|
|
exec_args[0] = sw_strdup(execfile);
|
|
int i = 1;
|
|
|
|
SW_HASHTABLE_FOREACH_START(Z_ARRVAL_P(args), value)
|
|
convert_to_string(value);
|
|
sw_zval_add_ref(&value);
|
|
exec_args[i] = Z_STRVAL_P(value);
|
|
i++;
|
|
SW_HASHTABLE_FOREACH_END();
|
|
exec_args[i] = NULL;
|
|
|
|
if (execv(execfile, exec_args) < 0)
|
|
{
|
|
swoole_php_fatal_error(E_WARNING, "execv(%s) failed. Error: %s[%d]", execfile, strerror(errno), errno);
|
|
RETURN_FALSE;
|
|
}
|
|
else
|
|
{
|
|
RETURN_TRUE;
|
|
}
|
|
}
|
|
|
|
static PHP_METHOD(swoole_process, daemon)
|
|
{
|
|
zend_bool nochdir = 1;
|
|
zend_bool noclose = 1;
|
|
|
|
if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "|bb", &nochdir, &noclose) == FAILURE)
|
|
{
|
|
RETURN_FALSE;
|
|
}
|
|
RETURN_BOOL(daemon(nochdir, noclose) == 0);
|
|
}
|
|
|
|
#ifdef HAVE_CPU_AFFINITY
|
|
static PHP_METHOD(swoole_process, setaffinity)
|
|
{
|
|
zval *array;
|
|
if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "a", &array) == FAILURE)
|
|
{
|
|
RETURN_FALSE;
|
|
}
|
|
if (Z_ARRVAL_P(array)->nNumOfElements == 0)
|
|
{
|
|
RETURN_FALSE;
|
|
}
|
|
if (Z_ARRVAL_P(array)->nNumOfElements > SW_CPU_NUM)
|
|
{
|
|
swoole_php_fatal_error(E_WARNING, "More than the number of CPU");
|
|
RETURN_FALSE;
|
|
}
|
|
|
|
zval *value = NULL;
|
|
cpu_set_t cpu_set;
|
|
CPU_ZERO(&cpu_set);
|
|
|
|
SW_HASHTABLE_FOREACH_START(Z_ARRVAL_P(array), value)
|
|
convert_to_long(value);
|
|
if (Z_LVAL_P(value) >= SW_CPU_NUM)
|
|
{
|
|
swoole_php_fatal_error(E_WARNING, "invalid cpu id [%d]", (int) Z_LVAL_P(value));
|
|
RETURN_FALSE;
|
|
}
|
|
CPU_SET(Z_LVAL_P(value), &cpu_set);
|
|
SW_HASHTABLE_FOREACH_END();
|
|
|
|
#ifdef __FreeBSD__
|
|
if (cpuset_setaffinity(CPU_LEVEL_WHICH, CPU_WHICH_PID, -1,
|
|
sizeof(cpu_set), &cpu_set) < 0)
|
|
#else
|
|
if (sched_setaffinity(getpid(), sizeof(cpu_set), &cpu_set) < 0)
|
|
#endif
|
|
{
|
|
swoole_php_sys_error(E_WARNING, "sched_setaffinity() failed.");
|
|
RETURN_FALSE;
|
|
}
|
|
RETURN_TRUE;
|
|
}
|
|
#endif
|
|
|
|
static PHP_METHOD(swoole_process, exit)
|
|
{
|
|
long ret_code = 0;
|
|
|
|
if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "|l", &ret_code) == FAILURE)
|
|
{
|
|
RETURN_FALSE;
|
|
}
|
|
|
|
swWorker *process = swoole_get_object(getThis());
|
|
|
|
if (getpid() != process->pid)
|
|
{
|
|
swoole_php_fatal_error(E_WARNING, "not current process.");
|
|
RETURN_FALSE;
|
|
}
|
|
|
|
if (ret_code < 0 || ret_code > 255)
|
|
{
|
|
swoole_php_fatal_error(E_WARNING, "exit ret_code range is [>0 and <255] ");
|
|
ret_code = 1;
|
|
}
|
|
|
|
close(process->pipe);
|
|
|
|
SwooleG.running = 0;
|
|
|
|
if (ret_code == 0)
|
|
{
|
|
zend_bailout();
|
|
}
|
|
else
|
|
{
|
|
exit(ret_code);
|
|
}
|
|
}
|
|
|
|
static PHP_METHOD(swoole_process, close)
|
|
{
|
|
long which = 0;
|
|
if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "|l", &which) == FAILURE)
|
|
{
|
|
RETURN_FALSE;
|
|
}
|
|
|
|
swWorker *process = swoole_get_object(getThis());
|
|
if (process->pipe == 0)
|
|
{
|
|
swoole_php_fatal_error(E_WARNING, "no pipe, can not close the pipe.");
|
|
RETURN_FALSE;
|
|
}
|
|
|
|
int ret;
|
|
if (which == SW_PIPE_CLOSE_READ)
|
|
{
|
|
ret = shutdown(process->pipe, SHUT_RD);
|
|
}
|
|
else if (which == SW_PIPE_CLOSE_WRITE)
|
|
{
|
|
ret = shutdown(process->pipe, SHUT_WR);
|
|
}
|
|
else
|
|
{
|
|
ret = swPipeUnsock_close_ext(process->pipe_object, which);
|
|
}
|
|
if (ret < 0)
|
|
{
|
|
swoole_php_fatal_error(E_WARNING, "close() failed. Error: %s[%d]", strerror(errno), errno);
|
|
RETURN_FALSE;
|
|
}
|
|
if (which == 0)
|
|
{
|
|
process->pipe = 0;
|
|
efree(process->pipe_object);
|
|
process->pipe_object = NULL;
|
|
}
|
|
RETURN_TRUE;
|
|
}
|
|
|
|
static PHP_METHOD(swoole_process, setTimeout)
|
|
{
|
|
double seconds;
|
|
if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "d", &seconds) == FAILURE)
|
|
{
|
|
RETURN_FALSE;
|
|
}
|
|
|
|
swWorker *process = swoole_get_object(getThis());
|
|
if (process->pipe == 0)
|
|
{
|
|
swoole_php_fatal_error(E_WARNING, "no pipe, can not setTimeout the pipe.");
|
|
RETURN_FALSE;
|
|
}
|
|
SW_CHECK_RETURN(swSocket_set_timeout(process->pipe, seconds));
|
|
}
|
|
|
|
static PHP_METHOD(swoole_process, setBlocking)
|
|
{
|
|
zend_bool blocking;
|
|
if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "b", &blocking) == FAILURE)
|
|
{
|
|
RETURN_FALSE;
|
|
}
|
|
|
|
swWorker *process = swoole_get_object(getThis());
|
|
if (process->pipe == 0)
|
|
{
|
|
swoole_php_fatal_error(E_WARNING, "no pipe, can not setBlocking the pipe.");
|
|
RETURN_FALSE;
|
|
}
|
|
if (blocking)
|
|
{
|
|
swSetBlock(process->pipe);
|
|
}
|
|
else
|
|
{
|
|
swSetNonBlock(process->pipe);
|
|
}
|
|
if (SwooleG.main_reactor)
|
|
{
|
|
swConnection *_socket = swReactor_get(SwooleG.main_reactor, process->pipe);
|
|
if (_socket)
|
|
{
|
|
_socket->nonblock = blocking ? 0 : 1;
|
|
}
|
|
}
|
|
}
|