Chinaunix首页 | 论坛 | 博客
  • 博客访问: 111786
  • 博文数量: 64
  • 博客积分: 186
  • 博客等级: 入伍新兵
  • 技术积分: 120
  • 用 户 组: 普通用户
  • 注册时间: 2012-02-24 17:11
文章分类

全部博文(64)

文章存档

2014年(54)

2013年(2)

2012年(8)

我的朋友

分类: LINUX

2012-03-22 10:59:55

当我们使用遍历的方法来删除链表时:

list_for_each(pos, &student_list)

{

         list_del(pos);    

}

 

list_for_each(pos, head)这个宏定义是用来遍历链表的,通过其第一个参数pos来删除链表节点,但是,运行后就会出现以下错误:

 

Unable to handle kernel paging request at virtual address 00100100

pgd = c3aa8000

[00100100] *pgd=33a82031, *pte=00000000, *ppte=00000000

Internal error: Oops: 17 [#1]

last sysfs file: /sys/devices/virtual/vc/vcsa4/dev

Modules linked in: mylist(-) [last unloaded: mylist]

CPU: 0    Not tainted  (2.6.32.2 #1)

PC is at cleanup_module+0x48/0x64 [mylist]

LR is at sys_delete_module+0x1e8/0x25c

pc : []    lr : []    psr: 00000013

sp : c3a99f40  ip : bf0122e0  fp : 00000000

r10: be825e88  r9 : c3a98000  r8 : c002e024

r7 : c3a99f44  r6 : 00000880  r5 : bf01219c  r4 : 00000000

r3 : bf0122e4  r2 : bf0122e4  r1 : 00100100  r0 : c3a480d8

Flags: nzcv  IRQs on  FIQs on  Mode SVC_32  ISA ARM  Segment user

Control: c000717f  Table: 33aa8000  DAC: 00000015

Process rmmod (pid: 849, stack limit = 0xc3a98270)

Stack: (0xc3a99f40 to 0xc3a9a000)

9f40: c3ab8c80 696c796d 00007473 00000000 00000000 c35d8828 00000062 c0091bf8

9f60: 00000000 00000000 00000000 c3ab8c80 00000000 c3a9a6c0 c3ab8c80 00000000

9f80: bf01219c 00000880 c3a99f8c 00000000 c3ab8c80 be825f63 00000001 00000000

9fa0: 00000081 c002dea0 be825f63 00000001 be825f63 00000880 4022a024 00000001

9fc0: be825f63 00000001 00000000 00000081 00000001 00000000 be825e88 00000000

9fe0: 00000000 be825b10 00018250 401c886c 60000010 be825f63 00000000 00000000

[] (cleanup_module+0x48/0x64 [mylist]) from [] (sys_delete_module+0x1e8/0x25c)

[] (sys_delete_module+0x1e8/0x25c) from [] (ret_fast_syscall+0x0/0x28)

Code: e59fc018 e1a0300c e4931004 e1510003 (e5910000)

---[ end trace 2e1cdf07b6db8d2d ]---

Segmentation fault

 

原因在于使用list_for_each(pos, head)来遍历整个链表时,依赖于pos->next,从他的代码实现就可以看出来:

/*include/linux/list.h*/

#define list_for_each(pos, head) \

         for (pos = (head)->next; prefetch(pos->next), pos != (head); \

                 pos = pos->next)

而删除节点函数

list_del(pos);

会把pos的后向链表post->next指向另外一个地址,见函数原型:

/*include/linux/list.h*/

static inline void list_del(struct list_head *entry)

{

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

         entry->next = LIST_POISON1;

         entry->prev = LIST_POISON2;

}

/*include/linux/Poison.h*/

#define LIST_POISON1  ((void *) 0x00100100)

而这个地址正好是出错信息提示的地址0x00100100。

 

正确的做法其实应该使用另外一个遍历宏定义:

/*include/linux/list.h*/

#define list_for_each_safe(pos, n, head) \

         for (pos = (head)->next, n = pos->next; pos != (head); \

                   pos = n, n = pos->next)

这里用n做了pos的备份,当处理完for循环里的事情后,又把n的值重新赋回给pos,确保pos结构里的值不被改变。

 

JJDeng@SCUT

jjdeng.scut@gmail.com

2011.01.19

阅读(866) | 评论(0) | 转发(0) |
给主人留下些什么吧!~~