博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
内核中的list相关
阅读量:3558 次
发布时间:2019-05-20

本文共 18212 字,大约阅读时间需要 60 分钟。

linux内核有很多优秀的代码...

比如list

 

这是一个双向链表。

先贴个好文章...

 


先看下list_head的结构体,

/*                                                                                                                                                                                  * Simple doubly linked list implementation.                                                                                                                                        *                                                                                                                                                                                  * Some of the internal functions ("__xxx") are useful when                                                                                                                         * manipulating whole lists rather than single entries, as                                                                                                                          * sometimes we already know the next/prev entries and we can                                                                                                                       * generate better code by using them directly rather than                                                                                                                          * using the generic single-entry routines.                                                                                                                                         */                                                                                                                                                                                                                                                                                                                                                                   struct list_head {                                                                                                                                                                 ›   struct list_head *next, *prev;                                                                                                                                                 };

非常简单, 就记录了两个指针, 一个指向前面节点, 一个指向后面节点。


以dwc3驱动为例, 看下list如何使用。

static int dwc3_gadget_init_endpoints(struct dwc3 *dwc, u8 total){	struct dwc3_ep			*dep;	u8				epnum;	INIT_LIST_HEAD(&dwc->gadget.ep_list);

初始化端点时, 初始化了一个list_head, 叫ep_list

 

看下INIT_LIST_HEAD宏,

25 static inline void INIT_LIST_HEAD(struct list_head *list)                                                                            26 {                                                                                                                                    27 ›   list->next = list;                                                                                                               28 ›   list->prev = list;                                                                                                               29 }

即该list_head的prev, next指针都指向自己。

也就是说这个list目前是空的。

 

端点初始化函数中, 继续往下翻,

if (num == 0) {			usb_ep_set_maxpacket_limit(&dep->endpoint, 512);			dep->endpoint.maxburst = 1;			dep->endpoint.ops = &dwc3_gadget_ep0_ops;			if (!direction)				dwc->gadget.ep0 = &dep->endpoint;		} else if (direction) {			int mdwidth;			int kbytes;			int size;			int ret;			mdwidth = DWC3_MDWIDTH(dwc->hwparams.hwparams0);			/* MDWIDTH is represented in bits, we need it in bytes */			mdwidth /= 8;			size = dwc3_readl(dwc->regs, DWC3_GTXFIFOSIZ(num));			size = DWC3_GTXFIFOSIZ_TXFDEF(size);			/* FIFO Depth is in MDWDITH bytes. Multiply */			size *= mdwidth;			kbytes = size / 1024;			if (kbytes == 0)				kbytes = 1;			/*			 * FIFO sizes account an extra MDWIDTH * (kbytes + 1) bytes for			 * internal overhead. We don't really know how these are used,			 * but documentation say it exists.			 */			size -= mdwidth * (kbytes + 1);			size /= kbytes;			usb_ep_set_maxpacket_limit(&dep->endpoint, size);			dep->endpoint.max_streams = 15;			dep->endpoint.ops = &dwc3_gadget_ep_ops;			list_add_tail(&dep->endpoint.ep_list,					&dwc->gadget.ep_list);			ret = dwc3_alloc_trb_pool(dep);			if (ret)				return ret;		} else {			int		ret;			usb_ep_set_maxpacket_limit(&dep->endpoint, 1024);			dep->endpoint.max_streams = 15;			dep->endpoint.ops = &dwc3_gadget_ep_ops;			list_add_tail(&dep->endpoint.ep_list,					&dwc->gadget.ep_list);			ret = dwc3_alloc_trb_pool(dep);			if (ret)				return ret;		}

这里有些逻辑, 有两处list_add_tail, 总的来说就是描述好IN, OUT的端点, 然后放入gadget.ep_list中。

其中由于ep0是一个双向的端点, 所以需要两个端点物理资源。



那合适会用到这些端点呢?

 

很好理解, 作为主机端, 肯定是不需要的, 这些端点初始化函数都不会走到。

作为设备端,  当用户具体配置设备时,  就需要使用端点了。

比如配置一个msc storage设备, 肯定需要一个bulk in, 一个bulk out两个端点。以及默认的控制端点。

如果配置一个虚拟串口驱动, 除了控制端点,还需要bulk in, bulk out和一个interrupt中断端点。

 

所以最终调用的地方有, usb_ep_autoconfig_ss函数。

67 struct usb_ep *usb_ep_autoconfig_ss(                                                                                                 68 ›   struct usb_gadget›  ›   *gadget,                                                                                                 69 ›   struct usb_endpoint_descriptor› *desc,                                                                                           70 ›   struct usb_ss_ep_comp_descriptor *ep_comp ......  116 ›   /* Second, look at endpoints until an unclaimed one looks usable */                                                             117 ›   list_for_each_entry (ep, &gadget->ep_list, ep_list) {                                                                         + 118         // printk("(%d) ep->claimed = %d\n", count++, ep->claimed);                                                                 119 ›   ›   if (usb_gadget_ep_match_desc(gadget, ep, desc, ep_comp))                                                                    120 ›   ›   ›   goto found_ep;                                                                                                          121 ›   }

list_for_each_entry, 看下函数原型

440 /**                                                                                                                                 441  * list_for_each_entry› -›  iterate over list of given type                                                                         442  * @pos:›   the type * to use as a loop cursor.                                                                                     443  * @head:›  the head for your list.                                                                                                 444  * @member:›the name of the list_head within the struct.                                                                            445  */                                                                                                                                 446 #define list_for_each_entry(pos, head, member)› ›   ›   ›   \                                                                       447 ›   for (pos = list_first_entry(head, typeof(*pos), member);›   \                                                                   448 ›        &pos->member != (head);›   ›   ›   ›   ›   \                                                                               449 ›        pos = list_next_entry(pos, member))

即遍历gadget->ep_list, 然后usb_gadget_ep_match_desc函数进行需求匹配, 如果符号要求,  就会拿出来使用。

 


总结下list的使用相关。

1. list_head 结构本身很简单, 只记录了prev和next指针。

2. INIT_LIST_HEAD(&dwc->gadget.ep_list); 初始化好一个空队列。队列头为ep_list。

3. list_add_tail, 

67 /**                                                                                                                                  68  * list_add_tail - add a new entry                                                                                                   69  * @new: new entry to be added                                                                                                       70  * @head: list head to add it before                                                                                                 71  *                                                                                                                                   72  * Insert a new entry before the specified head.                                                                                     73  * This is useful for implementing queues.                                                                                           74  */                                                                                                                                  75 static inline void list_add_tail(struct list_head *new, struct list_head *head)                                                      76 {                                                                                                                                    77 ›   __list_add(new, head->prev, head);                                                                                               78 }

将前者new, 放入后者队列的尾部。 由于list是一个循环队列。。。 

__list_add(new, head->prev, head);

head->prev即为队列的尾部, head是本身, 即头部。

放在尾部和头部之间, 那就是新的尾部。

 

4. list_add

53 /**                                                                                                                                  54  * list_add - add a new entry                                                                                                        55  * @new: new entry to be added                                                                                                       56  * @head: list head to add it after                                                                                                  57  *                                                                                                                                   58  * Insert a new entry after the specified head.                                                                                      59  * This is good for implementing stacks.                                                                                             60  */                                                                                                                                  61 static inline void list_add(struct list_head *new, struct list_head *head)                                                           62 {                                                                                                                                    63 ›   __list_add(new, head, head->next);                                                                                               64 }

__list_add(new, head, head->next);

即放在head和head->next之间, 就是放在list的头部。 (list_head后面一个)

 

5. list_entry

345 /**                                                                                                                                 346  * list_entry - get the struct for this entry                                                                                       347  * @ptr:›   the &struct list_head pointer.                                                                                          348  * @type:›  the type of the struct this is embedded in.                                                                             349  * @member:›the name of the list_head within the struct.                                                                            350  */                                                                                                                                 351 #define list_entry(ptr, type, member) \                                                                                             352 ›   container_of(ptr, type, member)

get the struct for this entry

获取这个list_head的父亲结构体指针。

是的, 只有队列头部是用的一个list_head。

185 /* buffer for one video frame */                                                                                   186 struct vivi_buffer {                                                                                               187 ›   /* common v4l buffer stuff -- must be first */                                                                 188 ›   struct vb2_buffer›  vb;                                                                                        189 ›   struct list_head›   list;                                                                                      190 };  677 static void vivi_thread_tick(struct vivi_dev *dev)                                                                 678 {                                                                                                                  679 ›   struct vivi_dmaqueue *dma_q = &dev->vidq;                                                                      680 ›   struct vivi_buffer *buf;                                                                                       681 ›   unsigned long flags = 0;                                                                                       682                                                                                                                    683 ›   dprintk(dev, 1, "Thread tick\n");                                                                              684                                                                                                                    685 ›   spin_lock_irqsave(&dev->slock, flags);                                                                         686 ›   if (list_empty(&dma_q->active)) {                                                                              687 ›   ›   dprintk(dev, 1, "No active queue to serve\n");                                                             688 ›   ›   spin_unlock_irqrestore(&dev->slock, flags);                                                                689 ›   ›   return;                                                                                                    690 ›   }                                                                                                              691                                                                                                                    692 ›   buf = list_entry(dma_q->active.next, struct vivi_buffer, list);                                                693 ›   list_del(&buf->list);                                                                                          694 ›   spin_unlock_irqrestore(&dev->slock, flags);                                                                    695                                                                                                                    696 ›   v4l2_get_timestamp(&buf->vb.v4l2_buf.timestamp);                                                               697                                                                                                                    698 ›   /* Fill buffer */                                                                                              699 ›   vivi_fillbuff(dev, buf);                                                                                       700 ›   dprintk(dev, 1, "filled buffer %p\n", buf);                                                                    701                                                                                                                    702 ›   vb2_buffer_done(&buf->vb, VB2_BUF_STATE_DONE);                                                                 703 ›   dprintk(dev, 2, "[%p/%d] done\n", buf, buf->vb.v4l2_buf.index);                                                704 }

比如vivi驱动中, list_entry获取active队列数据头部, 即active.next的父亲结构体指针。 即vivi_buffer的数据指针。

方法呢??

是的, 就是那遍布内核各种驱动的神奇的container_of函数...

 

6. list_for_each_entry

440 /**                                                                                                                                 441  * list_for_each_entry› -›  iterate over list of given type                                                                         442  * @pos:›   the type * to use as a loop cursor.                                                                                     443  * @head:›  the head for your list.                                                                                                 444  * @member:›the name of the list_head within the struct.                                                                            445  */                                                                                                                                 446 #define list_for_each_entry(pos, head, member)› ›   ›   ›   \                                                                       447 ›   for (pos = list_first_entry(head, typeof(*pos), member);›   \                                                                   448 ›        &pos->member != (head);›   ›   ›   ›   ›   \                                                                               449 ›        pos = list_next_entry(pos, member))

即遍历队列中所有的数据, 并返还给pos。

看下list_first_entry(肯定又是container_of)

/**                                                                                                                     * list_first_entry - get the first element from a list                                                                 * @ptr:›   the list head to take the element from.                                                                     * @type:›  the type of the struct this is embedded in.                                                                 * @member:›the name of the list_struct within the struct.                                                              *                                                                                                                      * Note, that list is expected to be not empty.                                                                         */                                                                                                                    #define list_first_entry(ptr, type, member) \                                                                          ›   list_entry((ptr)->next, type, member)

 


ok, 大概捋一遍,  实践中慢慢用起来...

转载地址:http://ipcrj.baihongyu.com/

你可能感兴趣的文章
Python超详细的安装教程
查看>>
小甲鱼Python第一讲(我和Python的第一次亲密接触)
查看>>
小甲鱼Python第三讲(小插曲之变量和字符串)
查看>>
小甲鱼Python第十一讲(一个打了激素的数组2)
查看>>
小甲鱼Python第十三讲(戴上了枷锁的列表)
查看>>
小甲鱼Python第十四讲(各种奇葩的内置方法)
查看>>
小甲鱼Python第十五讲(格式化)
查看>>
小甲鱼Python第十七讲(Python的乐高积木)
查看>>
小甲鱼Python第十九讲(函数,我的地盘听我的)
查看>>
小甲鱼python第二十讲(内嵌函数和闭包)
查看>>
小甲鱼Python第二十一讲(lambda表达式)
查看>>
小甲鱼Python第二十三讲、第二十四讲(递归-这帮小兔崽子、汉诺塔)
查看>>
小甲鱼Python第二十七讲(集合)
查看>>
可调谐半导体激光器的窄线宽测试及压缩
查看>>
matlab中 %d,%f,%c,%s
查看>>
常见的光纤接头汇总
查看>>
半导体激光器—问题整理(二)
查看>>
科研日记7.31
查看>>
zemax仿真二向色镜
查看>>
stm32单片机编程时extern的用法
查看>>