archive
commit
3d3f6d6b8b
|
@ -0,0 +1,3 @@
|
|||
vendor/
|
||||
composer.lock
|
||||
.idea/
|
|
@ -0,0 +1,21 @@
|
|||
MIT License
|
||||
|
||||
Copyright (c) 2017 CismonX
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in all
|
||||
copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
SOFTWARE.
|
|
@ -0,0 +1,35 @@
|
|||
## Workerman-Uv
|
||||
|
||||
### 简介
|
||||
|
||||
[libuv](http://libuv.org/) 是一个事件驱动的异步 I/O 库,最初是为 Node.js 开发的。随后也在 Python、Julia 等语言中被应用。
|
||||
|
||||
[php-uv](https://pecl.php.net/package/uv) 是对 libuv 的封装,使其可以在 PHP 中被应用。
|
||||
|
||||
本项目将 php-uv 的 event-loop 应用于 Workerman,从而可以在基于 Workerman 的项目中利用 php-uv 提供的特性。
|
||||
|
||||
### 使用说明
|
||||
|
||||
1. 使用包管理器安装 libuv 和 libuv-devel(可能需要手动添加源)。
|
||||
|
||||
2. 使用 pecl 安装 php-uv(也可以从 pecl 官网或 GitHub 仓库下载源码后手动编译)。
|
||||
|
||||
3. 使用 composer 加载`Workerman\\Events\\Uv`。
|
||||
|
||||
```bash
|
||||
composer require cismonx/workerman-uv
|
||||
```
|
||||
|
||||
4. 在项目中使用 `Workerman\Events\Uv` 提供的 event-loop。如下:
|
||||
|
||||
```php
|
||||
Worker::$eventLoopClass = '\\Workerman\\Events\\Uv';
|
||||
```
|
||||
|
||||
### 注意
|
||||
|
||||
1. 使用 libuv 的 event-loop 后,Workerman 的子进程处理 SIGINT 事件时会 exit 2 (no such file or directory),这个问题待解决。
|
||||
|
||||
2. 如果需要使用 libuv 的多线程特性,需要线程安全(ZTS)的 PHP。
|
||||
|
||||
3. php-uv 目前处于 Beta 阶段,其稳定性不能保证。请避免将其应用于生产环境。
|
|
@ -0,0 +1,15 @@
|
|||
{
|
||||
"name" : "cismonx/workerman-uv",
|
||||
"description" : "Libuv event loop for Workerman.",
|
||||
"license" : "MIT",
|
||||
"type" : "library",
|
||||
"require" : {
|
||||
"workerman/workerman": "^3.4",
|
||||
"ext-uv": "*"
|
||||
},
|
||||
"autoload" : {
|
||||
"psr-4" : {
|
||||
"Workerman\\Events\\" : "src/"
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,176 @@
|
|||
<?php
|
||||
/**
|
||||
* Workerman-Uv
|
||||
* 2017 CismonX <admin@cismon.net>
|
||||
*/
|
||||
namespace Workerman\Events;
|
||||
use Workerman\Worker;
|
||||
|
||||
class Uv implements EventInterface {
|
||||
|
||||
/**
|
||||
* Libuv event loop.
|
||||
* @var resource
|
||||
*/
|
||||
protected $_loop;
|
||||
|
||||
/**
|
||||
* Read & write events.
|
||||
* @var array
|
||||
*/
|
||||
protected $_allEvents = [];
|
||||
|
||||
/**
|
||||
* Signals.
|
||||
* @var array
|
||||
*/
|
||||
protected $_eventSignal = [];
|
||||
|
||||
/**
|
||||
* Timers.
|
||||
* @var array
|
||||
*/
|
||||
protected $_eventTimer = [];
|
||||
|
||||
/**
|
||||
* Timer id counter.
|
||||
* @var int
|
||||
*/
|
||||
protected static $_timerId = 1;
|
||||
|
||||
/**
|
||||
* Identifies a socket with both read and write events registered.
|
||||
*/
|
||||
const EV_RW = 3;
|
||||
|
||||
/**
|
||||
* Constructor.
|
||||
*/
|
||||
public function __construct() {
|
||||
$this->_loop = uv_default_loop();
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function add($fd, $flag, $func, $args = null) {
|
||||
switch ($flag) {
|
||||
case self::EV_READ:
|
||||
case self::EV_WRITE:
|
||||
$fd_key = intval($fd);
|
||||
//uv_poll_init() can only be called once for a same file descriptor.
|
||||
if (!isset($this->_allEvents[$fd_key]))
|
||||
$this->_allEvents[$fd_key][0] = uv_poll_init($this->_loop, $fd);
|
||||
$event = $this->_allEvents[$fd_key][0];
|
||||
$this->_allEvents[$fd_key][$flag] = $func;
|
||||
if (isset($this->_allEvents[$fd_key][self::EV_RW - $flag]))
|
||||
$flag = self::EV_RW;
|
||||
//Call uv_poll_start() with both existing flags.
|
||||
uv_poll_start($event, $flag, function ($poll, $stat, $ev, $conn) use ($func) {
|
||||
$func($conn);
|
||||
});
|
||||
break;
|
||||
case self::EV_SIGNAL:
|
||||
$fd_key = intval($fd);
|
||||
$event = uv_signal_init();
|
||||
uv_signal_start($event, function ($ev, $signal) use ($func) {
|
||||
$func($signal);
|
||||
}, $fd_key);
|
||||
$this->_eventSignal[$fd_key] = $event;
|
||||
break;
|
||||
case self::EV_TIMER:
|
||||
case self::EV_TIMER_ONCE:
|
||||
$event = uv_timer_init();
|
||||
$param = [$func, (array)$args, $flag, self::$_timerId];
|
||||
$interval = $fd * 1000;
|
||||
uv_timer_start($event, $interval, $interval, \Closure::bind(function () use ($param) {
|
||||
$timer_id = $param[3];
|
||||
if ($param[2] === self::EV_TIMER_ONCE) {
|
||||
uv_timer_stop($this->_eventTimer[$timer_id]);
|
||||
unset($this->_eventTimer[$timer_id]);
|
||||
}
|
||||
try {
|
||||
call_user_func_array($param[0], $param[1]);
|
||||
} catch (\Exception $e) {
|
||||
Worker::log($e);
|
||||
exit(250);
|
||||
} catch (\Error $e) {
|
||||
Worker::log($e);
|
||||
exit(250);
|
||||
}
|
||||
}, $this, __CLASS__));
|
||||
$this->_eventTimer[self::$_timerId] = $event;
|
||||
return self::$_timerId++;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function del($fd, $flag) {
|
||||
switch ($flag) {
|
||||
case self::EV_READ:
|
||||
case self::EV_WRITE:
|
||||
$fd_key = intval($fd);
|
||||
if (isset($this->_allEvents[$fd_key][$flag])) {
|
||||
unset($this->_allEvents[$fd_key][$flag]);
|
||||
if (isset($this->_allEvents[$fd_key][self::EV_RW - $flag])) {
|
||||
$func = $this->_allEvents[$fd_key][self::EV_RW - $flag];
|
||||
//Call uv_poll_start() with the remaining flag instead of call uv_poll_stop().
|
||||
uv_poll_start($this->_allEvents[$fd_key][0], self::EV_RW - $flag,
|
||||
function ($poll, $stat, $ev, $conn) use ($func) {
|
||||
$func($conn);
|
||||
}
|
||||
);
|
||||
} else
|
||||
uv_poll_stop($this->_allEvents[$fd_key][0]);
|
||||
}
|
||||
break;
|
||||
case self::EV_SIGNAL:
|
||||
$fd_key = intval($fd);
|
||||
if (isset($this->_eventSignal[$fd_key])) {
|
||||
uv_signal_stop($this->_eventSignal[$fd_key]);
|
||||
unset($this->_eventSignal[$fd_key]);
|
||||
}
|
||||
break;
|
||||
case self::EV_TIMER:
|
||||
case self::EV_TIMER_ONCE:
|
||||
if (isset($this->_eventTimer[$fd])) {
|
||||
uv_timer_stop($this->_eventTimer[$fd]);
|
||||
unset($this->_eventTimer[$fd]);
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function loop() {
|
||||
uv_run();
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function clearAllTimer() {
|
||||
foreach ($this->_eventTimer as $event)
|
||||
uv_timer_stop($event);
|
||||
$this->_eventTimer = [];
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function destroy() {
|
||||
foreach ($this->_eventSignal as $event)
|
||||
uv_signal_stop($event);
|
||||
}
|
||||
|
||||
public function getTimerCount() {
|
||||
return count($this->_eventTimer);
|
||||
}
|
||||
}
|
Reference in New Issue