/** @return bool did a child exit? */ private function cleanChildren() { $status = null; if ($exited = pcntl_wait($status, WNOHANG)) { unset($this->workerProcesses[$exited]); $this->getLogger()->info("Worker {$exited} got WNOHANG during normal operation"); return true; } return false; }
function wait() { global $fatherpid; if (posix_getpid() == $fatherpid) { tlog("begin wait"); while (($pid = pcntl_wait($stat)) > 0) { tlog("child." . $pid . ". terminated \n"); } } }
public function run() { $this->numberOfThreadsToLaunch = $this->numberOfTasks; if ($this->maxThreads == 0 || count($this->pool) <= $this->maxThreads) { $this->launchAllTasks(); } else { while ($this->numberOfRunningThreads < $this->maxThreads) { $this->launchNextTask(); } } while (1) { // echo "waiting\n"; $pid = pcntl_wait($extra); if ($pid == -1) { break; } // echo ": task done : $pid\n"; $this->finishTask($pid); if ($this->numberOfThreadsToLaunch) { $this->launchNextTask(); } } // echo "processes done ; exiting\n"; return; }
/** * Create a daemon process. * * @return DaemonHttpApplication Return self to support chaining. */ public function execute() { // Create first child. if (pcntl_fork()) { // I'm the parent // Protect against Zombie children pcntl_wait($status); exit; } // Make first child as session leader. posix_setsid(); // Create second child. $pid = pcntl_fork(); if ($pid) { // If pid not 0, means this process is parent, close it. $this->processId = $pid; $this->storeProcessId(); exit; } $this->addLog('Daemonized'); fwrite(STDOUT, "Daemon Start\n-----------------------------------------\n"); $this->registerSignalHandler(); // Declare ticks to start signal monitoring. When you declare ticks, PCNTL will monitor // incoming signals after each tick and call the relevant signal handler automatically. declare (ticks=1); while (true) { $this->doExecute(); sleep(1); } return $this; }
/** * 多进程处理任务 * @param callback $mission_func 子进程要进行的任务函数 */ public function dealMission($mission_func) { $this->_mission_func = $mission_func; for ($i = 0; $i < $this->_process_num; $i++) { $pid[] = pcntl_fork(); if ($pid[$i] == 0) { //等于0时,是子进程 $this->_func_obj->{$mission_func}($i + 1); //结束当前子进程,以防止生成僵尸进程 if (function_exists("posix_kill")) { posix_kill(getmypid(), SIGTERM); } else { system('kill -9' . getmypid()); } exit; } else { if ($pid > 0) { //大于0时,是父进程,并且pid是产生的子进程的PID //TODO 可以记录下子进程的pid,用pcntl_wait_pid()去等待程序并结束 pcntl_wait($status); } else { throw new Exception('fork fail'); } } } }
public function __construct(callable $callBack = null) { $plug = \PMVC\plug(PLUGIN); $plug->log("Monitor starting."); while (empty($plug[IS_STOP_ALL]) || count($plug[CHILDREN])) { if (!empty($plug[MY_PARENT])) { break; } // Check for exited children $pid = pcntl_wait($status, WNOHANG); if (isset($plug[CHILDREN][$pid])) { $exitCode = pcntl_wexitstatus($status); $plug->log("Child {$pid} was stopped with exit code of {$exitCode}"); if (!$plug[IS_STOP_ALL] && 1 !== $exitCode) { $callbackId = $plug[CHILDREN][$pid]; $plug['start']->restore($callbackId); } $plug->cleanPid($pid); } pcntl_signal_dispatch(); if (empty($plug[CHILDREN])) { $plug[IS_STOP_ALL] = true; break; } if ($callBack && empty($plug[IS_STOP_ALL])) { call_user_func($callBack); } // php will eat up your cpu if you don't have this usleep(50000); pcntl_signal_dispatch(); } $plug->log("Monitor was exited."); }
/** * Start the task manager * * @param AbstractTask $task Task to start * * @return void */ public function start(AbstractTask $task) { $pid = pcntl_fork(); if ($pid == -1) { throw new \Exception('[Pid:' . getmypid() . '] Could not fork process'); } elseif ($pid) { $this->_activeThreads[$pid] = true; // Reached maximum number of threads allowed if ($this->maxThreads == count($this->_activeThreads)) { // Parent Process : Checking all children have ended (to avoid zombie / defunct threads) while (!empty($this->_activeThreads)) { $endedPid = pcntl_wait($status); if (-1 == $endedPid) { $this->_activeThreads = array(); } unset($this->_activeThreads[$endedPid]); } } } else { $task->initialize(); // On success if ($task->process()) { $task->onSuccess(); } else { $task->onFailure(); } posix_kill(getmypid(), 9); } pcntl_wait($status, WNOHANG); }
public function run() { $count = 0; $socket = stream_socket_server($this->socketString, &$errno, &$errstr); if (!$socket) { throw new RuntimeException($errstr); } while (true) { while (count($this->children) < $this->maxConnections) { $count++; $pid = pcntl_fork(); if ($pid == -1) { throw new RuntimeException('Couldn\'t fork'); } elseif ($pid == 0) { $this->createChild($socket, $count); exit; } $this->children[] = $pid; } while (pcntl_wait($status, WNOHANG or WUNTRACED) > 0) { usleep(500000); } while (list($key, $val) = each($this->children)) { if (!posix_kill($val, 0)) { unset($this->children[$key]); } } $this->children = array_values($this->children); usleep(500000); } }
protected function _doTestStartAll($baseConfig, $useFactoryMethodToCreateKeeper = false) { $config = $baseConfig; $config['quantity'] = $quantity = 3; if (!$useFactoryMethodToCreateKeeper) { $keeper = new OneForOneKeeper(array(new Config($config))); } else { $keeper = \Comos\Qpm\Supervision\Supervisor::oneForOne($config)->getKeeper(); } $keeper->startAll(); $pids = array(); for ($i = 0; $i < $quantity; $i++) { $status = 0; $pids[\pcntl_wait($status)] = true; } $currentPid = \posix_getpid(); $r = \file_get_contents($this->_logFile); $lines = explode("\n", $r); $count = 0; foreach ($lines as $line) { if (trim($line)) { list($pid, $ppid) = explode(',', $line); $count++; $this->assertTrue($pids[$pid]); $this->assertEquals($currentPid, $ppid); } } $this->assertEquals($quantity, $count); }
/** * Run jobs * * Run all jobs provided by the job provider. * * Jobs are run parallel in the background. The number of jobs executed in * parallel can be specified as the second parameter. * * Returns once all jobs have been executed. * * @param JobProvider $jobs * @param int $parallel * @return void */ public function run(JobProvider $jobs, $parallel = 4) { $this->logger->startExecutor($this, $jobs); $forks = array(); $jobNr = 0; while ($jobs->hasJobs() || count($forks)) { while (count($forks) < $parallel && ($job = $jobs->getNextJob())) { $this->logger->progressJob(++$jobNr); if (($forks[] = pcntl_fork()) === 0) { // We are the newly forked child, just execute the job call_user_func($job); exit(0); } } do { // Check if the registered jobs are still alive if ($pid = pcntl_wait($status)) { // Job has finished $jobId = array_search($pid, $forks); unset($forks[$jobId]); } } while (count($forks) >= $parallel); } $this->logger->finishedExecutor(); }
/** * Signals handler function * * @param integer $signal * @final */ public final function HandleSignals($signal) { $this->Logger->debug("HandleSignals received signal {$signal}"); if ($signal == SIGUSR2) { $this->Logger->debug("Recived SIGUSR2 from one of childs"); $this->ProcessManager->PIDs = array(); $this->ProcessManager->ForkThreads(); return; } $pid = @pcntl_wait($status, WNOHANG | WUNTRACED); if ($pid > 0) { $this->Logger->debug("Application received signal {$signal} from child with PID# {$pid} (Exit code: {$status})"); foreach ((array) $this->ProcessManager->PIDs as $ipid => $ipid_info) { if ($ipid == $pid) { unset($this->ProcessManager->PIDs[$ipid]); if ($this->ProcessManager->PIDDir) { $this->Logger->debug("Delete thread PID file {$ipid}"); @unlink($this->ProcessManager->PIDDir . "/" . $ipid); } $known_child = true; break; } } if ($known_child) { $this->ProcessManager->ForkThreads(); } else { $this->Logger->debug("Signal received from unknown child."); } } }
public function start($daemon = false) { /*{{{*/ if ($daemon) { if (!$this->daemonize()) { return false; } } $this->master_process_id = posix_getpid(); $this->startServer(); $this->startAgent(); while (true) { $pid = pcntl_wait($status, WNOHANG); switch ($pid) { case $this->listen_process_id: CronLogger::err("Cron server not running[{$status}], starting ..."); $this->startServer(); CronLogger::err("Cron server restart done."); break; case $this->agent_process_id: CronLogger::err("Cron agent not running[{$status}], starting ..."); $this->startAgent(); CronLogger::err("Cron server restart done."); break; case -1: posix_kill($this->listen_process_id, 9); posix_kill($this->agent_process_id, 9); $this->startAgent(); $this->startServer(); break; } sleep(3); } }
public function go() { foreach ($this->servers as $server) { $handler = new Handler\Daemonic($server['socket'], $server['protocol'], $server['transport']); // drop privileges after opening sockets, but before entering the working loop // this will only work when the process is started by root $this->dropPrivileges($server); for ($i = 0; $i < $server['min-children']; $i++) { $this->startWorker($handler, $server['app']); } } while (true) { pcntl_signal(SIGTERM, array($this, 'sigterm'), false); pcntl_signal(SIGINT, array($this, 'sigterm'), false); pcntl_signal(SIGHUP, array($this, 'sighup'), false); $status = null; declare (ticks=1) { $old_pid = pcntl_wait($status); } if (0 === $old_pid) { echo "[no workers]\n"; return; } if (-1 === $old_pid) { continue; // signal arrived } echo "[Restarting Worker]\n"; pcntl_signal(SIGTERM, SIG_DFL); pcntl_signal(SIGINT, SIG_DFL); pcntl_signal(SIGHUP, SIG_DFL); $this->restartWorker($old_pid); } }
/** * Signals handler function * * @param integer $signal * @final */ final public function HandleSignals($signal) { //Log::Log("HandleSignals received signal {$signal}", E_NOTICE); $pid = @pcntl_wait($status, WNOHANG | WUNTRACED); if ($pid > 0) { //Log::Log("Application received signal {$signal} from child with PID# {$pid} (Exit code: {$status})", E_NOTICE); foreach((array)$this->ProcessManager->PIDs as $kk=>$vv) { if ($vv == $pid) { unset($this->ProcessManager->PIDs[$kk]); $known_child = true; break; } } if ($known_child) $this->ProcessManager->ForkThreads(); else { //Log::Log("Signal received from unknown child.", E_NOTICE); } } }
/** * Start the child processes. * * This should only be called from the command line. It should be called * as early as possible during execution. * * This will return 'child' in the child processes. In the parent process, * it will run until all the child processes exit or a TERM signal is * received. It will then return 'done'. */ public function start() { // Trap SIGTERM pcntl_signal(SIGTERM, array($this, 'handleTermSignal'), false); do { // Start child processes if ($this->procsToStart) { if ($this->forkWorkers($this->procsToStart) == 'child') { return 'child'; } $this->procsToStart = 0; } // Check child status $status = false; $deadPid = pcntl_wait($status); if ($deadPid > 0) { // Respond to child process termination unset($this->children[$deadPid]); if ($this->flags & self::RESTART_ON_ERROR) { if (pcntl_wifsignaled($status)) { // Restart if the signal was abnormal termination // Don't restart if it was deliberately killed $signal = pcntl_wtermsig($status); if (in_array($signal, self::$restartableSignals)) { echo "Worker exited with signal {$signal}, restarting\n"; $this->procsToStart++; } } elseif (pcntl_wifexited($status)) { // Restart on non-zero exit status $exitStatus = pcntl_wexitstatus($status); if ($exitStatus > 0) { echo "Worker exited with status {$exitStatus}, restarting\n"; $this->procsToStart++; } } } // Throttle restarts if ($this->procsToStart) { usleep(500000); } } // Run signal handlers if (function_exists('pcntl_signal_dispatch')) { pcntl_signal_dispatch(); } else { declare (ticks=1) { $status = $status; } } // Respond to TERM signal if ($this->termReceived) { foreach ($this->children as $childPid => $unused) { posix_kill($childPid, SIGTERM); } $this->termReceived = false; } } while (count($this->children)); pcntl_signal(SIGTERM, SIG_DFL); return 'done'; }
public function go() { $is_parent = true; foreach ($this->servers as $server) { $app = new $server[0](); foreach (array_reverse($server[1]) as $mw_name) { $mw_class = 'MFS\\AppServer\\Middleware\\' . $mw_name . '\\' . $mw_name; $app = new $mw_class($app); } $handler = new \MFS\AppServer\DaemonicHandler($server[3], $server[2], 'Socket'); for ($i = 0; $i < $server[4]; $i++) { $pid = pcntl_fork(); if ($pid == -1) { die('could not fork'); } elseif ($pid === 0) { // we are the child $is_parent = false; try { $handler->serve($app); } catch (\Exception $e) { } die; } else { // parent-process, just continue } } } if ($is_parent) { // should be called one time for each child? pcntl_wait($status); //Protect against Zombie children } }
public function start() { $pid = pcntl_fork(); if ($pid < 0) { throw new Exception('count not fork'); } elseif ($pid == 0) { //parent if (empty($this->producer)) { exit; } $cur_size = 0; while (true) { $pid = pcntl_fork(); if ($pid == -1) { die("could not fork"); } else { if ($pid) { // parent $cur_size++; if ($cur_size >= $this->work_count) { $sunPid = pcntl_wait($status); $cur_size--; } } else { // worker exit; } } } } else { //sun parent } }
public function work() { //echo "Worker started with pid $this->pid...\n"; if ($this->daemonize) { $pid = pcntl_fork(); if ($pid == 0) { $this->pid = getmypid(); $this->isDaemon = true; pcntl_signal(SIGTERM, function () { //echo "Daemon process caught SIGTERM\n"; if ($this->childPids) { foreach (array_keys($this->childPids) as $pid) { //echo "Sending SIGKILL to child $pid\n"; posix_kill($pid, SIGKILL); } } //echo "Daemon process $this->pid exiting\n"; unlink($this->pidFile); exit; }); } else { //echo "Successfully daemonized. PID $pid written to $this->pidFile\n"; file_put_contents($this->pidFile, $pid); exit; } } $this->childPids = $pids = []; if ($this->fork) { RE_FORK: for ($c = count($this->childPids); $c < $this->fork; $c++) { $pid = pcntl_fork(); if ($pid > 0) { // "Forked child with PID $pid\n"; $this->childPids[$pid] = time(); } else { $this->pid = getmypid(); $this->isChild = true; $this->isDaemon = false; goto DO_WORK; } } while (count($this->childPids)) { $status = 0; $exitedPid = pcntl_wait($status); unset($this->childPids[$exitedPid]); if ($this->refork) { goto RE_FORK; } } goto END_FORK; } DO_WORK: $func = $this->callback; $func(); exit; END_FORK: exit; }
function check_wait($pid) { global $pids, $procs; array_push($pids, $pid); if (count($pids) > $procs) { $pid = pcntl_wait($status); array_remove($pid, $pids); } }
public function execute() { $server = TTMServer::primary(); if ($server instanceof FakeTTMServer) { $this->error("Translation memory is not configured properly", 1); } $dbw = $server->getDB(DB_MASTER); $this->statusLine('Deleting sources.. ', 1); $dbw->delete('translate_tms', '*', __METHOD__); $this->output('translations.. ', 1); $dbw->delete('translate_tmt', '*', __METHOD__); $this->output('fulltext.. ', 1); $dbw->delete('translate_tmf', '*', __METHOD__); $table = $dbw->tableName('translate_tmf'); $dbw->query("DROP INDEX tmf_text ON {$table}"); $this->output('done!', 1); $this->statusLine('Loading groups... ', 2); $groups = MessageGroups::singleton()->getGroups(); $this->output('done!', 2); $threads = $this->getOption('threads', 1); $pids = array(); foreach ($groups as $id => $group) { if ($group->isMeta()) { continue; } // Fork to avoid unbounded memory usage growth $pid = pcntl_fork(); if ($pid === 0) { // Child, reseed because there is no bug in PHP: // http://bugs.php.net/bug.php?id=42465 mt_srand(getmypid()); $this->exportGroup($group, $threads > 1); exit; } elseif ($pid === -1) { // Fork failed do it serialized $this->exportGroup($group); } else { $this->statusLine("Forked thread {$pid} to handle {$id}\n"); $pids[$pid] = true; // If we hit the thread limit, wait for any child to finish. if (count($pids) >= $threads) { $status = 0; $pid = pcntl_wait($status); unset($pids[$pid]); } } } // Return control after all threads have finished. foreach (array_keys($pids) as $pid) { $status = 0; pcntl_waitpid($pid, $status); } $this->statusLine('Adding fulltext index...', 9); $table = $dbw->tableName('translate_tmf'); $dbw->query("CREATE FULLTEXT INDEX tmf_text ON {$table} (tmf_text)"); $this->output(' done!', 9); }
/** * @throws \Exception when child process ends with an Exception * * @return mixed */ protected function handleParentProcess() { pcntl_wait($status); $result = $this->ipc->get(); if ($result instanceof ExceptionDataHolder) { throw new IsolatedCallbackExecutionException($result); } return $result; }
public function testProcessFork() { $child = Process::fork(function () { exit; }); $this->assertTrue($child instanceof ChildProcess); $st = 0; $cpid = pcntl_wait($st); $this->assertEquals($cpid, $child->getPid()); }
/** * @param Thread $thread */ public function add($job, $delay = 0) { if (count($this->threads) >= $this->size) { unset($this->threads[pcntl_wait($status)]); } $this->delay($delay); $thread = new Thread($job); $thread->start(); $this->threads[$thread->getPid()] = $thread; }
public function waitForNext($hang = true) { if (-1 === ($pid = pcntl_wait($status, ($hang ? WNOHANG : 0) | WUNTRACED))) { throw new ProcessControlException('Error while waiting for next fork to exit'); } if (isset($this->forks[$pid])) { $this->forks[$pid]->processWaitStatus($status); return $this->forks[$pid]; } }
/** * */ private function signalHandlersParent() { $root = $this; pcntl_signal(SIGCHLD, function () use($root) { while (($pid = pcntl_wait($status, WNOHANG)) > 0) { array_diff($root->children, [$pid]); } }); pcntl_signal_dispatch(); }
/** * @return $this */ public function wait_children() { while ($this->_current_pids) { $pid = pcntl_wait($status); if ($pid > 0) { unset($this->_current_pids[$pid]); $this->_current_process_count--; } } return $this; }
/** * @param \Extended\Process\Runnable $child * A runnable process to fork */ public function fork(Runnable $child) { $this->pid = pcntl_fork(); if ($this->pid == -1) { $error = pcntl_strerror(pcntl_get_last_error()); throw new ProcessException('Unable to fork the process: ' . $error); } elseif ($this->pid) { return pcntl_wait($this->pid); } self::$buffer->append($child->run()); }
public function reapChild() { // Check if any child process has terminated, // and if so remove it from memory $pid = pcntl_wait($status, WNOHANG); if ($pid < 0) { throw new \Exception("Out of memory"); } elseif ($pid > 0) { unset($this->processes[$pid]); } }
/** * master. * * to start and mantaince child Processes. * * @param integer $maxChildren */ function master($maxChildren) { for ($i = 0; $i < $maxChildren; $i++) { startWorker(); } // 维持子进程数量 while (true) { $status = null; pcntl_wait($status); startWorker(); } }
public function mainLoop() { $this->loadJobs(); $this->poolPid = posix_getpid(); $this->initSignalHandler(); while (true) { $this->logger->info("MainLoop"); if (!$this->terminating) { foreach ($this->jobs as $job => $settings) { $startWorker = false; if (count($settings['pids']) < $this->processesPerJob) { $startWorker = true; $this->logger->error("No process for job: {$job}. Starting..."); } else { foreach ($settings['pids'] as $pid) { if (!posix_kill($pid, 0)) { $startWorker = true; $this->logger->error("Process for job: {$job}. Not running. Starting..."); break; } } } if ($startWorker) { $this->forkChild($job); } } } $pid = pcntl_wait($status, WNOHANG); if ($pid > 0) { $this->logger->info(sprintf("wait() from child %s. Status: %d", $pid, $status)); foreach ($this->jobs as $job => $settings) { foreach ($settings['pids'] as $k => $wpid) { if ($wpid && $wpid == $pid) { $this->logger->warn("{$job} client worker died"); unset($settings['pids'][$k]); $this->jobs[$job] = $settings; break; } } } } if ($this->terminating) { $pids = 0; foreach ($this->jobs as $settings) { $pids += count($settings['pids']); } if ($pids == 0) { exit; } } sleep(10); } }