5.那些队列,那些队列操作函数(2)

5.那些队列,那些队列操作函数(2)

从队列里删除一个元素,并且将该元素做初始化,首先看__list_del():

 
 
  1. 155 static inline void __list_del(struct list_head * prev, struct list_head * next)  
  2. 156 {  
  3. 157     next->prevprev = prev;  
  4. 158     prev->nextnext = next;  
  5. 159 }  

INIT_LIST_HEAD()其实就是初始化为最初的状态,即一个空链表。如下:
 
 
  1. 30 static inline void INIT_LIST_HEAD(struct list_head *list)  
  2. 31 {  
  3. 32          list->next = list;  
  4. 33      list->prev = list;  
  5. 34 }  

当然了,还有一个超级经典的list_entry(),和以上所有list方面的宏一样,也是来自include/linux/list.h:
 
 
  1. 425 #define list_entry(ptr, type, member) \  
  2. 426         container_of(ptr, type, member)  

我相信,list_entry()这个宏在Linux内核代码中的地位都是耳熟能详的,如果你说你不知道list_entry(),那你千万别跟人说你懂Linux内核。

list_entry这个宏应该说还是有一定技术含量的。

关于list_entry(),让我们结合实例来看,在hub的故事里会接触到的一个重要的数据结构就是struct usb_hub,来自drivers/usb/core/hub.c:

 
 
  1. 34 struct usb_hub {  
  2. 35      struct device           *intfdev;       /* the "interface" device */  
  3. 36      struct usb_device       *hdev;  
  4. 37      struct urb              *urb;         /* for interrupt polling pipe */  
  5. 38  
  6. 39      /* buffer for urb ... with extra space in case of babble */  
  7. 40      char                    (*buffer)[8];  
  8. 41      dma_addr_t              buffer_dma;     /* DMA address for buffer */  
  9. 42      union {  
  10. 43              struct usb_hub_status   hub;  
  11. 44              struct usb_port_status  port;  
  12. 45          }          *status;        /* buffer for status reports */  
  13. 46      struct mutex            status_mutex;   /* for the status buffer */  
  14. 47  
  15. 48      int                     error;          /* last reported error */  
  16. 49      int                     nerrors;        /* track consecutive errors */  
  17. 50  
  18. 51      struct list_head        event_list;   /* hubs w/data or errs ready */  
  19. 52      unsigned long           event_bits[1];  /* status change bitmask */  
  20. 53      unsigned long           change_bits[1]; /* ports with logical connect  
  21. 54                                                         status change */  
  22. 55      unsigned long           busy_bits[1];   /* ports being reset or  
  23. 56                                                         resumed */  
  24. 57 #if USB_MAXCHILDREN > 31 /* 8*sizeof(unsigned long) - 1 */  
  25. 58 #error event_bits[] is too short!  
  26. 59 #endif  
  27. 60  
  28. 61      struct usb_hub_descriptor *descriptor;  /* class descriptor */  
  29. 62      struct usb_tt           tt;             /* Transaction Translator */  
  30. 63  
  31. 64      unsigned                mA_per_port;    /* current for each child */  
  32. 65  
  33. 66      unsigned                limited_power:1;  
  34. 67      unsigned                quiescing:1;  
  35. 68      unsigned                activating:1;  
  36. 69  
  37. 70      unsigned                has_indicators:1;  
  38. 71      u8                      indicator[USB_MAXCHILDREN];  
  39. 72      struct delayed_work     leds;  
  40. 73 };  

看到了吗,51行,struct list_head event_list,这个结构体变量将为我们组建一个队列,或者说组建一个链表。我们知道,一个struct usb_hub代表一个Hub,每一个struct usb_hub有一个event_list,即每一个Hub都有它自己的一个事件列表。要知道Hub可以有一个或者多个,而Hub驱动只需要一个,或者说khubd这个精灵进程永远都只有一个。而我们的做法是,不管实际上有多少个Hub,我们最终都会将其event_list挂入到全局链表hub_event_list中来统一处理(hub_event_list是对于整个USB系统来说是全局的,但对于整个内核来说当然是局部的,毕竟它前面有一个static)。

因为最终处理所有Hub事务的都是这一个精灵进程khubd,它只需要判断hub_event_list是否为空,不为空就去处理。或者说就去触发hub_events()函数,但当我们真的要处理Hub的事件时,当然要知道具体是哪个Hub触发了这起事件。而list_entry的作用就是,从struct list_head event_list得到它所对应的struct usb_hub结构体变量。比如以下的四行代码:

 
 
  1. struct list_head *tmp;  
  2. struct usb_hub *hub;  
  3. tmp=hub_event_list.next;  
  4. hub=list_entry(tmp,struct usb_hub,event_list);  

从全局链表hub_event_list中取出一个来,叫做tmp,然后通过tmp获得它所对应的struct usb_hub。

最后是总结,中学我们学习写议论文时,老师教过这样几种结构:总分总式结构、对照式结构、层进式结构和并列式结构。而总分总式结构就是先提出中心论点,然后围绕中心,以不同角度提出分论点,展开论述,最后进行总结。而总分总具体来说又有总分、分总、总分总三种形式。

以前我以为Linus只是技术比我强,现在我算是看明白了,语文学得也比我好。看出来了吗?这里采用的就是我们议论文中的总分总结构,先设置一个链表hub_event_list,设置一个总的函数hub_events(),这是"总";然后每一个Hub都有一个event_list,每当有一个hub的event_list出现了变化,就把它的event_list插入到hub_event_list中来,这是"分";然后触发总函数hub_events(),这又是"总";然后在hub_events()里又根据event_list来确定是哪个struct usb_hub,或者说是哪个Hub有问题,又针对该Hub进行具体处理,这又是"分"。这就是Linux中Hub驱动的中心思想。

最后,提醒各位读者,struct usb_hub在这里介绍了,稍后讲到这个结构体时就不会再介绍了。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值