浅谈linux内核中的list.h[2]

 

链表的删除

83/*

84 * Delete a list entry by making the prev/next entries

85 * point to each other.

86 *

87 * This is only for internal list manipulation where we know

88 * the prev/next entries already!

89 */

90static inline void __list_del(struct list_head * prev, struct list_head * next)

91{

92 next->prev = prev;

93 prev->next = next;

94}

该函数通过设置prevnext指针指向彼此,实现了删除二者之间节点的功能。但是这里我有个疑惑,删除的指针的释放在哪里实现。

96/**

97 * list_del - deletes entry from list.

98 * @entry: the element to delete from the list.

99 * Note: list_empty() on entry does not return true after this, the entry is

100 * in an undefined state.

101 */

102#ifndef CONFIG_DEBUG_LIST

103static inline void list_del(struct list_head *entry)

104{

105 __list_del(entry->prev, entry->next);

106 entry->next = LIST_POISON1;

107 entry->prev = LIST_POISON2;

108}

109#else

110extern void list_del(struct list_head *entry);

111#endif

该函数通过调用上面的内联函数实现节点的删除,这里的LIST_POISON1LIST_POISON2是在linux/poison.h定义的。此处仍然是条件编译。

 

 

链表节点的置换

113/**

114 * list_replace - replace old entry by new one

115 * @old : the element to be replaced

116 * @new : the new element to insert

117 *

118 * If @old was empty, it will be overwritten.

119 */

120static inline void list_replace(struct list_head *old,

121 struct list_head *new)

122{

123 new->next = old->next;

124 new->next->prev = new;

125 new->prev = old->prev;

126 new->prev->next = new;

127}

128

129static inline void list_replace_init(struct list_head *old,

130 struct list_head *new)

131{

132 list_replace(old, new);

133 INIT_LIST_HEAD(old);

134}

静态内联函数list_replace接受两个参数:oldnew,并通过new替换old。而list_replace_init函数则是通过调用list_replace进行替换,之后调用INIT_LIST_HEAD对被替换的old进行链表初始化。

 

 

链表的移动

146/**

147 * list_move - delete from one list and add as another’s head

148 * @list: the entry to move

149 * @head: the head that will precede our entry

150 */

151static inline void list_move(struct list_head *list, struct list_head *head)

152{

153 __list_del(list->prev, list->next);

154 list_add(list, head);

155}

List_move函数接受两个参数,第一个参数list为想要移动的节点指针,第二个参数为目的地节点指针。该函数通过调用__list_del函数实现list节点的prevnext两个指针互指实现删除list节点的效果,并且调用list_addlist节点插入到head之后。

157/**

158 * list_move_tail - delete from one list and add as another’s tail

159 * @list: the entry to move

160 * @head: the head that will follow our entry

161 */

162static inline void list_move_tail(struct list_head *list,

163 struct list_head *head)

164{

165 __list_del(list->prev, list->next);

166 list_add_tail(list, head);

167}

List_move_tail函数将指定节点移到指定链表的尾部,成为尾节点。并且由于链表是循环的,所以移动的节点指向该链表head节点。具体实现是通过目标节点的prevnext互指实现从原始链表中删除list节点,之后通过调用list_add_taillist节点插入到以head为表首的链表尾部。

判断节点是否为链表的最后一个

169/**

170 * list_is_last - tests whether @list is the last entry in list @head

171 * @list: the entry to test

172 * @head: the head of the list

173 */

174static inline int list_is_last(const struct list_head *list,

175 const struct list_head *head)

176{

177 return list->next == head;

178}

通过判断节点的next指向是否为表首来确定是否为last

 

 

判断链表是否为空

180/**

181 * list_empty - tests whether a list is empty

182 * @head: the list to test.

183 */

184static inline int list_empty(const struct list_head *head)

185{

186 return head->next == head;

187}

通过判断head节点是否指向自身来判断链表是否为空。

189/**

190 * list_empty_careful - tests whether a list is empty and not being modified

191 * @head: the list to test

192 *

193 * Description:

194 * tests whether a list is empty _and_ checks that no other CPU might be

195 * in the process of modifying either member (next or prev)

196 *

197 * NOTE: using list_empty_careful() without synchronization

198 * can only be safe if the only activity that can happen

199 * to the list entry is list_del_init(). Eg. it cannot be used

200 * if another CPU could re-list_add() it.

201 */

202static inline int list_empty_careful(const struct list_head *head)

203{

204 struct list_head *next = head->next;

205 return (next == head) && (next == head->prev);

206}

此处函数的作用并不十分理解,对于绿色注释说明部分的DescriptionNOTE部分也是一知半解。单纯地翻一下NOTE部分:如果没有经过同步化处理,那么如果要达到安全地使用list_empty_careful这个函数必须限定当前能对指定节点发生的操作仅仅为list_del_init(),比如当一个CPU对它进行add操作的时候不能使用该函数。

该函数能达到的效果是检查链表是否为空,并且检测是否有CPU在修改当前指定节点的prevnext指针。

