5.那些隊列,那些隊列操作函數(1)

5.那些隊列,那些隊列操作函數(1)

這一節我們講隊列。

隨着子進程進入了我們的視野,我們來看其入口函數hub_thread(),這是一個令你大跌隱形眼鏡的函數。

  1. 2817 static int hub_thread(void *__unused)  
  2. 2818 {  
  3. 2819    do {  
  4. 2820        hub_events();  
  5. 2821        wait_event_interruptible(khubd_wait,  
  6. 2822                            !list_empty(&hub_event_list) ||  
  7. 2823                            kthread_should_stop());  
  8. 2824            try_to_freeze();  
  9. 2825    } while (!kthread_should_stop() || !list_empty(&hub_event_list));  
  10. 2826  
  11. 2827    pr_debug("%s: khubd exiting\n", usbcore_name);  
  12. 2828    return 0;  
  13. 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:

  1. 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:

  1. 21 struct list_head {  
  2. 22      struct list_head *next, *prev;  
  3. 23 };  
  4. 24  
  5. 25 #define LIST_HEAD_INIT(name) { &(name), &(name) }  
  6. 26  
  7. 27 #define LIST_HEAD(name) \  
  8. 28         struct list_head name = LIST_HEAD_INIT(name)  

可以看出,我們無非就是定義了一個struct list_head的結構體hub_event_list,而且其兩個指針next和prev分別是指向自己。換而言之,我們建立了一個鏈表,而且是雙向鏈表,並且做了初始化,初始化成一個空隊列。而對於這個隊列的操作,內核提供了很多函數可以使用,不過在Hub中,我們將會用到這麼幾個函數。
  1. 298 static inline int list_empty(const struct list_head *head)  
  2. 299 {  
  3. 300         return head->next == head;  
  4. 301 }  

不言自明,判斷隊列是否爲空。我們說了,初始化時這個hub_event_list隊列是空的。

有了隊列,自然就要操作隊列,要往隊列里加東西、減東西。就像我們每個人每天都在不停地走進去,又走出來。來看第二個函數list_add_tail(),這就是往隊列里加東西:

  1. 84 static inline void list_add_tail(struct list_head *new, struct list_head *head)  
  2. 85 {  
  3. 86      __list_add(new, head->prev, head);  
  4. 87 }  

繼續跟着__list_add()看就會發現其實就是往隊列的末尾加一個元素:

  1. 43 static inline void __list_add(struct list_head *new,  
  2. 44                               struct list_head *prev,  
  3. 45                               struct list_head *next)  
  4. 46 {  
  5. 47          next->prev = new;  
  6. 48      new->nextnext = next;  
  7. 49      new->prevprev = prev;  
  8. 50      prev->next = new;  
  9. 51 }  

再來看下一個list_del_init(),隊列裏的元素不能只加不減,沒用了的元素就該刪除掉,把空間騰出來給別人:
  1. 254 static inline void list_del_init(struct list_head *entry)  
  2. 255 {  
  3. 256         __list_del(entry->prev, entry->next);  
  4. 257     INIT_LIST_HEAD(entry);  
  5. 258 }  
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章