LINUX内核设计与实现之可移植性
来源:互联网 发布:剑三2016成女捏脸数据 编辑:程序博客网 时间:2024/05/18 00:52
LINUX系统是一个可移植性非常好的操作系统.一般而言,暴露在外的内核接口往往是与硬件体系结构无关的.例如:
调试程序(存放于kernel/sched.c文件中)就是与体系结构无关的.但是其中封装的一些功能函数,如处理器上下文切换和地址空间切换等,是依赖于相应的体系结构完成的.因此,context_switch()用于实现进程切换,而在它内部,会调用switch_to()和switch_mm()分别完成处理器上下文和地址空间的切换.
与体系结构相关的代码存放在arch/architecture/和include/asm-architecture/目录下.architecture是LINUX支持的体系结构的简称,如i386.
19.1 LINUX的可移植性
目前LINUX支持的体系结构已经达到了20多种.像ARM、X86、MIPS等.
19.2 字长和数据类型
字:能够由机器一次就完成处理的数据.处理器通用寄存器(GPR’s)的大小和它的字长相同.一般来说,对于一个体系结构,它各部件的宽度,如内存总线,最少要和它的字长一样大.
LINUX无论支持哪种体系结构,都要遵循下面的规则:
.ANSI C标准规定,一个char的长度一定是8位;
.尽管没有规定int类型的长度是32位,但是在LINUX当前所有支持体系结构中,它都是32位的;
.short类型如果没有明文规定,它都是16位的;
.决不假定指针和long的长度,它是可变的,在32位和64位中变化;
.不能假设sizeof(int)==sizeof(long);
.不要假定指针和int长度相等.
19.2.1 不透明类型
用typedef声明一个类型,把它叫做不透明类型.如用来保存进程标识符的pid_t类型.处理不透明类型的原则是:
.不要假设该类型的长度;
.不要将该类型转化回其对应的C标准类型使用;
.编程时要保证该类型实际存储空间和格式发生变化时代码不受影响.
19.2.2 指定数据类型
内核中一些数据虽然不需要用不透明的类型表示,但是它们被定义成了指定的数据类型.jiffy数目和在中断控制时用到的flags参数就是两个例子.它们都应该被存放在unsigned long类型中.
19.2.3 长度明确的类型
我们在实际编程中,需要在程序中使用长度明确的数据.像操作硬件设备,进行网络通信和操作二进制文件时,通常都必须满足它们明确的内部要求.比如说,一块声卡可能用的是32位寄存器,一个网络包有一个16位字段,一个可执行文件有8位的cookie.内核在<asm/typs.h>中定义了这些长度明确的类型,而该文件又被包含在文件<linux/types.h>中.如下表:
这些长度明确的类型大部分通过typedef对标准C类型进行映射得到.下面是示意代码:
Typedef signed char s8;
Typedef unsigned char u8;
Typedef signed short s16;
Typedef unsigned short u16;
Typedef signed int s32;
Typedef unsigned int u32;
Typedef signed long s64;
Typeedf unsigned long u64;
而在32位机上,它们可能定义为:
Typedef signed char s8;
Typedef unsigned char u8;
Typedef signed short s16;
Typedef unsigned short u16;
Typedef signed int s32;
Typedef unsigned int u32;
Typedef signed long long s64;
Typedef unsigned long long u64;
上述的这些类型只能在内核使用,不可以在用户空间出现.用户空间的长度明确类型有两个下划线.如下:
__u32 à用户空间
U32 à内核空间
19.2.4 char型的符号问题
大部分体系结构上,char默认是带符号的,它可以自-128到127之间取值.也有一些例外,如ARM体系结构上,char就是不带符号的,它的取值范围是0~255.
19.3 数据对齐
保证数据对齐可以提高系统性能.
19.3.1 避免对齐引发的问题
一个数据类型长度较小,它本来是对齐的,如果用一个指针进行类型转换,并且转换后的类型长度较大,那么通过改指针进行数据访问时就会引发对齐问题.如下代码是错误的:
Char dog[10];
Char *p = &dog[1];
Unsigned long l = *(unsigned long *)p;
这个例子将一个指向char型的指针当作指向unsigned long 型来用,会引发对齐问题.因为此时会试图从一个并不能被4整除的内存地址上载入32位的unsigned long型数据.
19.3.2 非标准类型的对齐
前面提到了,对于标准数据类型来说,它的地址只要是其长度的整数倍对齐就可以了.而非标准的(复合的)C数据类型按照下列原则对齐:
.对于数组,只要按照基本数据类型进行对齐就可以了;
.对于联合,只要它包含的长度最大的数据类型能够对齐就可以了;
.对于结构体,只要它包含的长度最大的数据类型能够对齐就可以了.
19.3.3 结构体填补
为了保证结构体中每一个成员能够自然对齐,结构体要被填补.这点确保了当处理器访问结构中一个给定元素时,元素本身是对齐的.如下面的例子:
Struct animal_struct
{
Char dog; //1字节
Unsigned long cat; //4字节
Unsigned short pig; //2字节
Char fox; //1字节
}
由于该结构体不能准确满足各成员自然对齐,所以它在内存中可不是按原样放置的.编译器会在内存中创建一个类似下面给出的结构体:
Struct animal_struct
{
Char dog;
U8 __pad0[3];
Unsigned long cat ;
Unsigned short pig;
Char fox;
U8 __pad1;
}
因此,在内存中此结构体实际占用的空间大小为12字节.因此,需要我们编程时注意自然对齐问题,避免编译器填充,节省内存空间.对此结构体重新排序如下:
Struct animal_struct
{
Unsigned long cat;
Unsigned short pig;
Char dog;
Char fox;
}
这样结构体只有8字节了.
19.4 字节顺序
Big-Endian和Little-Endian的定义如下:
1) Little-Endian就是低位字节排放在内存的低地址端,高位字节排放在内存的高地址端。
2) Big-Endian就是高位字节排放在内存的低地址端,低位字节排放在内存的高地址端。
举一个例子,比如数字0x12 34 56 78在内存中的表示形式为:
1)大端模式:
低地址 -----------------> 高地址
0x12 | 0x34 | 0x56 | 0x78
2)小端模式:
低地址 ------------------> 高地址
0x78 | 0x56 | 0x34 | 0x12
下面给出一个判断机器是高位优先还是低位优先字节顺序的代码:
Int x = 1;
If(*(char *)&x ==1)
Printf("Little-Endian\n");
Else
Printf("Big-Endian\n");
19.4.2 内核中的字节顺序
内核中常常会涉及到字节顺序的转换.常用宏命令如下:
19.5 时间
不要假定时钟中断发生的频率.也就是每秒产生的jiffies数目.因上,绝对不要用jiffiess直接去和1000这样的数值比较.计量时间的正确方法是乘以或除以HZ.如:
HZ //1秒
(2*HZ) //2秒
(HZ/2) //半秒
19.6 页长度
不要假定页的长度.如假定页大小为4KB.当处理用页组织管理内存时,通过PAGE_SIZE来使用以字节数来表示的长度.而PAGE_SHIFT这个值定义了从最右端屏蔽多少位能够得到该地址对应的页的页号.比如,在页长为4KB的X86机上,PAGE_SIZE为4096而PAGE_SHIFT为12.它们都定义于<asm/page.h>文件中.如下表所示:
19.7 处理器排序
在代码中,如果在对排序要求最弱的体系结构上,要保证指令执行顺序.那么就必须使用诸如rmb()和wmb()等恰当的内存屏障来确保处理器以正确顺序提交装载和存储指令.
19.8 SMP、内核抢占、高端内存
在内核编程中涉及到SMP、内核抢占、高端内存时候,需要加上以下几条规范:
.假设你的代码会在SMP系统上运行,要正确选择和使用锁;
.假设你的代码会在支持内核抢占的情况下运行,要正确选择和使用锁和内核抢占语句;
.假设你的代码会运行在使用高端内存(非永久映射内存)的系统上,必要时使用kmap().
- LINUX内核设计与实现之可移植性
- linux内核设计与实现--19章 可移植性
- 《Linux内核设计与实现》——可移植性
- 《Linux内核设计与实现》读书笔记(十九)- 可移植性
- 《Linux内核设计与实现》读书笔记(十九)- 可移植性
- Linux内核设计与实现 学习笔记(9)可移植性
- 《Linux内核设计与实现》读书笔记(十九)- 可移植性
- 《Linux内核设计与实现》读书笔记(十九)- 可移植性
- Linux 内核开发之可移植性
- LINUX内核可移植性
- 读书笔记之《Linux内核设计与实现》
- 读书笔记之《Linux内核设计与实现》
- LINUX内核设计与实现之调试
- Linux内核设计与实现之大纲
- linux内核的可移植性
- Linux内核设计与实现 之二 从内核出发
- Linux内核设计与实现之内核同步介绍
- linux内核分析笔记----内核可移植性
- mysql 远程连接
- 各种排序的时间复杂度
- Django 学习笔记(1)
- 链表的操作
- Android ArrayAdapter 详解
- LINUX内核设计与实现之可移植性
- C语言占位符总结
- 为什么会出现这种局面
- hdu4565 矩阵快速幂
- 关于最新版本(19)的build-tools问题:Unable to execute dex: java.nio.BufferOverflowException
- nginx配置yii的安全
- UML活动图
- nginx 常用
- java applet调用客户端dll 简单案例