首頁 系統教程 Linux Linux中的神器:eventfd的原理與應用

Linux中的神器:eventfd的原理與應用

Feb 13, 2024 pm 08:30 PM
技巧 命令 overflow

Linux是一個強大的作業系統,它提供了許多高效的進程間通訊機制,如管道、訊號、訊息佇列、共享記憶體等。但是,有沒有一種更簡單、更靈活、更有效率的溝通方式呢?答案是有的,就是eventfd。 eventfd是Linux 2.6版本引入的一種系統調用,它可以用來實現事件通知,也就是透過一個檔案描述符來傳遞事件。 eventfd包含一個由核心維護的64位元無符號整數計數器,進程可以透過對這個檔案描述子進行read/write來讀取/改變計數器的值,從而實現進程間通訊。 eventfd有什麼優點呢?它有以下幾個特點:

Linux中的神器:eventfd的原理與應用

  • # eventfd不需要建立任何額外的檔案或記憶體空間,只需要一個檔案描述子;
  • eventfd可與select、poll、epoll等多工機制結合使用,實現高效率的事件驅動程式設計;
  • eventfd可以設定為非阻塞或信號量模式,提供了不同的通訊語意;
  • eventfd可以跨越行程或執行緒邊界,實作不同層級的通訊。

那麼,eventfd是如何運作的呢?它又有哪些應用場景呢?本文將從原理和應用兩個面向來介紹eventfd這個神器。

一般來說:Linux進程間通訊有五大方案:管道,訊息隊列,信號量,共享內存,套接字。
管道我不是很熟,只了解一般管道局限與父子進程之間,首先就被我排除了,因為我要做的是相互獨立的進程間通信,命名管道似乎不局限於父子進程,但在內核態怎麼使用不清楚。
訊息隊列完全不了解。
信號量的核心是一個核心變數的原子操作,但介面只體現在用戶態,而且信號量的P V操作更多做的好像是互斥,而不是我想要的通知喚醒機制。
共享記憶體就更麻煩了,介面只在用戶態,如果自己想做內核態與用戶態之間的共享內存,得自己寫file,然後提供mmap接口。
在套接字之前只是用過af_inet的tcp/udp與af_unix的dgram,還是上面的那個問題,內核沒有明確的接口提供,雖然可以自己去用比如sock->ops->recvmsg這樣的函數去調用,但畢竟需要自己構造入參,感覺還是不太安全。

那麼剩下的似乎只有netlink了,這個socket明確地提供了核心的發包函數,因為它明確地export出了netlink_kernel_create函數,所以內核態的函數得以用這個sock來進行發包。但一個是用戶態需要註冊收包函數,另一個核心態發包還是免不了要組裝skb,對於我單純地只想進行通知喚醒來說還是太複雜了。

於是我再次尋找,發現了eventfd這個神器,在KVM與Qemu的通信之間,eventfd被大牛使用的出神入化,仔細地分析了一下源碼,發現這個東西就如名字所說,純是為了通知而存在的。
作為一個file(linux裡有不是file的東西麼~~),它的private_data結構體 eventfd_ctx只有可憐的四個變數。

struct eventfd_ctx {
  struct kref kref;  /* 这个就不多说了,file计数用的,用于get/put */
  wait_queue_head_t wqh; /* 这个用来存放用户态的进程wait项,有了它通知机制才成为可能 */
/*
\* Every time that a write(2) is performed on an eventfd, the
\* value of the __u64 being written is added to "count" and a
\* wakeup is performed on "wqh". A read(2) will return the "count"
\* value to userspace, and will reset "count" to zero. The kernel
\* side eventfd_signal() also, adds to the "count" counter and
\* issue a wakeup.
*/
  __u64 count;  /* 这个就是一个技术器,应用程序可以自己看着办,read就是取出然后清空,write就是把value加上 */
  unsigned int flags;  /* 所有的file都有的吧,用来存放阻塞/非阻塞标识或是O_CLOEXEC之类的东西 */
};
  我之所以选用它是因为它有 eventfd_signal 这个特地为内核态提供的接口,下面的是注释。
 \* This function is supposed to be called by the kernel in paths that do not
 \* allow sleeping. In this function we allow the counter to reach the ULLONG_MAX
 \* value, and we signal this as overflow condition by returining a POLLERR to poll(2).
登入後複製

其實看程式碼會更清晰一些

