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 }  
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值