Sfoglia il codice sorgente

Add swoole support.

1.Add swoole support.\Worker::$eventLoopClass = \Workerman\Events\Swoole
2.Fix infinite loop when Worker::count=0.
3.Fix fatal error cause by SIGUSER1 and SIGIIO when the worker is
graceful stopping.
ares 7 anni fa
parent
commit
6b6ec77930
3 ha cambiato i file con 177 aggiunte e 11 eliminazioni
  1. 2 3
      Connection/TcpConnection.php
  2. 159 0
      Events/Swoole.php
  3. 16 8
      Worker.php

+ 2 - 3
Connection/TcpConnection.php

@@ -679,7 +679,7 @@ class TcpConnection extends ConnectionInterface
             $this->bytesWritten += $len;
             Worker::$globalEvent->del($this->_socket, EventInterface::EV_WRITE);
             $this->_sendBuffer = '';
-            // Try to emit onBufferDrain callback when the send buffer becomes empty. 
+            // Try to emit onBufferDrain callback when the send buffer becomes empty.
             if ($this->onBufferDrain) {
                 try {
                     call_user_func($this->onBufferDrain, $this);
@@ -941,8 +941,7 @@ class TcpConnection extends ConnectionInterface
             }
 
             if(0 === self::$statistics['connection_count']) {
-                Worker::$globalEvent->destroy();
-                exit(0);
+                Worker::stopAll();
             }
         }
     }

+ 159 - 0
Events/Swoole.php

@@ -0,0 +1,159 @@
+<?php
+/**
+ * This file is part of workerman.
+ *
+ * Licensed under The MIT License
+ * For full copyright and license information, please see the MIT-LICENSE.txt
+ * Redistributions of files must retain the above copyright notice.
+ *
+ * @author    Ares<aresrr#qq.com>
+ * @link      http://www.workerman.net/
+ * @link      https://github.com/ares333/Workerman
+ * @license   http://www.opensource.org/licenses/mit-license.php MIT License
+ */
+namespace Workerman\Events;
+
+use Swoole\Event;
+use Swoole\Timer;
+use Swoole\Process;
+
+class Swoole implements EventInterface
+{
+
+    protected $_timer = array();
+
+    protected $_fd = array();
+
+    public static $usePcntl = true;
+
+    // Swoole\Process::signal() is not stable in some version of php and swoole.
+    // The problem may be caused by using pcntl_signal() and pcntl_fork() and Swoole\Process::signal() together.
+    protected $_hasSignal = false;
+
+    /**
+     *
+     * {@inheritdoc}
+     *
+     * @see \Workerman\Events\EventInterface::add()
+     */
+    public function add($fd, $flag, $func, $args = null)
+    {
+        if (! isset($args)) {
+            $args = array();
+        }
+        switch ($flag) {
+            case self::EV_SIGNAL:
+                if (static::$usePcntl) {
+                    $res = pcntl_signal($fd, $func, false);
+                    if (! $this->_hasSignal && $res) {
+                        Timer::tick(800,
+                            function () {
+                                pcntl_signal_dispatch();
+                            });
+                        $this->_hasSignal = true;
+                    }
+                    return $res;
+                } else {
+                    return Process::signal($fd, $func);
+                }
+            case self::EV_TIMER:
+            case self::EV_TIMER_ONCE:
+                $method = self::EV_TIMER == $flag ? 'tick' : 'after';
+                $timer_id = Timer::$method($fd * 1000,
+                    function ($timer_id = null) use ($func, $args) {
+                        call_user_func_array($func, $args);
+                    });
+                $this->_timer[] = $timer_id;
+                return $timer_id;
+            case self::EV_READ:
+            case self::EV_WRITE:
+                if ($flag == self::EV_READ) {
+                    $res = Event::add($fd, $func, null, SWOOLE_EVENT_READ);
+                } else {
+                    $res = Event::add($fd, null, $func, SWOOLE_EVENT_WRITE);
+                }
+                if (! in_array((int) $fd, $this->_fd) && $res) {
+                    $this->_fd[] = (int) $fd;
+                }
+                return $res;
+        }
+    }
+
+    /**
+     *
+     * {@inheritdoc}
+     *
+     * @see \Workerman\Events\EventInterface::del()
+     */
+    public function del($fd, $flag)
+    {
+        switch ($flag) {
+            case self::EV_SIGNAL:
+                if (static::$usePcntl) {
+                    return pcntl_signal($fd, SIG_IGN, false);
+                } else {
+                    return Process::signal($fd, null);
+                }
+            case self::EV_TIMER:
+            case self::EV_TIMER_ONCE:
+                return Timer::clear($fd);
+            case self::EV_READ:
+            case self::EV_WRITE:
+                $key = array_search((int) $fd, $this->_fd);
+                if (false !== $key) {
+                    $res = Event::del($fd);
+                    if ($res) {
+                        unset($this->_fd[$key]);
+                    }
+                    return $res;
+                }
+        }
+    }
+
+    /**
+     *
+     * {@inheritdoc}
+     *
+     * @see \Workerman\Events\EventInterface::clearAllTimer()
+     */
+    public function clearAllTimer()
+    {
+        foreach ($this->_timer as $v) {
+            Timer::clear($v);
+        }
+        $this->_timer = array();
+    }
+
+    /**
+     *
+     * {@inheritdoc}
+     *
+     * @see \Workerman\Events\EventInterface::loop()
+     */
+    public function loop()
+    {
+        Event::wait();
+    }
+
+    /**
+     *
+     * {@inheritdoc}
+     *
+     * @see \Workerman\Events\EventInterface::destroy()
+     */
+    public function destroy()
+    {
+        Event::exit();
+    }
+
+    /**
+     *
+     * {@inheritdoc}
+     *
+     * @see \Workerman\Events\EventInterface::getTimerCount()
+     */
+    public function getTimerCount()
+    {
+        return count($this->_timer);
+    }
+}

