phpsocks5/Workerman/Events/Select.php

264 lines
7.5 KiB
PHP
Raw Normal View History

2015-04-04 21:46:31 +08:00
<?php
2016-09-20 21:27:41 +08:00
/**
* 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 walkor<walkor@workerman.net>
* @copyright walkor<walkor@workerman.net>
* @link http://www.workerman.net/
* @license http://www.opensource.org/licenses/mit-license.php MIT License
*/
2015-04-04 21:46:31 +08:00
namespace Workerman\Events;
2016-09-20 21:27:41 +08:00
/**
* select eventloop
*/
2015-04-04 21:46:31 +08:00
class Select implements EventInterface
{
/**
2016-09-20 21:27:41 +08:00
* All listeners for read/write event.
*
2015-04-04 21:46:31 +08:00
* @var array
*/
public $_allEvents = array();
2016-09-20 21:27:41 +08:00
2015-04-04 21:46:31 +08:00
/**
2016-09-20 21:27:41 +08:00
* Event listeners of signal.
*
2015-04-04 21:46:31 +08:00
* @var array
*/
public $_signalEvents = array();
2016-09-20 21:27:41 +08:00
2015-04-04 21:46:31 +08:00
/**
2016-09-20 21:27:41 +08:00
* Fds waiting for read event.
*
2015-04-04 21:46:31 +08:00
* @var array
*/
protected $_readFds = array();
2016-09-20 21:27:41 +08:00
2015-04-04 21:46:31 +08:00
/**
2016-09-20 21:27:41 +08:00
* Fds waiting for write event.
*
2015-04-04 21:46:31 +08:00
* @var array
*/
protected $_writeFds = array();
2016-09-20 21:27:41 +08:00
2015-04-04 21:46:31 +08:00
/**
2016-09-20 21:27:41 +08:00
* Timer scheduler.
2015-04-04 21:46:31 +08:00
* {['data':timer_id, 'priority':run_timestamp], ..}
2016-09-20 21:27:41 +08:00
*
* @var \SplPriorityQueue
2015-04-04 21:46:31 +08:00
*/
protected $_scheduler = null;
2016-09-20 21:27:41 +08:00
2015-04-04 21:46:31 +08:00
/**
2016-09-20 21:27:41 +08:00
* All timer event listeners.
2015-04-04 21:46:31 +08:00
* [[func, args, flag, timer_interval], ..]
2016-09-20 21:27:41 +08:00
*
2015-04-04 21:46:31 +08:00
* @var array
*/
protected $_task = array();
2016-09-20 21:27:41 +08:00
2015-04-04 21:46:31 +08:00
/**
2016-09-20 21:27:41 +08:00
* Timer id.
*
2015-04-04 21:46:31 +08:00
* @var int
*/
protected $_timerId = 1;
2016-09-20 21:27:41 +08:00
2015-04-04 21:46:31 +08:00
/**
2016-09-20 21:27:41 +08:00
* Select timeout.
*
2015-04-04 21:46:31 +08:00
* @var int
*/
protected $_selectTimeout = 100000000;
2016-09-20 21:27:41 +08:00
2015-04-04 21:46:31 +08:00
/**
2016-09-20 21:27:41 +08:00
* Paired socket channels
*
* @var array
*/
protected $channel = array();
/**
* Construct.
2015-04-04 21:46:31 +08:00
*/
public function __construct()
{
2016-09-20 21:27:41 +08:00
// Create a pipeline and put into the collection of the read to read the descriptor to avoid empty polling.
2015-04-04 21:46:31 +08:00
$this->channel = stream_socket_pair(STREAM_PF_UNIX, STREAM_SOCK_STREAM, STREAM_IPPROTO_IP);
2016-09-20 21:27:41 +08:00
if ($this->channel) {
2015-04-04 21:46:31 +08:00
stream_set_blocking($this->channel[0], 0);
$this->_readFds[0] = $this->channel[0];
}
2016-09-20 21:27:41 +08:00
// Init SplPriorityQueue.
2015-04-04 21:46:31 +08:00
$this->_scheduler = new \SplPriorityQueue();
$this->_scheduler->setExtractFlags(\SplPriorityQueue::EXTR_BOTH);
}
2016-09-20 21:27:41 +08:00
2015-04-04 21:46:31 +08:00
/**
2016-09-20 21:27:41 +08:00
* {@inheritdoc}
2015-04-04 21:46:31 +08:00
*/
2016-09-20 21:27:41 +08:00
public function add($fd, $flag, $func, $args = array())
2015-04-04 21:46:31 +08:00
{
2016-09-20 21:27:41 +08:00
switch ($flag) {
2015-04-04 21:46:31 +08:00
case self::EV_READ:
2016-09-20 21:27:41 +08:00
$fd_key = (int)$fd;
2015-04-04 21:46:31 +08:00
$this->_allEvents[$fd_key][$flag] = array($func, $fd);
2016-09-20 21:27:41 +08:00
$this->_readFds[$fd_key] = $fd;
2015-04-04 21:46:31 +08:00
break;
case self::EV_WRITE:
2016-09-20 21:27:41 +08:00
$fd_key = (int)$fd;
2015-04-04 21:46:31 +08:00
$this->_allEvents[$fd_key][$flag] = array($func, $fd);
2016-09-20 21:27:41 +08:00
$this->_writeFds[$fd_key] = $fd;
2015-04-04 21:46:31 +08:00
break;
case self::EV_SIGNAL:
2016-09-20 21:27:41 +08:00
$fd_key = (int)$fd;
2015-04-04 21:46:31 +08:00
$this->_signalEvents[$fd_key][$flag] = array($func, $fd);
pcntl_signal($fd, array($this, 'signalHandler'));
break;
case self::EV_TIMER:
case self::EV_TIMER_ONCE:
2016-09-20 21:27:41 +08:00
$run_time = microtime(true) + $fd;
2015-04-04 21:46:31 +08:00
$this->_scheduler->insert($this->_timerId, -$run_time);
2016-09-20 21:27:41 +08:00
$this->_task[$this->_timerId] = array($func, (array)$args, $flag, $fd);
2015-04-04 21:46:31 +08:00
$this->tick();
return $this->_timerId++;
}
2016-09-20 21:27:41 +08:00
2015-04-04 21:46:31 +08:00
return true;
}
2016-09-20 21:27:41 +08:00
2015-04-04 21:46:31 +08:00
/**
2016-09-20 21:27:41 +08:00
* Signal handler.
*
2015-04-04 21:46:31 +08:00
* @param int $signal
*/
public function signalHandler($signal)
{
call_user_func_array($this->_signalEvents[$signal][self::EV_SIGNAL][0], array($signal));
}
2016-09-20 21:27:41 +08:00
2015-04-04 21:46:31 +08:00
/**
2016-09-20 21:27:41 +08:00
* {@inheritdoc}
2015-04-04 21:46:31 +08:00
*/
2016-09-20 21:27:41 +08:00
public function del($fd, $flag)
2015-04-04 21:46:31 +08:00
{
$fd_key = (int)$fd;
2016-09-20 21:27:41 +08:00
switch ($flag) {
2015-04-04 21:46:31 +08:00
case self::EV_READ:
unset($this->_allEvents[$fd_key][$flag], $this->_readFds[$fd_key]);
2016-09-20 21:27:41 +08:00
if (empty($this->_allEvents[$fd_key])) {
2015-04-04 21:46:31 +08:00
unset($this->_allEvents[$fd_key]);
}
return true;
case self::EV_WRITE:
unset($this->_allEvents[$fd_key][$flag], $this->_writeFds[$fd_key]);
2016-09-20 21:27:41 +08:00
if (empty($this->_allEvents[$fd_key])) {
2015-04-04 21:46:31 +08:00
unset($this->_allEvents[$fd_key]);
}
return true;
case self::EV_SIGNAL:
unset($this->_signalEvents[$fd_key]);
pcntl_signal($fd, SIG_IGN);
break;
case self::EV_TIMER:
case self::EV_TIMER_ONCE;
unset($this->_task[$fd_key]);
return true;
}
2016-09-20 21:27:41 +08:00
return false;
2015-04-04 21:46:31 +08:00
}
2016-09-20 21:27:41 +08:00
2015-04-04 21:46:31 +08:00
/**
2016-09-20 21:27:41 +08:00
* Tick for timer.
*
2015-04-04 21:46:31 +08:00
* @return void
*/
protected function tick()
{
2016-09-20 21:27:41 +08:00
while (!$this->_scheduler->isEmpty()) {
$scheduler_data = $this->_scheduler->top();
$timer_id = $scheduler_data['data'];
$next_run_time = -$scheduler_data['priority'];
$time_now = microtime(true);
$this->_selectTimeout = ($next_run_time - $time_now) * 1000000;
if ($this->_selectTimeout <= 0) {
2015-04-04 21:46:31 +08:00
$this->_scheduler->extract();
2016-09-20 21:27:41 +08:00
if (!isset($this->_task[$timer_id])) {
2015-04-04 21:46:31 +08:00
continue;
}
2016-09-20 21:27:41 +08:00
// [func, args, flag, timer_interval]
2015-04-04 21:46:31 +08:00
$task_data = $this->_task[$timer_id];
2016-09-20 21:27:41 +08:00
if ($task_data[2] === self::EV_TIMER) {
$next_run_time = $time_now + $task_data[3];
2015-04-04 21:46:31 +08:00
$this->_scheduler->insert($timer_id, -$next_run_time);
}
2016-09-20 21:27:41 +08:00
call_user_func_array($task_data[0], $task_data[1]);
if (isset($this->_task[$timer_id]) && $task_data[2] === self::EV_TIMER_ONCE) {
$this->del($timer_id, self::EV_TIMER_ONCE);
2015-04-04 21:46:31 +08:00
}
continue;
}
2016-09-20 21:27:41 +08:00
return;
2015-04-04 21:46:31 +08:00
}
$this->_selectTimeout = 100000000;
}
2016-09-20 21:27:41 +08:00
2015-04-04 21:46:31 +08:00
/**
2016-09-20 21:27:41 +08:00
* {@inheritdoc}
2015-04-04 21:46:31 +08:00
*/
public function clearAllTimer()
{
$this->_scheduler = new \SplPriorityQueue();
$this->_scheduler->setExtractFlags(\SplPriorityQueue::EXTR_BOTH);
$this->_task = array();
}
2016-09-20 21:27:41 +08:00
2015-04-04 21:46:31 +08:00
/**
2016-09-20 21:27:41 +08:00
* {@inheritdoc}
2015-04-04 21:46:31 +08:00
*/
public function loop()
{
$e = null;
2016-09-20 21:27:41 +08:00
while (1) {
// Calls signal handlers for pending signals
2015-04-04 21:46:31 +08:00
pcntl_signal_dispatch();
2016-09-20 21:27:41 +08:00
$read = $this->_readFds;
2015-04-04 21:46:31 +08:00
$write = $this->_writeFds;
2016-09-20 21:27:41 +08:00
// Waiting read/write/signal/timeout events.
$ret = @stream_select($read, $write, $e, 0, $this->_selectTimeout);
if (!$this->_scheduler->isEmpty()) {
$this->tick();
2015-04-04 21:46:31 +08:00
}
2016-09-20 21:27:41 +08:00
if (!$ret) {
continue;
}
foreach ($read as $fd) {
$fd_key = (int)$fd;
if (isset($this->_allEvents[$fd_key][self::EV_READ])) {
call_user_func_array($this->_allEvents[$fd_key][self::EV_READ][0],
array($this->_allEvents[$fd_key][self::EV_READ][1]));
2015-04-04 21:46:31 +08:00
}
}
2016-09-20 21:27:41 +08:00
foreach ($write as $fd) {
$fd_key = (int)$fd;
if (isset($this->_allEvents[$fd_key][self::EV_WRITE])) {
call_user_func_array($this->_allEvents[$fd_key][self::EV_WRITE][0],
array($this->_allEvents[$fd_key][self::EV_WRITE][1]));
}
2015-04-04 21:46:31 +08:00
}
}
}
}