public function start() { if (!ProcessContainer::dup2_available()) { $cmd = "{$this->process_path} {$this->process_params}"; if ($this->is_php) { $cmd = "{$this->php_path} {$cmd}"; } $descriptorspec = array(0 => array("pipe", "r"), 1 => array("pipe", "w"), 2 => array("pipe", "w")); $process = proc_open($cmd, $descriptorspec, $pipes, dirname($this->process_path)); if (!is_resource($process)) { return FALSE; } $status = proc_get_status($process); $this->process_pid = $status['pid']; // 关闭输入 fclose($pipes[0]); $this->process_stdout = $pipes[1]; $this->process_stderr = $pipes[2]; $this->process = $process; return TRUE; } else { $pipes = array(1 => $this->pipe_open('w+'), 2 => $this->pipe_open('w+')); // 利用 dup2 重定向管道 $pid = pcntl_fork(); if ($pid == -1) { return FALSE; } else { if ($pid) { $this->process_pid = $pid; $this->process_stdout = $pipes[1]; $this->process_stderr = $pipes[2]; return TRUE; } } // 子进程 if ($this->child_init_handler) { call_user_func($this->child_init_handler); } $params = explode(' ', $this->process_params); if ($this->is_php) { $path = $this->php_path; array_unshift($params, $this->process_path); } else { $path = $this->process_path; } chdir(dirname($this->process_path)); //fildes_dup2(fildes_fileno($pipes[0]), fildes_fileno(STDIN)); fildes_dup2(fildes_fileno($pipes[1]), fildes_fileno(STDOUT)); fildes_dup2(fildes_fileno($pipes[2]), fildes_fileno(STDERR)); pcntl_exec($path, $params); exit; } }
public function command_start($params) { $jobname = $params['jobname']; $setting = $this->config->get($jobname); $command = $setting['command']; $cmdparams = $setting['params']; $buffersize = $setting['buffersize']; $writelog = $setting['writelog']; $pid = $this->shm_process_getpid($jobname); if ($pid) { // 检查进程是否正在运行 if ($this->process_exists($pid)) { $this->client_return('FAILED'); $this->server_echo("FAILED. (process \"{$jobname}\"({$pid}) has already exist.)"); return FALSE; } else { // 检查进程是否回收结束 if ($this->shm_process_getpid($jobname)) { $this->client_return('FAILED'); $this->server_echo("FAILED. (process \"{$jobname}\"({$pid}) is still exiting.)"); return FALSE; } } } if (!file_exists($command)) { // 文件不存在 $this->client_return('FAILED'); $this->server_echo("FAILED. (command path \"{$command}\" does not exist.)"); return FALSE; } // 新建孙子进程 $pid = pcntl_fork(); if ($pid == -1) { $this->client_return('FAILED'); $this->server_echo('pcntl_fork() failed.'); return FALSE; } else { if ($pid) { pcntl_waitpid($pid, $status); return TRUE; } } // 子进程 $t_pid = pcntl_fork(); if ($t_pid == -1) { $this->client_return('FAILED'); $this->server_echo('pcntl_fork() failed.'); return FALSE; } else { if ($t_pid) { exit; } } // 孙子进程 $this->jobname = $jobname; $this->writelog = $writelog; $this->buffersize = $buffersize; $newline = !isset($params['newline']) ? TRUE : $params['newline']; if (ProcessContainer::dup2_available()) { // 使用 dup2 手工配置管道定向 } else { // 需要在proc_open前关闭socket,否则会被proc_open进程继承,导致socket端口被占用 $this->client_return('OK'); $this->server_echo('OK', $newline); $this->socket_close(); } $process = new ProcessContainer($command, $cmdparams, TRUE); $process->register_output_handler(array($this, 'process_output_handler')); $process->register_error_handler(array($this, 'process_error_handler')); $process->register_exit_handler(array($this, 'process_exit_handler')); $process->register_child_init_handler(array($this, 'process_child_init_handler')); if (!$process->start()) { if (ProcessContainer::dup2_available()) { $this->client_return('FAILED'); $this->server_echo('FAILED. (output_buffer init failed.)'); $this->socket_close(); } return FALSE; } // 进程配置写入共享内存 $process_pid = $process->get_pid(); $this->shm_process_updatepid($jobname, $process_pid); // 创建共享变量用于输出缓冲 $output_buffer = array(); if (!$this->shm->put_var('ob_' . $jobname, $output_buffer, TRUE)) { if (ProcessContainer::dup2_available()) { $this->client_return('FAILED'); $this->server_echo('FAILED. (output_buffer init failed.)'); $this->socket_close(); } return FALSE; } if (ProcessContainer::dup2_available()) { $this->client_return('OK'); $this->server_echo('OK', $newline); $this->socket_close(); } $process->loop_read(); exit; }