全部博文(395)
分类: LINUX
2011-06-23 20:58:15
前言:linux内核中会经常碰到内核链表,并且这些链表运用的算法非常经典。学习内核链表是你学习linux内核重要的一步。
[root@bogon guoqian]# mkdir 4-4-2
[root@bogon guoqian]# ls
4-1-1 4-1-4 4-2-6-1 4-3-3 4-3-6 nfsroot
4-1-2 4-2-1 4-3-1 4-3-4 4-4-1 u-boot-2008.10
4-1-3 4-2-6 4-3-2 4-3-5 4-4-2 u-boot-2008.10.tar.bz2
[root@bogon guoqian]# cd 4-4-2/
[root@bogon 4-4-2]# ll
总计 0
[root@bogon 4-4-2]# cp ../
[root@bogon 4-4-2]# cp ../4-4-1/Makefile ./
[root@bogon 4-4-2]# ls
Makefile
[root@bogon 4-4-2]# vi mylist.c
#include
#include
#include
#include
#include
MODULE_LICENSE("GPL");
MODULE_AUTHOR("feifei");
MODULE_DESCRIPTION("List Module");
MODULE_ALIAS("List moudle");
struct student{
char name[100];
int num;
struct list_head list;
};
struct student *pstudent;
struct student *tmp_student;
struct list_head student_list;
struct list_head *pos;
static int __init mylist_init(void){
int i=0;
INIT_LIST_HEAD(&student_list);
pstudent = kmalloc(sizeof(struct student)*5,GFP_KERNEL);
memset(pstudent,0,sizeof(struct student)*5);
for(i=0;i<5;i++){
sprintf(pstudent[i].name,"Student%d",i+1);
pstudent[i].num=i+i;
list_add(&(pstudent[i].list),&student_list);
}
list_for_each(pos,&student_list){ //下面会解释这些宏的定义
tmp_student=list_entry(pos,struct student,list);
printk("<0>student %d name:%s\n",tmp_student->num,tmp_student->name);
}
return 0;
}
static void __exit mylist_exit(void){
int i;
for(i=0;i<5;i++){
list_del(&(pstudent[i].list));
}
kfree(pstudent);
}
module_init(mylist_init);
module_exit(mylist_exit);
[root@bogon 4-4-2]# vi Makefile
ifneq ($(KERNELRELEASE),)
obj-m :=mylist.o
else
KDIR :=/home/guoqian/4-3-1/linux-2.6.29
all:
make -C $(KDIR) M=$(PWD) modules
clean:
rm -f *.ko *.o *.mod.o *.mod.c *.symvers
endif
[root@bogon 4-4-2]# cp mylist.ko /home/guoqian/nfsroot/rootfs/tmp/
超级终端:
U-Boot 2008.10 (Jun 18 2011 - 18:29:43)
DRAM: 64 MB
Flash: 2 MB
In: serial
Out: serial
Err: serial
Mini2440 #
Mini2440 # bootm 31000000
eth0: link down
IP-Config: Guessing netmask 255.0.0.0
IP-Config: Complete:
device=eth0, addr=59.70.157.173, mask=255.0.0.0, gw=255.255.255.255,
host=59.70.157.173, domain=, nis-domain=(none),
bootserver=255.255.255.255, rootserver=59.70.157.174, rootpath=
Looking up port of RPC 100003/2 on 59.70.157.174
eth0: link up, 100Mbps, full-duplex, lpa 0x41E1
Looking up port of RPC 100005/1 on 59.70.157.174
VFS: Mounted root (nfs filesystem) on device 0:11.
Freeing init memory: 128K
Processing /etc/profile... Done
# cd /tmp/
# ls
alloc_mem.ko mylist.ko
# insmod mylist.ko
student 5 name:Student5
student 4 name:Student4
student 3 name:Student3
student 2 name:Student2
student 1 name:Student1
# lsmod
mylist 1420 0 - Live 0xbf000000
# rmmod mylist
rmmod: module 'mylist' not found
# lsmod
#
对上面的一些宏的定义:
以下转自:http://blog.csdn.net/jiatingqiang/archive/2011/05/22/6437496.aspx
和:http://cutebunny.blog.51cto.com/301216/67517
list_entry的宏定义:
#define list_entry(ptr, type, member) \
((type *)((char *)(ptr)-(unsigned long)(&((type *)0)->member)))
再看上面这个以前,先看看这个定义:
#define offsetof(TYPE, MEMBER) ((size_t) &((TYPE *)0)->MEMBER);
分析:
(TYPE *)0,将 0 强制转换为 TYPE 型指针,记 p = (TYPE *)0,p是指向TYPE的指针,它的值是0。那么 p->MEMBER 就是 MEMBER 这个元素了,而&(p->MEMBER)就是MENBER的地址,而基地址为0,这样就巧妙的转化为了TYPE中的偏移量。再把结果强制转换为size_t型的就OK了,size_t其实也就是int。
然后再看上面的
(char *)(ptr)使得指针的加减操作步长为一字节,(unsigned long)(&((type *)0)->member)等于ptr指向的member到该member所在结构体基地址的偏移字节数。二者一减便得出该结构体的地址。转换为 (type *)型的指针