libev源码解析——I/O模型
? ? ? ? 在《libev源碼解析——總覽》一文中,我們介紹過,libev是一個(gè)基于事件的循環(huán)庫(kù)。本文將介紹其和事件及循環(huán)之間的關(guān)系。(轉(zhuǎn)載請(qǐng)指明出于breaksoftware的csdn博客)
? ? ? ? 目前ibev支持如下IO事件模型:
- select模型。對(duì)應(yīng)文件是ev_select.c。
- poll模型。對(duì)應(yīng)文件是ev_poll.c。
- epoll模型。對(duì)應(yīng)的文件是ev_epoll.c。
- port模型。對(duì)應(yīng)文件是ev_port.c。
- kqueue模型。對(duì)應(yīng)的文件是ev_kqueue.c。
- iocp模型。即IO完成端口模型(I/O Completion Port)。
? ? ? ? 這些模型并不是我們這個(gè)系列介紹的重點(diǎn)。如果想了解select、poll、epoll模型,可以參閱《樸素、Select、Poll和Epoll網(wǎng)絡(luò)編程模型實(shí)現(xiàn)和分析》系列博文。(下圖是select模型的調(diào)用邏輯圖)
? ? ? ??
? ? ? ? 此處我們只要知道它們是libev可選的事件模型即可。至于選擇什么模型。要視loop_init的入?yún)lags。
static void noinline ecb_cold
loop_init (EV_P_ unsigned int flags) EV_THROW
{
……
#if EV_USE_IOCPif (!backend && (flags & EVBACKEND_IOCP )) backend = iocp_init (EV_A_ flags);
#endif
#if EV_USE_PORTif (!backend && (flags & EVBACKEND_PORT )) backend = port_init (EV_A_ flags);
#endif
#if EV_USE_KQUEUEif (!backend && (flags & EVBACKEND_KQUEUE)) backend = kqueue_init (EV_A_ flags);
#endif
#if EV_USE_EPOLLif (!backend && (flags & EVBACKEND_EPOLL )) backend = epoll_init (EV_A_ flags);
#endif
#if EV_USE_POLLif (!backend && (flags & EVBACKEND_POLL )) backend = poll_init (EV_A_ flags);
#endif
#if EV_USE_SELECTif (!backend && (flags & EVBACKEND_SELECT)) backend = select_init (EV_A_ flags);
#endif
……
}
? ? ? ? backend是一個(gè)用于記錄libev使用的是哪種IO模型的標(biāo)記位。
? ? ? ? 在每個(gè)模型初始化函數(shù)中,都需要指定兩個(gè)模型相關(guān)的函數(shù)指針。比如epoll模型的初始化函數(shù)epoll_init中
int inline_size
epoll_init (EV_P_ int flags)
{
……backend_mintime = 1e-3; /* epoll does sometimes return early, this is just to avoid the worst */backend_modify = epoll_modify;backend_poll = epoll_poll;
……
}
? ? ? ? 而在select模型中則是
int inline_size
select_init (EV_P_ int flags)
{backend_mintime = 1e-6;backend_modify = select_modify;backend_poll = select_poll;
……
}
? ? ? ? backend_mintime是需要等待事件的超時(shí)秒數(shù);backend_modify是輪詢中修改事件信息的函數(shù)。backend_poll則是等待事件的函數(shù)。libev通過上述四個(gè)變量,隔離了不同模型選擇導(dǎo)致不同函數(shù)調(diào)用的問題。
? ? ? ? 但是這兒需要指出的是,libev并沒有將這種隔離做徹底。因?yàn)樵陉P(guān)閉IO模型時(shí),它仍然依靠backend的值,調(diào)用了不同函數(shù)(ev_loop_destroy中)
#if EV_USE_IOCPif (backend == EVBACKEND_IOCP ) iocp_destroy (EV_A);
#endif
#if EV_USE_PORTif (backend == EVBACKEND_PORT ) port_destroy (EV_A);
#endif
#if EV_USE_KQUEUEif (backend == EVBACKEND_KQUEUE) kqueue_destroy (EV_A);
#endif
#if EV_USE_EPOLLif (backend == EVBACKEND_EPOLL ) epoll_destroy (EV_A);
#endif
#if EV_USE_POLLif (backend == EVBACKEND_POLL ) poll_destroy (EV_A);
#endif
#if EV_USE_SELECTif (backend == EVBACKEND_SELECT) select_destroy (EV_A);
#endif
? ? ? ? 個(gè)人認(rèn)為,可以在各個(gè)模型的初始化中,將其對(duì)應(yīng)的銷毀函數(shù)指針賦值給一個(gè)叫backend_destory的變量。這樣上述代表就可以變成一行了。
? ? ? ? 結(jié)合《libev源碼解析——調(diào)度策略》的內(nèi)容,我們可以用下圖表達(dá)出libev運(yùn)轉(zhuǎn)的大體流程。
? ? ? ? 針對(duì)上圖,可能有人會(huì)問:為什么backend_poll函數(shù)需要指定超時(shí)?我們讓其一直等待到有事件發(fā)生不是更好么?
? ? ? ? 還有人會(huì)問:“符合條件的監(jiān)視器”是否可以表述為“本次觸發(fā)事件對(duì)應(yīng)的監(jiān)視器”?
? ? ? ? 對(duì)于這些問題,我們將在之后章節(jié)給出答案。
總結(jié)
以上是生活随笔為你收集整理的libev源码解析——I/O模型的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: libev源码解析——调度策略
- 下一篇: libev源码解析——定时器原理