1.1 数据类型所占空间
在编译内核时使用-Wall-Wstict-prototypes选项,可以避免很多错误的发生
内核使用的基本数据类型
int 标准C语言整数类型
u32 32位整数类型
pid_t 特定内核对象pid的类型
其中基于sparc64平台的linux用户空间可以运行32代码,用户空间指针是32位宽的,但内核是64位的
内核中的地址是unsigned long类型,指针大小和long类型相同
使用有前缀的类型用于将变量显露给用户空间.如_ _u8类型.例如一个驱动程序通过ioctl函数与运行在用户空间的程序交换数据,应该用_ _u32来声明32位的数据类型
有时内核使用C语言的类型,如unsigned int,这通常用于大小独立于体系结构的数据项.
内核中许多数据类型由typedef声明,这样方便移植.如使用pid_t类型作为进程标志符(pid)的类型,而不是int类型,pid_t屏蔽了在不同平台上的实际数据类型的差异.
如果不容易选择适合的类型,就将起强制转换成最可能的类型(long或unsigned long).
1.2 时间间隔
对于1s的时间间隔,不能用100个jiffy.因为不同的平台可能设置不一,所以应该用Hz(每秒定时器中断的次数)来衡量
页面大小
内存页的大小个PAGE_SIZE字节,而不是4KB.在不同的平台上,页大小范围可以是4KB到64KB.PAGE_SHIFT的作用是通过对地址右移PAGE_SHIT得到一个地址所在页的页
号.对于用户空间,可以使用geipagesize函数来得到页的大小.
使用get_free_pages函数申请16KB空闲空间(2的14次方),先将16KB转换成2的x次方的空闲页数.在x85下定义PAGE_SHIFT为12
int order = (14 - PAGE_SHIFT > 0)?14 - PAGE_SHIFT:0;
buf = get_free_pages(GFP_KERNEL,order);
字节存储顺序
字节存储顺序有两种,低字节优先的方式是在存储多字节数值时,低字节在前面,高字节在后面.高字节优先正好相反.现代的处理器大部分工作在big-endian模式下.Linux内核定
义了一组宏,用于在处理器字节序数据和特殊字节数据之间进行转换.宏在Linux/byteorder/big_endian.h中
u32 _ _cpu_to _le32(u32);//将一个CPU的值的字节序转换策划嗯一个小端字节的无符号值
还有_be64_to_cpu
数据对齐
读取一个存储在非4字节倍数的地址中的4字节值,这就存在数据对其的问题,用下面的宏访问未对齐的数据
#Include<asm/unaligned.h>
get_unaligned(ptr);
put_unaligned(val,ptr);
这些宏是与类型无关,对各项数据项,都有效.
1.3 内核通用链表
在<Linux/list.h>文件中定义了一个list_head类型简单结构
struct list_head{
struct list_head *next,*prev;
};
通用链表的常用用途是将某一个数据结构本身串成链表,或将某些链表与一个数据结构联系起来,这两种情况实质上都是由结构list_head组成链表.
将某一个数据结构本身串成链表
(1)加入list_head结构成员
struct example_struct{
struct list_head list;
int priority;
.......//其他成员
}
用list成员将example_struct结构串成链表,就是list_head"背负"的负载是example_struct结构.
(2)创建list_head结构
使用前必须申请链表头并用INIT_LIST_HEAD宏来初始化链表头.可使用两种方法
方法1:
struct list_head example_list;
INIT_LIST_HEAD(&example_list);
方法2:
LIST_HEAD(example_list):
其中,这两个宏在include/Linux/list.h中定义如下:
#define LIST_HEAD(name) \
struct list_head name = LIST_HEAD_INIT(name)
#define INIT_LIST_HEAD(ptr)do{
(ptr)->next = (ptr); (prt)->prev = (ptr);\
}while(0)
(3)从example_list链表中得到节点对应的example_struct结构指针,其中ptr是example_list链表中的指针,如ptr = example_list->next
struct example_struct *node = list_entury(ptr,struct example_struct,list);
在上面代码行中的宏定义list_entry将一个list_head结构指针映射回一个只想结构example_struct的指针,即得到list_head的宿主结构,宏定义(在include/Linux/list.h)
#define list_entry(ptr,type,member)\
container_of(ptr,type,member)
得到链表中节点的结构:
ptr是链表中的一个struct list_head结构元素指针
type是用户定义的结构类型,其中,包含struct list_head结构成员
member用户定义结构的struct list_head结构成员名字
在include/Linux/kernel.h中有contain_of的定义,参数含义与list_entry中一直,container_of得到list的容器结构,即含有list成员的机构type.contain_of的定义如下:
#define container_of(ptr,type,member)({
//将链表中的元素ptr转换成结构type中成员menber的类型
const typeof(((type *)0)->member)*_mptr = (ptr);
//_mptr减去member成员偏移地址正好是type结构地址
(type *)((char *)_mptr - offsetof(type,member));
})
在include/Linux/stddef.h中有宏offsetof的定义,列出如下
#define offsetof(TYPE,MEMBER)((size_t)&((TYPE *)0)->MEMBER)