5.那些隊列,那些隊列操作函數(1)
這一節我們講隊列。
隨着子進程進入了我們的視野,我們來看其入口函數hub_thread(),這是一個令你大跌隱形眼鏡的函數。
- 2817 static int hub_thread(void *__unused)
- 2818 {
- 2819 do {
- 2820 hub_events();
- 2821 wait_event_interruptible(khubd_wait,
- 2822 !list_empty(&hub_event_list) ||
- 2823 kthread_should_stop());
- 2824 try_to_freeze();
- 2825 } while (!kthread_should_stop() || !list_empty(&hub_event_list));
- 2826
- 2827 pr_debug("%s: khubd exiting\n", usbcore_name);
- 2828 return 0;
- 2829 }
這就是Hub驅動中最精華的代碼。這幾乎是一個死循環,但是關於Hub的所有故事都發生在這裏,沒錯,就在這短短几行代碼中。
而這其中,最核心的函數自然是hub_events()。我們先不看hub_events(),先把外面這幾個函數看明白了。kthread_should_stop()的意思很明顯,就是字面意思--是不是該停掉。如果是,那麼這裏循環就結束了,hub_thread()返回0,而要讓kthread_should_stop()爲真,就是當我們調用kthread_stop()時。這種情況,這個進程就該結束了。
再看hub_event_list,同樣來自drivers/usb/core/hub.c:
- 83 static LIST_HEAD(hub_event_list); /* List of hubs needing servicing */
我們來看LIST_HEAD吧,當你越接近那些核心的代碼,你就會發現關於鏈表的定義就會越多。其實在usb-storage裏面,我們也提到過一些鏈表,但卻並沒有自己用LIST_HEAD來定義過鏈表,因爲我們用不着。可是Hub這邊就有用了,當然主機控制器的驅動程序裏也會有。
使用鏈表的目的很明確,因爲有很多事情要做,於是就把它放進鏈表裏,一件事一件事地處理。還記得我們當初在usb-storage裏面提交urb請求了嗎?你的U盤不停地提交urb請求,USB鍵盤也提交,USB鼠標也提交,那USB主機控制器怎麼能應付得過來呢?很簡單,建立一個隊列,然後你每次提交就是往一個隊列裏邊插入,然後USB主機控制器再統一去調度,一個一個來執行。
那麼這裏Hub它有什麼事件?比如探測到一個設備連進來了,於是就會執行一些代碼去初始化設備,所以就建一個隊列。關於Linux內核中的鏈表,可以專門寫一篇文章了,我們簡單介紹,來看include/linux/list.h:
- 21 struct list_head {
- 22 struct list_head *next, *prev;
- 23 };
- 24
- 25 #define LIST_HEAD_INIT(name) { &(name), &(name) }
- 26
- 27 #define LIST_HEAD(name) \
- 28 struct list_head name = LIST_HEAD_INIT(name)
可以看出,我們無非就是定義了一個struct list_head的結構體hub_event_list,而且其兩個指針next和prev分別是指向自己。換而言之,我們建立了一個鏈表,而且是雙向鏈表,並且做了初始化,初始化成一個空隊列。而對於這個隊列的操作,內核提供了很多函數可以使用,不過在Hub中,我們將會用到這麼幾個函數。
- 298 static inline int list_empty(const struct list_head *head)
- 299 {
- 300 return head->next == head;
- 301 }
不言自明,判斷隊列是否爲空。我們說了,初始化時這個hub_event_list隊列是空的。
有了隊列,自然就要操作隊列,要往隊列里加東西、減東西。就像我們每個人每天都在不停地走進去,又走出來。來看第二個函數list_add_tail(),這就是往隊列里加東西:
- 84 static inline void list_add_tail(struct list_head *new, struct list_head *head)
- 85 {
- 86 __list_add(new, head->prev, head);
- 87 }
繼續跟着__list_add()看就會發現其實就是往隊列的末尾加一個元素:
- 43 static inline void __list_add(struct list_head *new,
- 44 struct list_head *prev,
- 45 struct list_head *next)
- 46 {
- 47 next->prev = new;
- 48 new->nextnext = next;
- 49 new->prevprev = prev;
- 50 prev->next = new;
- 51 }
再來看下一個list_del_init(),隊列裏的元素不能只加不減,沒用了的元素就該刪除掉,把空間騰出來給別人:
- 254 static inline void list_del_init(struct list_head *entry)
- 255 {
- 256 __list_del(entry->prev, entry->next);
- 257 INIT_LIST_HEAD(entry);
- 258 }