Ejemplo n.º 1
0
 /**
  * @param ServerEvent $event
  */
 public function bindPnctlEvent(ServerEvent $event)
 {
     if (!extension_loaded('pcntl')) {
         return;
     }
     $loop = $event->getEventLoop();
     $server = $event->getServer();
     $pnctlEmitter = new PnctlEmitter($loop);
     $pnctlEmitter->on(SIGTERM, function () use($server, $loop) {
         $server->emit('end');
         $server->shutdown();
         $loop->stop();
         $this->logger->notice('Server stopped !');
     });
     $pnctlEmitter->on(SIGINT, function () use($server, $loop) {
         $this->logger->notice('Press CTLR+C again to stop the server');
         if (SIGINT === pcntl_sigtimedwait([SIGINT], $siginfo, 5)) {
             $this->logger->notice('Stopping server ...');
             $server->emit('end');
             $server->shutdown();
             foreach ($this->periodicRegistry->getPeriodics() as $periodic) {
                 if ($periodic instanceof TimerInterface && $loop->isTimerActive($periodic)) {
                     $loop->cancelTimer($periodic);
                 }
             }
             $loop->stop();
             $this->logger->notice('Server stopped !');
         } else {
             $this->logger->notice('CTLR+C not pressed, continue to run normally');
         }
     });
 }
Ejemplo n.º 2
0
 protected function serverLoop()
 {
     while ($this->_listenLoop) {
         if (($client = @socket_accept($this->sockServer)) === false) {
             $info = array();
             if (pcntl_sigtimedwait(array(SIGUSR1), $info, 1) > 0) {
                 if ($info['signo'] == SIGUSR1) {
                     $this->handleProcess();
                 }
             }
             continue;
         }
         $socketClient = new SocketClientBroadcast($client, $this);
         if (is_array($this->connectionHandler)) {
             $object = $this->connectionHandler[0];
             $method = $this->connectionHandler[1];
             $childPid = $object->{$method}($socketClient);
         } else {
             $function = $this->connectionHandler;
             $childPid = $function($socketClient);
         }
         if (!$childPid) {
             // force child process to exit from loop
             return;
         }
         $this->connections[$childPid] = $socketClient;
     }
 }
 /**
  * @param ServerEvent $event
  */
 public function bindPnctlEvent(ServerEvent $event)
 {
     if (!extension_loaded('pcntl')) {
         return;
     }
     $loop = $event->getEventLoop();
     $server = $event->getServer();
     $pnctlEmitter = new PnctlEmitter($loop);
     $pnctlEmitter->on(SIGTERM, function () use($server, $loop) {
         $this->closure($server, $loop);
     });
     $pnctlEmitter->on(SIGINT, function () use($pnctlEmitter) {
         $this->logger->notice('Press CTLR+C again to stop the server');
         if (SIGINT === pcntl_sigtimedwait([SIGINT], $siginfo, 5)) {
             $pnctlEmitter->emit(SIGTERM);
         } else {
             $this->logger->notice('CTLR+C not pressed, continue to run normally');
         }
     });
 }
Ejemplo n.º 4
0
 /**
  * 次のトリガまで待機
  *
  * @param int $sec
  */
 public function wait($sec)
 {
     $limit = microtime(true) + $sec;
     for (;;) {
         $sec = (int) ($limit - microtime(true) + 1);
         if ($sec < 1) {
             return true;
         }
         if ($signo = pcntl_sigtimedwait($this->_sigset, $info, $sec)) {
             switch ($signo) {
                 case SIGTERM:
                 case SIGINT:
                 case SIGHUP:
                     return false;
                 case SIGUSR2:
                     return true;
             }
         }
     }
 }
Ejemplo n.º 5
0
function sigSleep($secs = 10)
{
    // Uses pcntl_sigtimedwait instead of sleep, so we can be sure we catch sighup
    // signals from the OS. This may seem counterproductive, as sleep(3) will wake
    // on *any* signal, but php does all sorts of crazy things to make this
    // unreliable.
    if ($secs < 5) {
        $secs = 5;
    }
    pcntl_sigtimedwait(array(SIGHUP), $sig, $secs);
    if ($sig['signo'] === SIGHUP) {
        sigHupHandler(1);
    }
}
Ejemplo n.º 6
0
 /**
  * Sig Timed Wait
  *
  * @param array $set         Array of signals to wait for.
  * @param array $sigInfo     The siginfo is set to an array containing informations about the signal. See pcntl_sigwaitinfo().
  * @param int   $seconds     Timeout in seconds.
  * @param int   $nanoseconds Timeout in nanoseconds.
  *
  * @return int  On success, pcntl_sigtimedwait() returns a signal number.
  */
 public function sigTimedWait(array $set, array $sigInfo, $seconds = 0, $nanoseconds = 0)
 {
     return pcntl_sigtimedwait($set, $sigInfo, $seconds, $nanoseconds);
 }