这里引用一段解释,来自杨沙洲:

Linux链表另行提供了一个list_empty_careful()宏,它同时判断头指针的nextprev,仅当两者都指向自己时才返回真。这主要是为了应付另一个cpu正在处理同一个链表而造成nextprev不一致的情况。但代码注释也承认,这一安全保障能力有限:除非其他cpu的链表操作只有list_del_init(),否则仍然不能保证安全,也就是说,还是需要加锁保护。

 

 

判断链表是否只有唯一的一个节点

208/**

209 * list_is_singular - tests whether a list has just one entry.

210 * @head: the list to test.

211 */

212static inline int list_is_singular(const struct list_head *head)

213{

214 return !list_empty(head) && (head->next == head->prev);

215}

空表并不是一个节点都没有,唯一的节点也不是指只有一个节点,具体看函数代码我们便可以了解。当一个节点指针被执行LIST_HEAD了以后,它的prevnext指针都指向自身,这便称为空表;而如果它的prevnext指针都指向仅有的第二个节点,那么它便称为仅有一个节点。

 

 

链表的切割

217static inline void __list_cut_position(struct list_head *list,

218 struct list_head *head, struct list_head *entry)

219{

220 struct list_head *new_first = entry->next;

221 list->next = head->next;

222 list->next->prev = list;

223 list->prev = entry;

224 entry->next = list;

225 head->next = new_first;

226 new_first->prev = head;

227}

228

229/**

230 * list_cut_position - cut a list into two

231 * @list: a new list to add all removed entries

232 * @head: a list with entries

233 * @entry: an entry within head, could be the head itself

234 * and if so we won’t cut the list

235 *

236 * This helper moves the initial part of @head, up to and

237 * including @entry, from @head to @list. You should

238 * pass on @entry an element you know is on @head. @list

239 * should be an empty list or a list you do not care about

240 * losing its data.

241 *

242 */

243static inline void list_cut_position(struct list_head *list,

244 struct list_head *head, struct list_head *entry)

245{

246 if (list_empty(head))

247 return;

248 if (list_is_singular(head) &&

249 (head->next != entry && head != entry))

250 return;

251 if (entry == head)

252 INIT_LIST_HEAD(list);

253 else

254 __list_cut_position(list, head, entry);

255}

这里有三个参数,list,head,entry

假设原先有链表:head <-> node1 <-> node2 <-> node3 <-> entry <-> node4 <-> head

那么最后会得到链表1head <-> node4 <-> head 和链表2list <-> node1 <-> node2 <-> node3 <-> entry <-> list

这里最好自己画图模拟一下。

链表的合并

257static inline void __list_splice(const struct list_head *list,

258 struct list_head *prev,

259 struct list_head *next)

260{

261 struct list_head *first = list->next;

262 struct list_head *last = list->prev;

263

264 first->prev = prev;

265 prev->next = first;

266

267 last->next = next;

268 next->prev = last;

269}

假设有两条链表:head <-> node1 <-> node2 <-> node3 <-> head

和:last <-> list <-> first

那么合并的结果是取代了headlast <-> list <-> first <-> node1 <-> node2 <-> node3 <-> last

271/**

272 * list_splice - join two lists, this is designed for stacks

273 * @list: the new list to add.

274 * @head: the place to add it in the first list.

275 */

276static inline void list_splice(const struct list_head *list,

277 struct list_head *head)

278{

279 if (!list_empty(list))

280 __list_splice(list, head, head->next);

281}

282

283/**

284 * list_splice_tail - join two lists, each list being a queue

285 * @list: the new list to add.

286 * @head: the place to add it in the first list.

287 */

288static inline void list_splice_tail(struct list_head *list,

289 struct list_head *head)

290{

291 if (!list_empty(list))

292 __list_splice(list, head->prev, head);

293}

294

295/**

296 * list_splice_init - join two lists and reinitialise the emptied list.

297 * @list: the new list to add.

298 * @head: the place to add it in the first list.

299 *

300 * The list at @list is reinitialised

301 */

302static inline void list_splice_init(struct list_head *list,

303 struct list_head *head)

304{

305 if (!list_empty(list)) {

306 __list_splice(list, head, head->next);

307 INIT_LIST_HEAD(list);

308 }

309}

310

311/**

312 * list_splice_tail_init - join two lists and reinitialise the emptied list

313 * @list: the new list to add.

314 * @head: the place to add it in the first list.

315 *

316 * Each of the lists is a queue.

317 * The list at @list is reinitialised

318 */

319static inline void list_splice_tail_init(struct list_head *list,

320 struct list_head *head)

321{

322 if (!list_empty(list)) {

323 __list_splice(list, head->prev, head);

324 INIT_LIST_HEAD(list);

325 }

326}

以下的合并函数都是调用第一个合并内联函数__list_splice,区别只在于合并取代的位置以及是否对空出来的head进行初始化,即调用INIT_LIST_HEAD等宏。

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值