设为首页 加入收藏

TOP

Linux内核分析及编程之数据类型与列表
2014-11-24 00:39:07 来源: 作者: 【 】 浏览:5
Tags:Linux 内核 分析 编程 数据 类型

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


get_unaligned(ptr);


put_unaligned(val,ptr);


这些宏是与类型无关,对各项数据项,都有效.


1.3 内核通用链表


文件中定义了一个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)


其中&((struct example_struct *)0 )->list表示当结构example_struct正好在地址0上时其成员list的地址,即成员位移


】【打印繁体】【投稿】【收藏】 【推荐】【举报】【评论】 【关闭】 【返回顶部
分享到: 
上一篇Eclipse 平台下SVN的配置步骤与注.. 下一篇Linux网络编程技术学习笔记

评论

帐  号: 密码: (新用户注册)
验 证 码:
表  情:
内  容: