1int hloop_run(hloop_t* loop)
hloop_run总结 :
1.loop状态判断和管理
2.loop的flags管理(
HLOOP_FLAG_QUIT_WHEN_NO_ACTIVE_EVENTS,HLOOP_FLAG_RUN_ONCE,HLOOP_FLAG_AUTO_FREE
)3.创建custom event通信fd,方便loop进行custom event事件传递
4.
hloop_process_events
真正处理事件的函数
lua
int hloop_run(hloop_t* loop) {
//状态控制已经状态判断,loop基于单线程运行模式,所以状态无锁
if (loop == NULL) return -1;
if (loop->status == HLOOP_STATUS_RUNNING) return -2;
loop->status = HLOOP_STATUS_RUNNING;
loop->pid = hv_getpid();
loop->tid = hv_gettid();
//用户custom event通信,即pairsocket
if (loop->intern_nevents == 0) {
hmutex_lock(&loop->custom_events_mutex);
if (loop->eventfds[EVENTFDS_WRITE_INDEX] == -1) {
hloop_create_eventfds(loop);
}
hmutex_unlock(&loop->custom_events_mutex);
#ifdef DEBUG
htimer_add(loop, hloop_stat_timer_cb, HLOOP_STAT_TIMEOUT, INFINITE);
++loop->intern_nevents;
#endif
}
while (loop->status != HLOOP_STATUS_STOP) {
if (loop->status == HLOOP_STATUS_PAUSE) {
hv_msleep(HLOOP_PAUSE_TIME);
hloop_update_time(loop);
continue;
}
++loop->loop_cnt;
//hloop标志,参考epool的flag
//当没有激活事件的时候,退出loop
if ((loop->flags & HLOOP_FLAG_QUIT_WHEN_NO_ACTIVE_EVENTS) &&
loop->nactives <= loop->intern_nevents) {
break;
}
//真正处理事件的函数
hloop_process_events(loop, HLOOP_MAX_BLOCK_TIME);
//只运行一次,然后退出loop
if (loop->flags & HLOOP_FLAG_RUN_ONCE) {
break;
}
}
loop->status = HLOOP_STATUS_STOP;
loop->end_hrtime = gethrtime_us();
//自动释放loop
if (loop->flags & HLOOP_FLAG_AUTO_FREE) {
hloop_cleanup(loop);
HV_FREE(loop);
}
return 0;
}
2.int hloop_process_events(hloop_t* loop, int timeout_ms)
hloop_process_events总结
- 处理事件优先级:
timer > io > idle
- 如果有timer事件并且timeout,则加入pendding队列,并且立马处理timer事件,跳过io事件
- 如果存在io并且没有触发timer的情况下,则检查io状态,如果io事件触发则加入pendding队列
- custom 事件不进入pendding队列,而是直接进入eventfd_read_cb
- 当不存在pendding事件,则触发idle
- 真正处理事件的是hloop_process_pendings
lua
int hloop_process_events(hloop_t* loop, int timeout_ms) {
// ios -> timers -> idles
int nios, ntimers, nidles;
nios = ntimers = nidles = 0;
// calc blocktime
int32_t blocktime_ms = timeout_ms;
//如果存在定时器,则检查定时器是否超时,
//由于这里是基于小根堆实现的定时器,所以只需要检查根节点是否超时即可
if (loop->ntimers) {
hloop_update_time(loop);
int64_t blocktime_us = blocktime_ms * 1000;
if (loop->timers.root) {
int64_t min_timeout = TIMER_ENTRY(loop->timers.root)->next_timeout - loop->cur_hrtime;
blocktime_us = MIN(blocktime_us, min_timeout);
}
if (loop->realtimers.root) {
int64_t min_timeout = TIMER_ENTRY(loop->realtimers.root)->next_timeout - hloop_now_us(loop);
blocktime_us = MIN(blocktime_us, min_timeout);
}
//如果已经超时,则说明定时器已经触发,直接处理定时器
if (blocktime_us < 0) goto process_timers;
blocktime_ms = blocktime_us / 1000 + 1;
blocktime_ms = MIN(blocktime_ms, timeout_ms);
}
//如果存在io则处理iowatcher_poll_events,不同的模型,实现不一样
//如果io事件被触发则加入pendding队列
if (loop->nios) {
nios = hloop_process_ios(loop, blocktime_ms);
} else {
hv_msleep(blocktime_ms);
}
hloop_update_time(loop);
// wakeup by hloop_stop
if (loop->status == HLOOP_STATUS_STOP) {
return 0;
}
process_timers:
//处理定时器,并加入pendding队列,真正触发cb的是hloop_process_pendings
if (loop->ntimers) {
ntimers = hloop_process_timers(loop);
}
//如果不存pending事件,则触发idles事件
int npendings = loop->npendings;
if (npendings == 0) {
if (loop->nidles) {
nidles= hloop_process_idles(loop);
}
}
//处理pendding事件
int ncbs = hloop_process_pendings(loop);
// printd("blocktime=%d nios=%d/%u ntimers=%d/%u nidles=%d/%u nactives=%d npendings=%d ncbs=%d\n",
// blocktime, nios, loop->nios, ntimers, loop->ntimers, nidles, loop->nidles,
// loop->nactives, npendings, ncbs);
return ncbs;
}
3.int hloop_process_pendings(hloop_t* loop)
hloop_process_pendings总结
- 根据优先级遍历队列处理加入的pendding事件,如果存在回调则触发回调
lua
int hloop_process_pendings(hloop_t* loop) {
if (loop->npendings == 0) return 0;
hevent_t* cur = NULL;
hevent_t* next = NULL;
int ncbs = 0;
// NOTE: invoke event callback from high to low sorted by priority.
//从高优先级遍历到低优先级,不同优先级的事件放在不同list
for (int i = HEVENT_PRIORITY_SIZE-1; i >= 0; --i) {
cur = loop->pendings[i];
//遍历当前优先级下的所有事件,并且触发回调
while (cur) {
next = cur->pending_next;
if (cur->pending) {
if (cur->active && cur->cb) {
cur->cb(cur);
++ncbs;
}
cur->pending = 0;
// NOTE: Now we can safely delete event marked as destroy.
if (cur->destroy) {
EVENT_DEL(cur);
}
}
cur = next;
}
loop->pendings[i] = NULL;
}
loop->npendings = 0;
return ncbs;
}
至此hloop_run的链路分析完毕。
总结
上述代码分析过程中,发现timer,io均是无锁模式(custom event除外)。得益于loop要求一个loop只能运行在一个线程中
,避免了多线程竞争的问题。hloop_run基于单线程模式禁止跨线程使用loop,将触发事件加入pendding队列,最后由pendding队列统一处理cb。
问题:如果loop基于单线程模式,那么如果作为服务端是怎么实现高并发的呢?
答:参考libhv的 examples/multi-thread 目录下给出了几种常见的多线程/多进程模式的具体写法:
- multi-acceptor-processes:多accept进程模式
- multi-acceptor-threads:多accept线程模式
- one-acceptor-multi-workers:一个accept线程+多worker线程