Ejemplo n.º 7
0
 /**
  * Waits for signals, with a timeout
  * @param int Seconds
  * @param int Nanoseconds
  * @return void
  */
 protected function sigwait($sec = 0, $nano = 1)
 {
     $siginfo = NULL;
     $signo = pcntl_sigtimedwait(self::$signalsno, $siginfo, $sec, $nano);
     if (is_bool($signo)) {
         return $signo;
     }
     if ($signo > 0) {
         $this->sighandler($signo);
         return TRUE;
     }
     return FALSE;
 }
Ejemplo n.º 8
0
 /**
  * Wait some time for signal.
  * If signal received, it will be correclty handled.
  */
 public function wait()
 {
     $siginfo = [];
     $signal = pcntl_sigtimedwait(array_keys($this->handlers), $siginfo, 0, pow(10, 9) * 0.01);
     $this->handle($signal);
 }
Ejemplo n.º 9
0
 /**
  * Waits for signals, with a timeout
  * @param int Seconds
  * @param int Nanoseconds
  * @return boolean Success
  */
 protected function sigwait($sec = 0, $nano = 300000000.0)
 {
     $siginfo = null;
     if (!function_exists('pcntl_sigtimedwait')) {
         $signo = $this->sigtimedwait(array_keys(static::$signals), $siginfo, $sec, $nano);
     } else {
         $signo = @\pcntl_sigtimedwait(array_keys(static::$signals), $siginfo, $sec, $nano);
     }
     if (is_bool($signo)) {
         return $signo;
     }
     if ($signo > 0) {
         $this->sighandler($signo);
         return true;
     }
     return false;
 }
Ejemplo n.º 10
0
                 posix_kill($child1, SIGHUP);
                 $firstChildIsFree = false;
                 $got2execution = true;
             } elseif ($secondChildIsFree) {
                 posix_kill($child2, SIGHUP);
                 $secondChildIsFree = false;
                 $got2execution = true;
             }
             if ($got2execution) {
                 file_put_contents('db.txt', '');
             } else {
                 echo "No free workers\n";
             }
         }
         //Check signals from child processes
         if (pcntl_sigtimedwait(array(SIGUSR1, SIGUSR2), $siginfo, 0, 1) != -1) {
             if ($siginfo['signo'] == SIGUSR1) {
                 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));
Ejemplo n.º 11
0
        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;
    }
}
Ejemplo n.º 12
0
 public function sigwait($millisec = 10)
 {
     $siginfo = array();
     $sec = $millisec * 0.001 > 0 ? $millisec * 0.001 : 0;
     $nanosec = $millisec * 1000000.0 < 1000000000.0 ? $millisec * 1000000.0 : 0;
     $signo = pcntl_sigtimedwait(Thread::$signalsno, $siginfo, $sec, $nanosec);
     if (is_bool($signo)) {
         return $signo;
     }
     if ($signo > 0) {
         $this->sighandler($signo);
         return TRUE;
     }
     return FALSE;
 }
