1. 程式人生 > >【Linux深入】epoll原始碼的函式呼叫流程分析(圖)

【Linux深入】epoll原始碼的函式呼叫流程分析(圖)

引入

  • 我在上一篇博文中講了epoll原始碼的剖析,你是不是看的有點懵呢,反正我是有點,接下來我就以流程圖的形式梳理一下epoll原始碼的結構。

  • 當然,這篇博文是建立在上一篇博文的基礎上,若你還沒看過epoll原始碼,那麼我建議你最好還是看一下,請點選【Linux深入】epoll原始碼剖析

  • 接下來我就以流程圖的形式介紹一下函式的呼叫過程。

整體的資料結構圖

這裡寫圖片描述

注:圖中黃色和綠色方框表示連結串列關係,而粉色代表等待佇列。

主要的函式呼叫圖

1.epoll_create()

這裡寫圖片描述

分析:

  • epoll_create()函式沒有什麼實際作用,它僅有的一個size引數沒有,它的主要功能是通過epoll_create1()函式來完成的

  • epoll_create1()函式通過ep_alloc生成一個eventpoll物件,並初始化eventpoll的三個等待佇列,wait,poll_wait以及rdlist (ready的fd list)。同時還會初始化被監視fs的rbtree 根節點。

  • epoll_create1()在呼叫ep_alloc通過anon_inode_getfd建立一個名字為“[eventpoll]”的eventpollfs檔案描述符號並將file->private_data指定為指向前面生成的eventpoll。這樣就將eventpoll和檔案id關聯。最後返回檔案描述符id

2.epoll_ctl()

這裡寫圖片描述

  • epoll_ctl函式

    • 通過epoll_create生成一個eventpoll後,可以通過epoll_ctl提供的相關操作對eventpoll進行ADD,MOD,DEL操作。
    • epoll_ctl首先通過epfd的private_data域獲取需要操作的eventpoll,然後通過ep_find確認需要操作的fd是否已經在被監視的紅黑樹中(eventpoll->rbr)。然後根據op的型別分別作ADD(ep_insert),MOD(ep_modify),DEL(ep_remove)操作。
  • ep_insert()

    • 從slub中分配一個epitem的物件epitem。並初始化epitem的三個list頭指標,rdllink(指向eventpoll的rdlist),fllist指向(struct file的f_ep_links),pwqlist(指向包含此epitem的所有poll wait queue)。將epitem的ep指標,指向傳入的eventpoll,
    • 通過傳入引數event對ep內部變數event賦值。然後通過ep_set_ffd將目標檔案和epitem關聯。這樣epitem本身就完成了和eventpoll以及被監視檔案的關聯。下面還需要做兩個動作:將epitem插入目標檔案的polllist並註冊回撥函式;將epitem插入eventpoll的rbtree。
  • Poll()函式是系統函式,一般由裝置驅動提供。

  • poll_wait()函式呼叫 ep_ptable_queue_proc()函式

  • ep_ptable_queue_proc()主要功能是使用等待佇列實現epitem和callback函式的關聯。然後通過目標檔案的poll函式呼叫callback函式。

  • ep_poll_callback()函式

    • 當fd狀態改變時(感興趣事件),呼叫該函式,
    • 首先會把檔案描述符epitem 放到eventpoll 的rdllist中
    • 然後呼叫wake_up函式喚醒epitem上wq的程序。這樣就可以返回到epoll_wait的呼叫者,將他喚醒。

3.epoll_wait()

這裡寫圖片描述

  • epoll_wait()函式

    • 首先會檢測傳入引數的合法性;events指向的空間是否可寫;epfd是否合法等。引數合法性檢測都通過後,將通過epfd獲取鎖依賴的struct file,
    • 然後通過file->private_data獲取eventpoll。獲取epoll後呼叫ep_poll函式完成真正的epoll_wait工作。
  • ep_poll()函式

    • 首先根據timeout的值判斷是否是無限等待,如果不是將timeout(ms)轉換為jiffs。
    • 然後判斷eventpoll的rdlist是否為空,如果為空,那麼將current程序通過一個waitquene entry加入eventpoll的waitlist(wq)。如果rdlist非空,那麼通過ep_send_events將event轉發到使用者空間。
  • ep_send_events函式呼叫ep_scan_ready_list對ready_list進行掃描

  • ep_scan_ready_list對ready_list進行掃描。將所有的epitem都轉移到了txlist上, 而rdllist被清空了。然後呼叫ep_send_events_proc()函式。

  • ep_send_events_proc掃描rdlist從頭上面拿出epitem,然後呼叫ep_eventpoll_poll函式,完成轉發。
    先把就緒事件連結串列轉移到中間連結串列,然後挨個遍歷拷貝到使用者空間,並且挨個判斷其是否為水平觸發,是的話再次插入到就緒連結串列

4.全部函式的的呼叫關係圖

這裡寫圖片描述

注:忽略藍色豎線,手當時抖了一下,多加了一條線。



本人才疏學淺,若有錯,請指出,謝謝!
如果你有更好的建議,可以留言我們一起討論,共同進步!
衷心的感謝您能耐心的讀完本篇博文!