int eventfd_signal(struct eventfd_ctx *ctx, int n)
{
  unsigned long flags;

  if (n return -EINVAL;
  spin_lock_irqsave(&ctx->wqh.lock, flags);
  if (ULLONG_MAX - ctx->count count);
  ctx->count += n;
  if (waitqueue_active(&ctx->wqh))
    wake_up_locked_poll(&ctx->wqh, POLLIN);
  spin_unlock_irqrestore(&ctx->wqh.lock, flags);

  return n;
}  
登入後複製

本質就是做一次喚醒,不用read,也不用write,與eventfd_write的差別是不用阻塞

#下面說一下我的具體用法:
內核狀態是一個模組,註冊一個misc設備,建立核心執行緒工作(參數為模組的file->private_data)。提供ioctl介面供用戶態進程下發自己eventfd所建立的fd,保存在核心執行緒可以存取的file->private_data中。
當核心態想通知用戶態時,直接使用eventfd_signal,此時用戶態執行緒需要先把自己放在eventfd_ctx->wqh上,有兩個方案,一個是呼叫read,一個是呼叫poll。如果是read,之後會將eventfd_ctx->count清零,下次還能阻塞住。但如果使用poll,之後count並未清零,導致再次poll時,即使核心態沒有eventfd_signal,poll也會即時回傳。
使用者態通知核心態稍微麻煩一點,,首先需要再建立一個eventfd,然後下發給file->private_data(這裡的操作同上面),額外需要在模組裡做一個iotcl,專門負責使用者態來通知核心態,函數裡就做eventfd_signal,內核態線程需要先放在eventfd_ctx->wqh上,可以利用vfs_read,或是自己在核心態做一次poll(似乎又麻煩了)。

本文介紹了eventfd這個Linux中的神器,它是一種簡單、靈活、有效率的進程間通訊機制。我們從原理方面分析了eventfd的創建、讀寫和標誌位等內容,並且給出了相應的程式碼範例。我們也從應用方面介紹了eventfd在用戶態與內核態通訊、定時器和事件觸發器等場景中的使用方法,並且給出了對應的程式碼範例。透過本文的學習,我們可以掌握eventfd的基本用法,並且能夠在實際開發中靈活地運用eventfd來實現不同的通訊需求。希望本文對你有幫助!

以上是Linux中的神器:eventfd的原理與應用的詳細內容。更多資訊請關注PHP中文網其他相關文章!

本網站聲明
本文內容由網友自願投稿,版權歸原作者所有。本站不承擔相應的法律責任。如發現涉嫌抄襲或侵權的內容,請聯絡admin@php.cn

熱AI工具

Undresser.AI Undress

Undresser.AI Undress

人工智慧驅動的應用程序,用於創建逼真的裸體照片

AI Clothes Remover

AI Clothes Remover

用於從照片中去除衣服的線上人工智慧工具。

Undress AI Tool

Undress AI Tool

免費脫衣圖片

Clothoff.io

Clothoff.io

AI脫衣器

Video Face Swap

Video Face Swap

使用我們完全免費的人工智慧換臉工具,輕鬆在任何影片中換臉!

熱工具

記事本++7.3.1

記事本++7.3.1

好用且免費的程式碼編輯器

SublimeText3漢化版

SublimeText3漢化版

中文版,非常好用

禪工作室 13.0.1

禪工作室 13.0.1

強大的PHP整合開發環境

Dreamweaver CS6

Dreamweaver CS6

視覺化網頁開發工具

SublimeText3 Mac版

SublimeText3 Mac版

神級程式碼編輯軟體(SublimeText3)

H5頁面製作是前端開發嗎 H5頁面製作是前端開發嗎 Apr 05, 2025 pm 11:42 PM

是的,H5頁面製作是前端開發的重要實現方式,涉及HTML、CSS和JavaScript等核心技術。開發者通過巧妙結合這些技術,例如使用<canvas>標籤繪製圖形或使用JavaScript控制交互行為,構建出動態且功能強大的H5頁面。

為什麼inline-block元素會出現錯位現象?如何解決這個問題? 為什麼inline-block元素會出現錯位現象?如何解決這個問題? Apr 04, 2025 pm 10:39 PM

關於inline-block元素錯位顯示的原因及解決方案在編寫網頁佈局時,我們常常會遇到一些看似奇怪的顯示問題。比...

如何通過CSS自定義resize符號並使其與背景色統一? 如何通過CSS自定義resize符號並使其與背景色統一? Apr 05, 2025 pm 02:30 PM

CSS自定義resize符號的方法與背景色統一在日常開發中,我們經常會遇到需要自定義用戶界面細節的情況,比如調...

如何使用CSS的clip-path屬性實現分段器的45度曲線效果? 如何使用CSS的clip-path屬性實現分段器的45度曲線效果? Apr 04, 2025 pm 11:45 PM

如何實現分段器的45度曲線效果?在實現分段器的過程中,如何讓點擊左側按鈕時右側邊框變成45度曲線,而點�...

2018-2024年比特幣最新價格美元大全 2018-2024年比特幣最新價格美元大全 Feb 15, 2025 pm 07:12 PM

實時比特幣美元價格 影響比特幣價格的因素 預測比特幣未來價格的指標 以下是 2018-2024 年比特幣價格的一些關鍵信息:

如何實現帶有45度曲線邊框的分段器效果? 如何實現帶有45度曲線邊框的分段器效果? Apr 04, 2025 pm 11:48 PM

實現分段器效果的技巧在用戶界面設計中,分段器是一種常見的導航元素,尤其是在移動應用和響應式網頁中。 ...

如何通過JavaScript或CSS控制瀏覽器打印設置中的頁首和頁尾? 如何通過JavaScript或CSS控制瀏覽器打印設置中的頁首和頁尾? Apr 05, 2025 pm 10:39 PM

如何使用JavaScript或CSS控制瀏覽器打印設置中的頁首和頁尾在瀏覽器的打印設置中,有一個選項可以控制是否顯�...

在移動端如何兼容多行溢出省略? 在移動端如何兼容多行溢出省略? Apr 05, 2025 pm 10:36 PM

移動端多行溢出省略在不同設備上的兼容問題在使用Vue2.0開發移動端應用時,常常會遇到需要對文本進行多行溢...

See all articles