前情提要
在swoole的timer定时器中,添加定时器的步骤其实还有很多的初始化操作,这些操作是很重要的,因为限制于篇幅,于是把这一部分放到这里来说。
起死回生:swoole毫秒定时器(Timer)源码解析一zhuanlan.zhihu.com![e0078931a98d09326812518ec9041319.png](https://i-blog.csdnimg.cn/blog_migrate/bf215095dac059f161a7717fe199fa2c.jpeg)
swoole_timer_add中的初始化
TimerNode *swoole_timer_add(long ms, bool persistent, const TimerCallback &callback, void *private_data) {
if (sw_unlikely(SwooleTG.timer == nullptr)) {
SwooleTG.timer = new Timer();
if (sw_unlikely(!SwooleTG.timer->init())) {
delete SwooleTG.timer;
SwooleTG.timer = nullptr;
return nullptr;
}
}
return SwooleTG.timer->add(ms, persistent, private_data, callback);
}
接着是Timer的构造函数。
// 先看看Timer的实例化
Timer::Timer()
// 最小堆,默认1024个,使用最小堆的原因是堆顶的定时任务还没到时间执行
// 那么其余的定时任务也肯定没到时间。
: heap(1024, Heap::MIN_HEAP) {
_current_id = -1; // 当前定时器id
next_msec_ = -1; // 下一次执行时间
_next_id = 1; // 下一个定时器id
round = 0;
now(&base_time);// 初始化启动时间,获取相对毫秒数有用,因为定时器都是下一次执行的
}
Timer的init方法
// SwooleTG.timer->init()
bool Timer::init() {
// 这步骤我觉得是多余的,因为Timer的构造函数已经执行了这个功能了。
// 我感觉构造函数那一块的now(&base_time)不需要
if (now(&base_time) < 0) {
return false;
}
if (SwooleTG.reactor) {
// 基于事件驱动的
return init_reactor(SwooleTG.reactor);
} else {
// 基于setitimer的定时器
return init_system_timer();
}
}
基于事件的定时器初始化
// 基于事件的初始化
bool Timer::init_reactor(Reactor *reactor) {
reactor_ = reactor;
// 当出现了时间间隔更加小的定时任务,需要用这个方法实时更新Timer的执行间隔
set = [](Timer *timer, long exec_msec) -> int {
timer->reactor_->timeout_msec = exec_msec;
return SW_OK;
};
// 关闭定时器
close = [](Timer *timer) { timer->set(timer, -1); };
// reactor线程添加该定时器执行时的函数select,定时器超时就会调用这个函数
reactor->set_end_callback(Reactor::PRIORITY_TIMER, [this](Reactor *) { select(); });
// reactor线程退出的条件
reactor->set_exit_condition(Reactor::EXIT_CONDITION_TIMER,
[this](Reactor *reactor, int &event_num) -> bool { return count() == 0; });
// reactor线程销毁时候要执行的方法。
reactor->add_destroy_callback([](void *) { swoole_timer_free(); });
return true;
}
基于setitimer的初始化
// 基于setitimer的初始化
bool Timer::init_system_timer() {
// 当出现了时间间隔更加小的定时任务,需要用这个方法实时更新Timer的执行间隔
// 和setitimer的执行间隔
set = SystemTimer_set;
// 关闭定时器
close = [](Timer *timer) { SystemTimer_set(timer, -1); };
// setitimer触发的是SIGALRM,因此添加该信号的处理器
swSignal_set(SIGALRM, [](int sig) { SwooleG.signal_alarm = true; });
return true;
}
Timer::init_system_timer的SystemTimer_set
static int SystemTimer_set(Timer *timer, long next_msec) {
struct itimerval timer_set;
struct timeval now;
if (gettimeofday(&now, nullptr) < 0) {
swSysWarn("gettimeofday() failed");
return SW_ERR;
}
if (next_msec > 0) {
// 秒数
int sec = next_msec / 1000;
// 毫秒数
int msec = next_msec % 1000;
timer_set.it_interval.tv_sec = sec;
timer_set.it_interval.tv_usec = msec * 1000;
timer_set.it_value.tv_sec = sec;
timer_set.it_value.tv_usec = timer_set.it_interval.tv_usec;
// timer_set.it_value.tv_usec如果超过1s,1e6就是1000000微秒,也就是1s
if (timer_set.it_value.tv_usec > 1e6) {
timer_set.it_value.tv_usec = timer_set.it_value.tv_usec - 1e6;
timer_set.it_value.tv_sec += 1; // 秒数加1
}
} else {
timer_set = {};
}
// setitimer设置,ITIMER_REAL表示触发SIGALRM信号
if (setitimer(ITIMER_REAL, &timer_set, nullptr) < 0) {
swSysWarn("setitimer() failed");
return SW_ERR;
}
return SW_OK;
}
Timer::init_system_timer的swSignal_set
swSignalHandler swSignal_set(int signo, swSignalHandler handler) {
#ifdef HAVE_SIGNALFD
// 将信号抽象为一个文件描述符,当有信号发生时可以对其read,
// 这样可以将信号的监听放到select、poll、epoll等监听队列中,事件监听
if (SwooleG.use_signalfd) {
return swSignalfd_set(signo, handler);
} else
#endif
{
#ifdef HAVE_KQUEUE // 苹果系统
// SIGCHLD can not be monitored by kqueue, if blocked by SIG_IGN
// see https://www.freebsd.org/cgi/man.cgi?kqueue
// if there's no main reactor, signals cannot be monitored either
if (signo != SIGCHLD && sw_reactor()) {
return swKqueueSignal_set(signo, handler);
} else
#endif
{
// 设置信号的一些信息
signals[signo].handler = handler;
signals[signo].activated = true;
signals[signo].signo = signo;
return swSignal_set(signo, swSignal_async_handler, 1, 0);
}
}
}
看看swSignal_set这个重载函数
swSignalHandler swSignal_set(int signo, swSignalHandler func, int restart, int mask) {
// ignore
if (func == nullptr) {
func = SIG_IGN; // 忽略该信号
}
// clear
else if ((long) func == -1) {
func = SIG_DFL; // 默认操作
}
struct sigaction act {
}, oact{};
act.sa_handler = func;
if (mask) {
// 初始化act.sa_mask指向的信号集,使其包括所有信号
sigfillset(&act.sa_mask);
} else {
// 初始化act.sa_mask指向的信号集,清除所有信号
sigemptyset(&act.sa_mask);
}
act.sa_flags = 0;
// 注册该信号的关联的处理动作
if (sigaction(signo, &act, &oact) < 0) {
return nullptr;
}
return oact.sa_handler;
}
swSignalfd_set将signal转化为文件描述符
// 信号抽象为一个文件描述符
static swSignalHandler swSignalfd_set(int signo, swSignalHandler handler) {
swSignalHandler origin_handler = nullptr;
if (handler == nullptr && signals[signo].activated) {
// 如果信号处理函数为nullptr,
// 将signo信号从signalfd_mask删除
sigdelset(&signalfd_mask, signo);
// 重置signals[signo]对应的swSignal
sw_memset_zero(&signals[signo], sizeof(swSignal));
} else {
// 否则,将该信号加入signalfd_mask信号集
sigaddset(&signalfd_mask, signo);
// 重新设置该信号的属性
origin_handler = signals[signo].handler;
signals[signo].handler = handler;
signals[signo].signo = signo;
signals[signo].activated = true;
}
// 如果信号描述符signal_fd存在
if (signal_fd > 0) {
// SIG_SETMASK表示该信号的新的屏蔽是signalfd_mask指向的值
sigprocmask(SIG_SETMASK, &signalfd_mask, nullptr);
// 因为signal_fd 不为-1,所以这里是更新操作
signalfd(signal_fd, &signalfd_mask, SFD_NONBLOCK | SFD_CLOEXEC);
} else if (sw_reactor()) {
//否则,安装该信号描述符
swSignalfd_setup(sw_reactor());
}
return origin_handler;
}
swSignalfd_setup安装信号处理器
// 设置信号文件描述符
int swSignalfd_setup(Reactor *reactor) {
if (signal_fd != 0) {
return SW_OK;
}
// -1表示新建一个信号文件描述符
signal_fd = signalfd(-1, &signalfd_mask, SFD_NONBLOCK | SFD_CLOEXEC);
if (signal_fd < 0) {
swSysWarn("signalfd() failed");
return SW_ERR;
}
// 套接字
signal_socket = swoole::make_socket(signal_fd, SW_FD_SIGNAL);
// SIG_BLOCK表示新的屏蔽字是当前信号屏蔽字和signalfd_mask的交集。
if (sigprocmask(SIG_BLOCK, &signalfd_mask, nullptr) == -1) {
swSysWarn("sigprocmask() failed");
goto _error;
}
// 这部分具体设涉及的我还没看
// 为socket设置函数处理器
// 定时器时间到就会执行这个函数swSignalfd_onSignal
swoole_event_set_handler(SW_FD_SIGNAL, swSignalfd_onSignal);
if (swoole_event_add(signal_socket, SW_EVENT_READ) < 0) {
goto _error;
}
// reactor线程添加可以退出的条件
reactor->set_exit_condition(Reactor::EXIT_CONDITION_SIGNALFD, [](Reactor *reactor, int &event_num) -> bool {
event_num--;
return true;
});
SwooleG.signal_fd = signal_fd;
return SW_OK;
_error:
signal_socket->fd = -1;
signal_socket->free();
close(signal_fd);
signal_fd = 0;
return SW_ERR;
}
其实看到这里是非常绕的,其实Timer定时器初始化有下面几个步骤:
1.Timer::init()执行的时候通过if决定是要基于事件的定时器还是基于setitimer的定时器。
2.如果选择基于事件的定时器,先初始化一些基本的属性,最主要的是下面这一步
定时器超时就会执行这个命令。
但是reactor如何定时执行我还没有去了解。。。。。
reactor->set_end_callback(Reactor::PRIORITY_TIMER, [this](Reactor *) { select(); });
3.如果是基于setitimer的定时器,先判断系统是否支持signalfd这个函数,支持的话会优先将信号处理为文件描述符,并加入事件机制中等待信号触发。
定时器超时就会执行signalfd_siginfo这个方法。
swoole_event_set_handler(SW_FD_SIGNAL, swSignalfd_onSignal)
如果系统不支持signalfd,那就是通过sigaction注册信号处理函数。
if (sigaction(signo, &act, &oact) < 0) {
return nullptr;
}
这里的注册函数是,定时器超时就会执行这个函数swSignal_async_handler,
swSignal_async_handler里面也是根据signo找到对应的信号处理函数。
[](int sig) { SwooleG.signal_alarm = true; }
这里我的猜测是SwooleG.signal_alarm = true,reactor就能直接通过最小堆拿出堆顶的进行判断。
static void swSignal_async_handler(int signo) {
if (sw_reactor()) {
sw_reactor()->singal_no = signo;
} else {
// discard signal
if (_lock) {
return;
}
_lock = 1;
swSignal_callback(signo);
_lock = 0;
}
}
void swSignal_callback(int signo) {
if (signo >= SW_SIGNO_MAX) {
swWarn("signal[%d] numberis invalid", signo);
return;
}
swSignalHandler callback = signals[signo].handler;
if (!callback) {
swoole_error_log(SW_LOG_WARNING, SW_ERROR_UNREGISTERED_SIGNAL, SW_UNREGISTERED_SIGNAL_FMT, swSignal_str(signo));
return;
}
callback(signo);
}
天气很冷,边抖边写的,写的不好的话望斧正。谢谢啦!!!