function watchdog() { $childpid = 0; $signals = array(SIGINT, SIGCHLD); pcntl_sigprocmask(SIG_BLOCK, $signals); do { printf("%s watchdog launching daemon...\n", @date('r')); if (0 === ($childpid = pcntl_fork())) { unreliable_daemon(); exit(1); } $signal = pcntl_sigwaitinfo($signals, $info); } while ($signal != SIGINT); echo "watchdog got SIGINT. killing child...\n"; posix_kill($childpid, SIGKILL); echo "watchdog exiting...\n"; }
/** * 运行守护进程,监控有变化的日志文件。 * * @see ZtChart_Model_Monitor_Abstract::daemon() */ public function run() { if (0 == ($pid = pcntl_fork())) { // 子进程负责处理当前日志 try { $this->tail($this->_console->getLogPaths()); } catch (ZtChart_Model_Monitor_Exception $e) { $this->_logger->err($e->getMessage()); exit(1); } } else { if (0 < $pid) { pcntl_setpriority(-1); // 父进程负责把子进产生的数据写入数据库 if (pcntl_sigprocmask(SIG_BLOCK, array(SIGCHLD, SIGALRM, SIGINT, SIGTERM))) { $interval = 10; // 10秒写一次 pcntl_alarm($interval); while ($signo = pcntl_sigwaitinfo(array(SIGCHLD, SIGALRM, SIGINT, SIGTERM))) { if (SIGALRM == $signo) { pcntl_alarm($interval); } try { $this->extract($interval); } catch (ZtChart_Model_Monitor_Exception $e) { posix_kill($pid, 9); exit(1); } if (SIGCHLD == $signo || SIGINT == $signo || SIGTERM == $signo) { break; } } } } } exit(0); }
/** * Sig Wait Info * * @param array $set Array of signals to wait for. * @param array $siginfo The siginfo parameter is set to an array containing informations about the signal. * * @return int On success, pcntl_sigwaitinfo() returns a signal number. */ public function sigWaitInfo(array $set, array $siginfo) { return pcntl_sigwaitinfo($set, $siginfo); }
/** * Приостанавливает работу демона * * @return void */ public function __sleep() { $this->iNumberOfWorkers = 0; foreach ($this->aInstances as $iPID => $sValue) { pcntl_waitpid($iPID, $iStatus); if ($iStatus === 0) { $this->aStopped[$this->aInstances[$iPID]] = $this->aInstances[$iPID]; unset($this->aInstances[$iPID]); } } pcntl_sigwaitinfo(array(SIGCONT), $aInfo); $this->iNumberOfWorkers = count($this->aWorkers); }
echo "Got signal from child1\n"; $firstChildIsFree = true; } elseif ($siginfo['signo'] == SIGUSR2) { echo "Got signal from child2\n"; $secondChildIsFree = true; } } sleep(1); } } else { pcntl_setpriority(5); echo "Child2 waiting for SIGHUP\n"; while (true) { pcntl_sigwaitinfo(array(SIGHUP)); echo "Child2 has been activated\n"; sleep(10); echo "Child2 is now free, notify parent #{$parentPid}\n"; posix_kill($parentPid, SIGUSR2); } } } else { pcntl_setpriority(5); echo "Child1 waiting for SIGHUP\n"; while (true) { pcntl_sigwaitinfo(array(SIGHUP)); echo "Child1 has been activated\n"; sleep(10); echo "Child1 is now free, notify parent #{$parentPid}\n"; posix_kill($parentPid, SIGUSR1); } }
echo "signo === SIGCHLD\n"; var_dump($siginfo['signo'] === SIGCHLD); echo "signo === uid\n"; var_dump($siginfo['uid'] === posix_getuid()); echo "signo === pid\n"; var_dump($siginfo['pid'] === $pid); pcntl_waitpid($pid, $status); set_error_handler(function ($errno, $errstr) { echo "Error triggered\n"; }, E_WARNING); echo "sigprocmask with invalid arguments\n"; /* Valgrind expectedly complains about this: * "sigprocmask: unknown 'how' field 2147483647" * Skip */ if (getenv("USE_ZEND_ALLOC") !== '0') { var_dump(pcntl_sigprocmask(PHP_INT_MAX, array(SIGTERM))); } else { echo "Error triggered\n"; echo "bool(false)\n"; } var_dump(pcntl_sigprocmask(SIG_SETMASK, array(0))); echo "sigwaitinfo with invalid arguments\n"; var_dump(pcntl_sigwaitinfo(array(0))); echo "sigtimedwait with invalid arguments\n"; var_dump(pcntl_sigtimedwait(array(SIGTERM), $signo, PHP_INT_MAX, PHP_INT_MAX)); } else { $siginfo = NULL; pcntl_sigtimedwait(array(SIGINT), $siginfo, 3600, 0); exit; } }