Android中的双向链表
来源:互联网 发布:linux下编译nodejs 编辑:程序博客网 时间:2024/06/15 14:38
1.看源码必须搞懂Android的数据结构。在init源代码中双向链表listnode使用很多,它只有prev和next两个指针,没有任何数据成员。这个和linux内核的list_head如出一辙,由此可见安卓深受linux内核的影响的。本来来分析一下这个listnode数据结构。
这里需要考虑的一个问题是,链表操作都是通过listnode进行的,但是那不过是个连接件,如果我们手上有个宿主结构,那当然知道了它的某个listnode在哪里,从而以此为参数调用list_add和list_del函数;可是,反过来,当我们顺着链表取得其中一项的listnode结构时,又怎样找到其宿主结构呢?在listnode结构中并没有指向其宿主结构的指针啊。毕竟,我们我真正关心的是宿主结构,而不是连接件。对于这个问题,我们举例内核中的list_head的例子来解决。内核的page结构体含有list_head成员,问题是:知道list_head的地址,如何获取page宿主的地址?下面是取自mm/page_alloc.c中的一行代码:
page = memlist_entry(curr, struct page, list);
这里的memlist_entry将一个list_head指针curr换算成其宿主结构的起始地址,也就是取得指向其宿主page结构的指针。读者可能会对memlist_entry()的实现感到困惑。
#define memlist_entry list_entry
而list_entry定义则在include/linux/list.h中
135 /**136 * list_entry getthe struct for this entry137 * @ptr: the &struct list_head pointer.138 * @type: the type of the struct this is embedded in.139 * @member: the name of the list_struct within the struct.140 */141 #define list_entry(ptr, type, member) \142 ((type *)((char *)(ptr)-(unsigned long)(&((type *)0)->member)))
这样我们应该就明白了,curr是一个page结构内部成分list的地址,而我们所需要的却是那个page结构本身的地址,所以要从curr减去一个偏移量,即成分list在page内部的位移量。那么这个位移量怎么求?&((struct page*)0)->list就表示当结构page正好在地址0上时其成分list的地址,这就是所求的偏移量。
2.测试代码
#include<stdio.h>#include<stddef.h>typedef struct _listnode{ struct _listnode *prev; struct _listnode *next;}listnode;#define node_to_item(node,container,member) \(container*)(((char*)(node))-offsetof(container,member))//向list双向链表尾部添加node节点,list始终指向双向链表的头部(这个头部只含有prev/next)void list_add_tail(listnode *list,listnode *node){ list->prev->next=node; node->prev=list->prev; node->next=list; list->prev=node;}//定义一个测试的宿主结构typedef struct _node{ int data; listnode list;}node;int main(){ node n1,n2,n3,*n; listnode list,*p; n1.data=1; n2.data=2; n3.data=3; list.prev=&list; list.next=&list; list_add_tail(&list,&n1.list); list_add_tail(&list,&n2.list); list_add_tail(&list,&n3.list); for(p=list.next;p!=&list;p=p->next) { n=node_to_item(p,node,list); printf("%d\n",n->data); } return 0;}
0 0
- Android中的双向链表
- android源代码学习 init中的双向链表listnode
- java中的双向链表
- 数据结构中的双向链表
- 看linux中的双向链表
- Redis中的双向链表的实现
- Linux中的双向循环链表
- C语言中的双向循环链表
- 成对交换双向链表中的结点
- Linux中的双向循环链表
- 双向链表中的交换节点
- 双向链表实现数据结构中的队列
- php中的单项链表与双向链表
- 双向循环链表在 LINUX kernel 中的实现
- 双向链表在内核中的超然地位
- linux双向链表分析之list_del中的技巧
- 内核双向链表list.h中的list_entry
- linux双向链表分析之list_del中的技巧
- MySql常用字典表
- spring+ehcache实现的缓存查询参数
- Git系列之二 --- git-dir & work-tree
- linq to xml查找元素的值
- SQL 以月份或日期为条件进行查询
- Android中的双向链表
- Android XML使用
- Android WifiDisplay分析一:相关Service的启动(转载)
- led驱动_使用次设备号来区别设备
- Java之美[从菜鸟到高手演变]之设计模式
- .NET入门基础教程视频分享
- 数位dp--spoj1182
- 黑马程序员-java——JNI
- The 3n+1