成都創(chuàng)新互聯(lián)是一家專業(yè)提供浦東企業(yè)網(wǎng)站建設(shè),專注與做網(wǎng)站、成都網(wǎng)站設(shè)計(jì)、H5開發(fā)、小程序制作等業(yè)務(wù)。10年已為浦東眾多企業(yè)、政府機(jī)構(gòu)等服務(wù)。創(chuàng)新互聯(lián)專業(yè)網(wǎng)站建設(shè)公司優(yōu)惠進(jìn)行中。
Epoll是Linux IO多路復(fù)用的管理機(jī)制。作為現(xiàn)在Linux平臺(tái)高性能網(wǎng)絡(luò)IO必要的組件。內(nèi)核的實(shí)現(xiàn)可以參照:fs/eventpoll.c .
為什么需要自己實(shí)現(xiàn)epoll呢?現(xiàn)在自己打算做一個(gè)用戶態(tài)的協(xié)議棧。采用單線程的模式。https://github.com/wangbojing/NtyTcp,至于為什么要實(shí)現(xiàn)用戶態(tài)協(xié)議棧?可以自行百度C10M的問(wèn)題。
由于協(xié)議棧做到了用戶態(tài)故需要自己實(shí)現(xiàn)高性能網(wǎng)絡(luò)IO的管理。所以epoll就自己實(shí)現(xiàn)一下。代碼:https://github.com/wangbojing/NtyTcp/blob/master/src/nty_epoll_rb.c
?
在實(shí)現(xiàn)epoll之前,先得好好理解內(nèi)核epoll的運(yùn)行原理。內(nèi)核的epoll可以從四方面來(lái)理解。
1.?????Epoll的數(shù)據(jù)結(jié)構(gòu),rbtree對(duì)
2.?????Epoll的線程安全,SMP的運(yùn)行,以及防止死鎖。
3.?????Epoll內(nèi)核回調(diào)。
4.?????Epoll的LT(水平觸發(fā))與ET(邊沿觸發(fā))
下面從這四個(gè)方面來(lái)實(shí)現(xiàn)epoll。
Epoll主要由兩個(gè)結(jié)構(gòu)體:eventpoll與epitem。Epitem是每一個(gè)IO所對(duì)應(yīng)的的事件。比如 epoll_ctl EPOLL_CTL_ADD操作的時(shí)候,就需要?jiǎng)?chuàng)建一個(gè)epitem。Eventpoll是每一個(gè)epoll所對(duì)應(yīng)的的。比如epoll_create 就是創(chuàng)建一個(gè)eventpoll。
Epitem的定義
Eventpoll的定義
數(shù)據(jù)結(jié)構(gòu)如下圖所示。
List 用來(lái)存儲(chǔ)準(zhǔn)備就緒的IO。對(duì)于數(shù)據(jù)結(jié)構(gòu)主要討論兩方面:insert與remove。同樣如此,對(duì)于list我們也討論insert與remove。何時(shí)將數(shù)據(jù)插入到list中呢?當(dāng)內(nèi)核IO準(zhǔn)備就緒的時(shí)候,則會(huì)執(zhí)行epoll_event_callback的回調(diào)函數(shù),將epitem添加到list中。
那何時(shí)刪除list中的數(shù)據(jù)呢?當(dāng)epoll_wait激活重新運(yùn)行的時(shí)候,將list的epitem逐一copy到events參數(shù)中。
Rbtree用來(lái)存儲(chǔ)所有io的數(shù)據(jù),方便快速通io_fd查找。也從insert與remove來(lái)討論。
對(duì)于rbtree何時(shí)添加:當(dāng)App執(zhí)行epoll_ctl EPOLL_CTL_ADD操作,將epitem添加到rbtree中。何時(shí)刪除呢?當(dāng)App執(zhí)行epoll_ctl EPOLL_CTL_DEL操作,將epitem添加到rbtree中。
List與rbtree的操作又如何做到線程安全,SMP,防止死鎖呢?
?
?
Epoll 從以下幾個(gè)方面是需要加鎖保護(hù)的。List的操作,rbtree的操作,epoll_wait的等待。
List使用最小粒度的鎖spinlock,便于在SMP下添加操作的時(shí)候,能夠快速操作list。
List添加
346行:獲取spinlock。
347行:epitem 的rdy置為1,代表epitem已經(jīng)在就緒隊(duì)列中,后續(xù)再觸發(fā)相同事件就只需更改event。
348行:添加到list中。
349行:將eventpoll的rdnum域 加1。
350行:釋放spinlock
?
List刪除
301行:獲取spinlock
304行:判讀rdnum與maxevents的大小,避免event溢出。
307行:循環(huán)遍歷list,判斷添加list不能為空
309行:獲取list首個(gè)結(jié)點(diǎn)
310行:移除list首個(gè)結(jié)點(diǎn)。
311行:將epitem的rdy域置為0,標(biāo)識(shí)epitem不再就緒隊(duì)列中。
313行:copy epitem的event到用戶空間的events。
316行:copy數(shù)量加1
317行:eventpoll中rdnum減一。
避免SMP體系下,多核競(jìng)爭(zhēng)。此處采用自旋鎖,不適合采用睡眠鎖。
?
Rbtree的添加
149行:獲取互斥鎖。
153行:查找sockid的epitem是否存在。存在則不能添加,不存在則可以添加。
160行:分配epitem。
167行:sockid賦值
168行:將設(shè)置的event添加到epitem的event域。
170行:將epitem添加到rbrtree中。
173行:釋放互斥鎖。
?
Rbtree刪除:
177行:獲取互斥鎖。
181行:刪除sockid的結(jié)點(diǎn),如果不存在,則rbtree返回-1。
188行:釋放epitem
190行:釋放互斥鎖。
?
Epoll_wait的掛起。
采用pthread_cond_wait,具體實(shí)現(xiàn)可以參照。
https://github.com/wangbojing/NtyTcp/blob/master/src/nty_epoll_rb.c
?
?
Epoll 的回調(diào)函數(shù)何時(shí)執(zhí)行,此部分需要與Tcp的協(xié)議棧一起來(lái)闡述。Tcp協(xié)議棧的時(shí)序圖如下圖所示,epoll從協(xié)議?;卣{(diào)的部分從下圖的編號(hào)1,2,3,4。具體Tcp協(xié)議棧的實(shí)現(xiàn),后續(xù)從另外的文章中表述出來(lái)。下面分別對(duì)四個(gè)步驟詳細(xì)描述
編號(hào)1:是tcp三次握手,對(duì)端反饋ack后,socket進(jìn)入rcvd狀態(tài)。需要將監(jiān)聽socket的event置為EPOLLIN,此時(shí)標(biāo)識(shí)可以進(jìn)入到accept讀取socket數(shù)據(jù)。
編號(hào)2:在established狀態(tài),收到數(shù)據(jù)以后,需要將socket的event置為EPOLLIN狀態(tài)。
編號(hào)3:在established狀態(tài),收到fin時(shí),此時(shí)socket進(jìn)入到close_wait。需要socket的event置為EPOLLIN。讀取斷開信息。
編號(hào)4:檢測(cè)socket的send狀態(tài),如果對(duì)端cwnd>0是可以,發(fā)送的數(shù)據(jù)。故需要將socket置為EPOLLOUT。
所以在此四處添加EPOLL的回調(diào)函數(shù),即可使得epoll正常接收到io事件。
LT(水平觸發(fā))與ET(邊沿觸發(fā))是電子信號(hào)里面的概念。不清楚可以man epoll查看的。如下圖所示:
比如:event = EPOLLIN | EPOLLLT,將event設(shè)置為EPOLLIN與水平觸發(fā)。只要event為EPOLLIN時(shí)就能不斷調(diào)用epoll回調(diào)函數(shù)。
比如: event = EPOLLIN | EPOLLET,event如果從EPOLLOUT變化為EPOLLIN的時(shí)候,就會(huì)觸發(fā)。在此情形下,變化只發(fā)生一次,故只調(diào)用一次epoll回調(diào)函數(shù)。關(guān)于水平觸發(fā)與邊沿觸發(fā)放在epoll回調(diào)函數(shù)執(zhí)行的時(shí)候,如果為EPOLLET(邊沿觸發(fā)),與之前的event對(duì)比,如果發(fā)生改變則調(diào)用epoll回調(diào)函數(shù),如果為EPOLLLT(水平觸發(fā)),則查看event是否為EPOLLIN,即可調(diào)用epoll回調(diào)函數(shù)。
BAT, 滴滴,今日頭條,美圖,美團(tuán)等一線內(nèi)推 技術(shù)崗位內(nèi)推?
QQ群:935760465