Linux内核链表listhead扩展klist.docx
《Linux内核链表listhead扩展klist.docx》由会员分享,可在线阅读,更多相关《Linux内核链表listhead扩展klist.docx(27页珍藏版)》请在冰豆网上搜索。
Linux内核链表listhead扩展klist
看SPI驱动核心模块时,看到用到很多klist,之前没多深入理解,现在来一步步分析源码。
klist是对list_head的扩展,实现代码很少。
内核代码:
include/linux/klist.h
lib/klist.c
----------------------
先要有一点点预备知识——list_head
----------------------
先看看头文件如何定义klist,以及一些基本操作方法接口。
----------------------
klist头文件/*头文件*/
1/*
2*klist.h-Somegenericlisthelpers,extendingstructlist_headabit.
3*
4*Implementationsarefoundinlib/klist.c
5*
6*
7*Copyright(C)2005PatrickMochel
8*
9*ThisfileisrleasedundertheGPLv2.
10*/
11
12#ifndef_LINUX_KLIST_H
13#define_LINUX_KLIST_H
14
/*自旋锁,这个过几天认真看下实现,具体作用就是多处理器的临界操作锁
*对于嵌入式单处理器比较少用到
*/
15#include
/*这个是内核引用次数的原子变量定义和原子操作
*操作接口就是原子变量的增加get、减少put,以此实现内核对象引用次数操作
*/
16#include
/*内核链表list_head*/
17#include
18
/*先声明klist_node节点,在后面定义*/
19structklist_node;
/*klist结构体定义*/
20structklist{
/*klist操作自旋锁*/
21spinlock_tk_lock;
/*内核链表*/
22structlist_headk_list;
/*获取klist_node节点方法*/
23void(*get)(structklist_node*);
/*添加klist_node节点方法*/
24void(*put)(structklist_node*);
25}__attribute__((aligned(sizeof(void*))));/*按指针大小对齐*/
26
/*定义klist链表初始化宏
*名字初始化锁、链表、get、put方法
*/
27#defineKLIST_INIT(_name,_get,_put)\
/*初始化为解锁状态*/
28{.k_lock=__SPIN_LOCK_UNLOCKED(_name.k_lock),\
/*初始化链表*/
29.k_list=LIST_HEAD_INIT(_name.k_list),\
/*get方法*/
30.get=_get,\
/*put方法*/
31.put=_put,}
32
/*定义并初始化链表*/
33#defineDEFINE_KLIST(_name,_get,_put)\
34structklist_name=KLIST_INIT(_name,_get,_put)
35
/*klist初始化接口,在klist.c里具体分析*/
36externvoidklist_init(structklist*k,void(*get)(structklist_node*),
37void(*put)(structklist_node*));
38
/*节点结构体*/
39structklist_node{
40void*n_klist;/*neveraccessdirectly*/
/*节点链表入口*/
41structlist_headn_node;
/*引用次数的一个原子变量*/
42structkrefn_ref;
43};
44
/*下面是链表操作方法声明,在klist.c具体分析*/
45externvoidklist_add_tail(structklist_node*n,structklist*k);
46externvoidklist_add_head(structklist_node*n,structklist*k);
47externvoidklist_add_after(structklist_node*n,structklist_node*pos);
48externvoidklist_add_before(structklist_node*n,structklist_node*pos);
49
50externvoidklist_del(structklist_node*n);
51externvoidklist_remove(structklist_node*n);
52
53externintklist_node_attached(structklist_node*n);
54
55
/*klist迭代器和操作方法,关于迭代器比较难理解,先看klist.c再说*/
56structklist_iter{
57structklist*i_klist;
58structklist_node*i_cur;
59};
60
61
62externvoidklist_iter_init(structklist*k,structklist_iter*i);
63externvoidklist_iter_init_node(structklist*k,structklist_iter*i,
64structklist_node*n);
65externvoidklist_iter_exit(structklist_iter*i);
66externstructklist_node*klist_next(structklist_iter*i);
67
68#endif
69----------------------
klist实现代码1/*
2*klist.c-Routinesformanipulatingklists.
3*
4*Copyright(C)2005PatrickMochel
5*
6*ThisfileisreleasedundertheGPLv2.
7*
8*Thisklistinterfaceprovidesacoupleofstructuresthatwraparound
9*structlist_headtoprovideexplicitlist"head"(structklist)andlist
10*"node"(structklist_node)objects.Forstructklist,aspinlockis
11*includedthatprotectsaccesstotheactuallistitself.struct
12*klist_nodeprovidesapointertotheklistthatownsitandakref
13*referencecountthatindicatesthenumberofcurrentusersofthatnode
14*inthelist.
15*
16*Theentirepointistoprovideaninterfaceforiteratingoveralist
17*thatissafeandallowsformodificationofthelistduringthe
18*iteration(e.g.insertionandremoval),includingmodificationofthe
19*currentnodeonthelist.
20*
21*Itworksusinga3rdobjecttype-structklist_iter-thatisdeclared
22*andinitializedbeforeaniteration.klist_next()isusedtoacquirethe
23*nextelementinthelist.ItreturnsNULLiftherearenomoreitems.
24*Internally,thatroutinetakestheklist'slock,decrementsthe
25*referencecountofthepreviousklist_nodeandincrementsthecountof
26*thenextklist_node.Itthendropsthelockandreturns.
27*
28*Thereareprimitivesforaddingandremovingnodesto/fromaklist.
29*Whendeleting,klist_del()willsimplydecrementthereferencecount.
30*Onlywhenthecountgoesto0isthenoderemovedfromthelist.
31*klist_remove()willtrytodeletethenodefromthelistandblockuntil
32*itisactuallyremoved.Thisisusefulforobjects(likedevices)that
33*havebeenremovedfromthesystemandmustbefreed(butmustwaituntil
34*allaccessorshavefinished).
35*/
36
37#include
38#include
39#include
40
/*下面定义一些节点操作方法,先看下去,再来理解这些操作真正作用*/
41/*
42*Usethelowestbitofn_klisttomarkdeletednodesandexclude
43*deadonesfromiteration.
44*/
45#defineKNODE_DEAD1LU
46#defineKNODE_KLIST_MASK~KNODE_DEAD
47
/*由节点获取链表头*/
48staticstructklist*knode_klist(structklist_node*knode)
49{
50return(structklist*)
51((unsignedlong)knode->n_klist&KNODE_KLIST_MASK);
52}
53
/*判断节点“死了”*/
54staticboolknode_dead(structklist_node*knode)
55{
56return(unsignedlong)knode->n_klist&KNODE_DEAD;
57}
58
/*设置节点的链表*/
59staticvoidknode_set_klist(structklist_node*knode,structklist*klist)
60{
61knode->n_klist=klist;
62/*noknodedeservestostartitslifedead*/
/*没有节点刚开始就是“死的”*/
63WARN_ON(knode_dead(knode));
64}
65
/*“杀死”节点*/
66staticvoidknode_kill(structklist_node*knode)
67{
68/*andnoknodeshoulddietwiceevereither,seewe'reveryhumane*/
/*没有节点能“死”两次,瞧我们多人性化*/
69WARN_ON(knode_dead(knode));
70*(unsignedlong*)&knode->n_klist|=KNODE_DEAD;
71}
72
73/**
74*klist_init-Initializeakliststructure.
75*@k:
Theklistwe'reinitializing.
76*@get:
Thegetfunctionfortheembeddingobject(NULLifnone)
77*@put:
Theputfunctionfortheembeddingobject(NULLifnone)
78*
79*Initialisesthekliststructure.Iftheklist_nodestructuresare
80*goingtobeembeddedinrefcountedobjects(necessaryforsafe
81*deletion)thentheget/putargumentsareusedtoinitialise
82*functionsthattakeandreleasereferencesontheembedding
83*objects.
84*/
/*klist初始化接口
*get/put方法用来操作klist_node
*/
85voidklist_init(structklist*k,void(*get)(structklist_node*),
86void(*put)(structklist_node*))
87{
88INIT_LIST_HEAD(&k->k_list);
89spin_lock_init(&k->k_lock);
90k->get=get;
91k->put=put;
92}
93EXPORT_SYMBOL_GPL(klist_init);
94
/*将节点加入到链表头*/
95staticvoidadd_head(structklist*k,structklist_node*n)
96{
97spin_lock(&k->k_lock);
98list_add(&n->n_node,&k->k_list);
99spin_unlock(&k->k_lock);
100}
101
/*将节点加入到链表尾*/
102staticvoidadd_tail(structklist*k,structklist_node*n)
103{
104spin_lock(&k->k_lock);
105list_add_tail(&n->n_node,&k->k_list);
106spin_unlock(&k->k_lock);
107}
108
/*节点初始化
*包括初始化链表、引用计数、设置指向klist
*/
109staticvoidklist_node_init(structklist*k,structklist_node*n)
110{
111INIT_LIST_HEAD(&n->n_node);
112kref_init(&n->n_ref);
113knode_set_klist(n,k);
/*如果klist的get方法存在,则调用获取节点*/
114if(k->get)
115k->get(n);
116}
117
118/**
119*klist_add_head-Initializeaklist_nodeandaddittofront.
120*@n:
nodewe'readding.
121*@k:
klistit'sgoingon.
122*/
/*将节点n初始化并加入到klist的头*/
123voidklist_add_head(structklist_node*n,structklist*k)
124{
125klist_node_init(k,n);
126add_head(k,n);
127}
128EXPORT_SYMBOL_GPL(klist_add_head);
129
130/**
131*klist_add_tail-Initializeaklist_nodeandaddittoback.
132*@n:
nodewe'readding.
133*@k:
klistit'sgoingon.
134*/
/*将节点n初始化并加入到klist的尾*/
135voidklist_add_tail(structklist_node*n,structklist*k)
136{
137klist_node_init(k,n);
138add_tail(k,n);
139}
140EXPORT_SYMBOL_GPL(klist_add_tail);
141
142/**
143*klist_add_after-Initaklist_nodeandadditafteranexistingnode
144*@n:
nodewe'readding.
145*@pos:
nodetoput@nafter
146*/
/*在节点pos后面插入节点n*/
147voidklist_add_after(structklist_node*n,structklist_node*pos)
148{
149structklist*k=knode_klist(pos);
150
151klist_node_init(k,n);
152spin_lock(&k->k_lock);
153list_add(&n->n_node,&pos->n_node);
154spin_unlock(&k->k_lock);
155}
156EXPORT_SYMBOL_GPL(klist_add_after);
157
158/**
159*klist_add_before-Initaklist_nodeandadditbeforeanexistingnode
160*@n:
nodewe'readding.
161*@pos:
nodetoput@nafter
162*/
/*在节点pos前面插入节点n*/
163voidklist_add_before(structklist_node*n,structklist_node*pos)
164{
165structklist*k=knode_klist(pos);
166
167klist_node_init(k,n);
168spin_lock(&k->k_lock);
169list_add_tail(&n->n_node,&pos->n_node);
170spin_unlock(&k->k_lock);
171}
172EXPORT_SYMBOL_GPL(klist_add_before);
173
/*等待者结构体,用于删除节点,删除完成唤醒进程*/
174structklist_waiter{
175structlist_headlist;
176structklist_node*node;
177structtask_struct*process;
178intwoken;
179};
180
/*定义并初始化klist节点移除自旋锁*/
181staticDEFINE_SPINLOCK(klist_remove_lock);
/*定义一个等待器的链表*/
182staticLIST_HEAD(klist_remove_waiters);
183
184staticvoidklist_release(structkref*kref)
185{
186structklist_waiter*waiter,*tmp;
187structklist_node*n=container_of(kref,structklist_node,n_ref);
188
189WARN_ON(!
knode_dead(n));
/*删除链表中的节点入口*/
190list_del(&n->n_node);
191spin_lock(&klist_remove_lock);
/*内核链表操作宏include/linux/list.h,遍历klist节点移除等待链表*/
192list_for_each