+ 16 - 8
Worker.php

@@ -227,9 +227,15 @@ class Worker
     /**
      * Pause accept new connections or not.
      *
-     * @var string
+     * @var bool
      */
     protected $_pauseAccept = true;
+    
+    /**
+     * Is worker stopping ?
+     * @var bool
+     */
+    public $stopping = false;
 
     /**
      * Daemonize.
@@ -601,6 +607,7 @@ class Worker
     {
         foreach (static::$_workers as $worker_id => $worker) {
             $new_id_map = array();
+            $worker->count = $worker->count <= 0 ? 1 : $worker->count;
             for($key = 0; $key < $worker->count; $key++) {
                 $new_id_map[$key] = isset(static::$_idMap[$worker_id][$key]) ? static::$_idMap[$worker_id][$key] : 0;
             }
@@ -758,11 +765,11 @@ class Worker
                 if ($command2 === '-g') {
                     static::$_gracefulStop = true;
                     $sig = SIGTERM;
-                    static::log("Workerman[$start_file] is gracefully stoping ...");
+                    static::log("Workerman[$start_file] is gracefully stopping ...");
                 } else {
                     static::$_gracefulStop = false;
                     $sig = SIGINT;
-                    static::log("Workerman[$start_file] is stoping ...");
+                    static::log("Workerman[$start_file] is stopping ...");
                 }
                 // Send stop signal to master process.
                 $master_pid && posix_kill($master_pid, $sig);
@@ -917,7 +924,7 @@ class Worker
         static::$globalEvent->add(SIGUSR1, EventInterface::EV_SIGNAL, array('\Workerman\Worker', 'signalHandler'));
         // reinstall graceful reload signal handler
         static::$globalEvent->add(SIGQUIT, EventInterface::EV_SIGNAL, array('\Workerman\Worker', 'signalHandler'));
-        // reinstall  status signal handler
+        // reinstall status signal handler
         static::$globalEvent->add(SIGUSR2, EventInterface::EV_SIGNAL, array('\Workerman\Worker', 'signalHandler'));
         // reinstall connection status signal handler
         static::$globalEvent->add(SIGIO, EventInterface::EV_SIGNAL, array('\Workerman\Worker', 'signalHandler'));
@@ -1121,7 +1128,6 @@ class Worker
                 }
             }
 
-            $worker->count = $worker->count <= 0 ? 1 : $worker->count;
             while (count(static::$_pidMap[$worker->workerId]) < $worker->count) {
                 static::forkOneWorkerForLinux($worker);
             }
@@ -1600,9 +1606,13 @@ class Worker
         else {
             // Execute exit.
             foreach (static::$_workers as $worker) {
-                $worker->stop();
+                if(!$worker->stopping){
+                    $worker->stop();
+                    $worker->stopping = true;
+                }
             }
             if (!static::$_gracefulStop || ConnectionInterface::$statistics['connection_count'] <= 0) {
+                static::$_workers = array();
                 static::$globalEvent->destroy();
                 exit(0);
             }
@@ -2124,8 +2134,6 @@ class Worker
         }
         // Clear callback.
         $this->onMessage = $this->onClose = $this->onError = $this->onBufferDrain = $this->onBufferFull = null;
-        // Remove worker instance from static::$_workers.
-        unset(static::$_workers[$this->workerId]);
     }
 
     /**