2012-07-04 64 views
12

我正在開發的一個Linux內核驅動程序是在內核中使用網絡通信(sock_create()sock->ops->bind()等)。模擬內核套接字編程中select()和poll()的效果

問題是會有多個套接字接收數據。所以我需要一些能夠在內核空間中模擬select()poll()的東西。由於這些函數使用文件描述符,除非我使用系統調用來創建套接字,否則我不能使用系統調用,但由於我在內核中工作,這似乎沒有必要。

所以我想在我自己的處理程序(custom_sk_data_ready())中包裝默認sock->sk_data_ready處理程序,這將解鎖信號量。然後,我可以編寫我自己的kernel_select()函數來嘗試鎖定信號量並進行阻塞,直到它打開。這樣內核函數進入休眠狀態,直到信號被解鎖custom_sk_data_ready()。一旦kernel_select()獲得鎖定,它將解鎖並呼叫custom_sk_data_ready()重新鎖定它。因此,唯一的附加初始化是在綁定套接字之前運行custom_sk_data_ready(),以便第一次調用custom_select()時不會錯誤觸發。

我看到一個可能的問題。如果發生多個接收,則多次調用custom_sk_data_ready()將嘗試解鎖信號量。所以爲了不丟失多個呼叫並跟蹤正在使用的sock,必須有一個表或指向正在使用的套接字的指針列表。並且custom_sk_data_ready()將不得不在表/列表中標記它傳遞的套接字。

這種方法聽起來嗎?或者,在使用標準系統調用時,我是否應該爲用戶/內核空間問題而煩惱?

初步調查結果:

sock結構中的所有回調函數被調用在中斷上下文。這意味着他們無法入睡。爲了讓主內核線程在就緒套接字列表中休眠,使用互斥鎖,但custom_sk_data_ready()必須像互斥鎖一樣在互斥鎖上重複(重複調用mutex_trylock())。這也意味着任何動態分配都必須使用GFP_ATOMIC標誌。


其他可能性:

對於每一個開放式插槽,替換每個插座的sk_data_ready()有一個自定義(custom_sk_data_ready())和創建工作(struct work_struct)和工作隊列(struct workqueue_struct)。一個普通的process_msg()函數將用於每個工人。創建一個內核模塊級別的全局列表,其中每個列表元素都有一個指向套接字的指針幷包含worker結構。當數據在套接字上準備就緒時,custom_sk_data_ready()將執行並使用相同的套接字找到匹配的列表元素,然後使用list元素的工作隊列和worker調用queue_work()。然後將調用process_msg()函數,並且可以通過struct work_struct *參數(地址)的內容找到匹配的列表元素,或者使用container_of()宏來獲取保存worker結構的列表結構的地址。

哪種技術最健全?

+0

難道你不能有一個用戶空間幫助程序做'poll'嗎?使用'poll'或'select'複用輸入與調度程序有關(因爲暫停過程是空閒的,所以其他進程可以運行),所以我不會在內核中這樣做! –

+1

@BasileStarynkevitch:這就是爲什麼我只是試圖模擬'poll()'和'select()'的睡眠阻塞。使用來自內核的這兩個系統調用是最後的手段。我懷疑在用戶空間助手中運行'poll()'和'select()'有問題。該助手必須能夠訪問文件描述符(這不是在'sock_create()'中完成的),並且可能有權訪問駐留在內核空間中的套接字。所以現在套接字的創建必須發生在用戶空間助手中,並且模塊必須根據用戶空間文件描述符找到套接字。現在它變得更加複雜。 – Joshua

+0

你不應該在內核中做任何事情。 – mpe

回答

3

你的第二個想法聽起來更像它的工作。

CEPH代碼看起來像它做類似的事情,請參閱net/ceph/messenger.c