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;
 }