Ejemplo n.º 13
0
 /**
  * Dispatcher responsible for the thread intercommunication and communication with their parent process.
  * @param bool $useBlocking On true blocks the internal execution until communication data is available for the current dispatched thread otherwise it skips it.
  * @return void
  */
 public static function dispatch($useBlocking = false)
 {
     // {{{
     $NULL = null;
     // prevent any threads to run their own dispatchers
     if (self::$instancesCreatedEverAArr === null || count(self::$instancesCreatedEverAArr) == 0) {
         return;
     }
     // for checking SIGCHLD child signals informing that a particular "thread" was paused
     $sigSet = array(SIGCHLD);
     $sigInfo = array();
     // begin the dispatching process
     foreach (self::$instancesCreatedEverAArr as $instId => &$inst) {
         // loop through ALL active instances of GPhpCriticalSection
         foreach ($inst->mastersThreadSpecificData as $threadId => &$specificDataAArr) {
             // loop though the threads per each instance in GPhpCriticalSection
             // checking for child signals informing that a thread has exited or was paused
             while (pcntl_sigtimedwait($sigSet, $sigInfo) == SIGCHLD) {
                 if ($sigInfo['code'] >= 0 && $sigInfo['code'] <= 3) {
                     // child has exited
                     self::$threadsForRemovalAArr[$sigInfo['pid']] = $sigInfo['pid'];
                 } else {
                     if ($sigInfo['code'] == 5) {
                         // stopped (paused) child
                         $specificDataAArr['dispatchPriority'] = 0;
                         // make the dispatch priority lowest
                     } else {
                         if ($sigInfo['code'] == 6) {
                             // resume stopped (paused) child
                             $specificDataAArr['dispatchPriority'] = 1;
                             // increase little bit the priority since we expect interaction with the critical section
                         }
                     }
                 }
             }
             $inst->intercomInterlocutorPid =& $specificDataAArr['intercomInterlocutorPid'];
             if (isset(self::$threadsForRemovalAArr[$inst->intercomInterlocutorPid])) {
                 unset($inst->mastersThreadSpecificData[$threadId]);
                 continue;
             }
             $inst->intercomRead =& $specificDataAArr['intercomRead'];
             $inst->intercomWrite =& $specificDataAArr['intercomWrite'];
             $inst->dispatchPriority =& $specificDataAArr['dispatchPriority'];
             if (!$useBlocking && !$inst->intercomRead->isReceivingDataAvailable()) {
                 $inst->dispatchPriority = 0;
                 if ($inst->isIntercomBroken()) {
                     unset($inst->mastersThreadSpecificData[$threadId]);
                     // remove the thread from the dispatching list as soon as we can
                 }
                 continue;
             }
             self::dataDispatch($inst, $threadId);
             $mostPrioritizedThreadId = NULL;
             if ($inst->dispatchPriority !== 2) {
                 foreach ($inst->mastersThreadSpecificData as $threadId2 => &$specificDataAArr2) {
                     if ($specificDataAArr2['dispatchPriority'] === 2) {
                         $mostPrioritizedThreadId = $threadId2;
                     }
                 }
             } else {
                 $mostPrioritizedThreadId = $threadId;
             }
             if ($mostPrioritizedThreadId !== NULL && $mostPrioritizedThreadId !== $threadId) {
                 $inst->intercomInterlocutorPid =& $inst->mastersThreadSpecificData[$mostPrioritizedThreadId]['intercomInterlocutorPid'];
                 $inst->intercomRead =& $inst->mastersThreadSpecificData[$mostPrioritizedThreadId]['intercomRead'];
                 $inst->intercomWrite =& $inst->mastersThreadSpecificData[$mostPrioritizedThreadId]['intercomWrite'];
                 $inst->dispatchPriority =& $inst->mastersThreadSpecificData[$mostPrioritizedThreadId]['dispatchPriority'];
                 if (!$useBlocking && !$inst->intercomRead->isReceivingDataAvailable()) {
                     $inst->dispatchPriority = 0;
                     if ($inst->isIntercomBroken()) {
                         unset($inst->mastersThreadSpecificData[$mostPrioritizedThreadId]);
                         // remove the thread from the dispatching list as soon as we can
                     }
                     continue;
                 }
                 self::dataDispatch($inst, $threadId);
             }
         }
         // rearrange the threads in the current critical section
         // instance using their new dispatch priority number
         // if a lock has already occurred that thread will have the
         // highest priority
         uksort($inst->mastersThreadSpecificData, function ($a, $b) use($inst) {
             if ($inst->mastersThreadSpecificData[$a]['intercomInterlocutorPid'] == $inst->ownerPid) {
                 return -1;
             }
             if ($inst->mastersThreadSpecificData[$b]['intercomInterlocutorPid'] == $inst->ownerPid) {
                 return 1;
             }
             return $inst->mastersThreadSpecificData[$a]['dispatchPriority'] < $inst->mastersThreadSpecificData[$b]['dispatchPriority'];
         });
         $inst->intercomInterlocutorPid =& $NULL;
         $inst->intercomRead =& $NULL;
         $inst->intercomWrite =& $NULL;
         $inst->dispatchPriority =& $NULL;
     }
     // make sure that no terminated threads are left in the internal thread
     // dispatching list that all instances of GPhpThreadCriticalSection have
     foreach (self::$instancesCreatedEverAArr as $instId => &$inst) {
         foreach ($inst->mastersThreadSpecificData as $threadId => &$specificDataAArr) {
             $inst->intercomInterlocutorPid =& $specificDataAArr['intercomInterlocutorPid'];
             if (isset(self::$threadsForRemovalAArr[$inst->intercomInterlocutorPid])) {
                 unset($inst->mastersThreadSpecificData[$threadId]);
             }
         }
         $inst->intercomInterlocutorPid =& $NULL;
     }
     self::$threadsForRemovalAArr = array();
     // rearrange the active instances of GPhpThreadCriticalSection in the
     // following priority order (the higher the number the bigger the priority):
     // 2. the instance with the thread that has currently locked the critical section
     // 1. instances with threads with the highest dispatch priority
     // 0. instances with the most threads inside
     $instCrtdEver =& self::$instancesCreatedEverAArr;
     uksort($instCrtdEver, function ($a, $b) use($instCrtdEver) {
         // the locker thread is with highest priority
         if ($instCrtdEver[$a]->mastersThreadSpecificData['intercomInterlocutorPid'] == $instCrtdEver[$a]->ownerPid) {
             return -1;
         }
         if ($instCrtdEver[$b]->mastersThreadSpecificData['intercomInterlocutorPid'] == $instCrtdEver[$b]->ownerPid) {
             return 1;
         }
         // deal with the case of critical sections with no threads
         if (!empty($instCrtdEver[$a]->mastersThreadSpecificData) && empty($instCrtdEver[$b]->mastersThreadSpecificData)) {
             return -1;
         } else {
             if (empty($instCrtdEver[$a]->mastersThreadSpecificData) && !empty($instCrtdEver[$b]->mastersThreadSpecificData)) {
                 return 1;
             } else {
                 if (empty($instCrtdEver[$b]->mastersThreadSpecificData) && empty($instCrtdEver[$b]->mastersThreadSpecificData)) {
                     return 0;
                 }
             }
         }
         // a
         // gather the thread dispatch priorities for the compared critical sections
         $dispPriorTableA = array();
         // priority value => occurrences count
         $dispPriorTableB = array();
         // priority value => occurrences count
         foreach ($instCrtdEver[$a]->mastersThreadSpecificData as $thrdSpecificData) {
             @($dispPriorTableA[$thrdSpecificData['dispatchPriority']] += 1);
         }
         foreach ($instCrtdEver[$b]->mastersThreadSpecificData as $thrdSpecificData) {
             @($dispPriorTableB[$thrdSpecificData['dispatchPriority']] += 1);
         }
         // both critical sections have threads
         // make the tables to have the same amount of keys (rows)
         foreach ($dispPriorTableA as $key => $value) {
             @($dispPriorTableB[$key] = $dispPriorTableB[$key]);
         }
         // this is done on purpose
         foreach ($dispPriorTableB as $key => $value) {
             @($dispPriorTableA[$key] = $dispPriorTableA[$key]);
         }
         ksort($dispPriorTableA);
         ksort($dispPriorTableB);
         // compare the tables while taking into account the priority
         // and the thread count that have it per critical section
         foreach ($dispPriorTableA as $key => $value) {
             if ($value < $dispPriorTableB[$key]) {
                 return 1;
             } else {
                 if ($value > $dispPriorTableB[$key]) {
                     return -1;
                 }
             }
             // a
         }
         return 0;
         // a
     });
 }
Ejemplo n.º 14
0
<?php

pcntl_signal(SIGALRM, function () {
});
var_dump(pcntl_alarm());
pcntl_alarm(0);
var_dump(pcntl_alarm(60));
var_dump(pcntl_alarm(1) > 0);
$siginfo = array();
var_dump(pcntl_sigtimedwait(array(SIGALRM), $siginfo, 2) === SIGALRM);
Ejemplo n.º 15
0
 /**
  * 主进程主循环 主要是监听子进程退出、服务终止、平滑重启信号
  * @return void
  */
 public static function loop()
 {
     $siginfo = array();
     while (1) {
         @pcntl_sigtimedwait(array(SIGCHLD), $siginfo, 1);
         // 初始化任务系统
         Lib\Task::tick();
         // 检查是否有进程退出
         self::checkWorkerExit();
         // 触发信号处理
         pcntl_signal_dispatch();
     }
 }
Ejemplo n.º 16
0
 /**
  * Kill all children with the supplied signal and wait for them to exit
  *
  * @param int $signal
  * @return bool
  */
 protected function killChildren($signal = SIGKILL)
 {
     // Signal all processes to exit
     foreach ($this->processPIDs as $pid => $name) {
         \posix_kill($pid, $signal);
     }
     for ($i = 0; $i < 3000; $i++) {
         if (\count($this->processPIDs) === 0) {
             return true;
         }
         $signalInfo = null;
         if (-1 !== \pcntl_sigtimedwait([SIGCHLD], $signalInfo, 0, 100000000)) {
             $this->cleanupChild($signalInfo, true);
         }
     }
     // Forcefully destroy all remaining processes
     foreach ($this->processPIDs as $pid => $name) {
         \posix_kill($pid, SIGKILL);
     }
     return false;
 }