一、可移植的操作系统
1、可移植操作系统:
1)、尽可能少地涉及与机器相关的代码。汇编代码用的少之又少,为了支持各种不同类别的体系结构,界面和功能再定义时都尽最大可能地具有普适性和抽象性。
2)、问题在于,体系结构相关的一些特性往往无法被支持,也不能对特定的及其代码进行手动优化。选择这种设计,就是利用代码的优化能力换取代码的可移植性。
2、不可移植的操作系统:
1)、尽最大可能追求代码的性能表现,尽可能多的使用汇编代码,压根就是只为一种硬件体系结构使用。
3、Linux中差不多所有的接口和核心代码都是独立于硬件体系结构的代码。但是,在对性能要求很严格的部分,内核的特性会根据不同的硬件体系结构进行调整。
二、Linux移植史
三、字长和数据类型
一)相关简介
1、能够由机器一次完成处理的数据称为字。字是指位的整数数目——比如说1、2、4或8等。处理器通用寄存器的大小和它的字长是相同的。
2、对于支持的每一种体系结构,Linux都要将<asm/types.h>的BITS_PER_LONG定义为C long类型的长度,也就是系统的字长。
3、一般而言,Linux对于一种体系结构都会分别实现32位和64位的不同版本。
4、Linux支持的体系结构(P312 表19-1)。
5、C语言虽然规定了变量的最小长度,但是没有规定变量具体的标准长度,它们可以根据实现变化。情况其实更加复杂,用户空间使用的数据类型和内核空间使用的数据类型
不一定要相互关联。
6、可移植下需要牢记下述准则
1)、ANSI C标准规定,一个char的长度一定是1字节。
2)、尽管没有规定int类型的长度是32位,但在Linux当前所有支持的体系结构中,他都是32位的。
3)、short类型也类似,在当前所有支持的体系结构中,虽然没有明文规定,但是它都是16位的。
4)、决不应该假定指针和龙的长度,在Linux当前支持的体系结构中,它们可以在32位和64位变化。
5)、由于不同的体系结构中long的长度不同,绝不能假设sizeof(int)=sizeof(long)。
6)、类似的,也不要假设指针和int长度相等。
7、操作系统常用一个简单的助记符来描述此系统中数据类型的大小。
二)、不透明类型
1、不透明数据类型隐藏了它们的内部格式或结构。
2、处理不透明类型的原则是:
1)、不要假设该类型的长度。
2)、不要把该类型转化回其对应的C标准类型使用。
3)、成为一个大小不知论者。编程时要保证在该类型实际存储空间和格式发生变化时代码不受影响。
三)、指定数据类型
1、内核中还有一些数据虽然无须用不透明的类型表示,但它们定义成了指定的数据类型。
2、当存放和处理这些特殊的数据时,一定要搞清它们对应的类型后在使用,把它们存放在其他类型中是一种常见的错误。
四)、长度明确的类型
1、作为一个程序员,我们应该在程序中使用长度明确的数据。
2、内核在<asm/typs.h>中定义了这些长度明确的类型,而该文件又被包含在文件<linux/types.h>中。(P314 表19-2)
3、长度明确的数据类型只能在内核内使用,不可以再用户空间出现。此为了保护命名空间。不过对应这些不可见变量的同时也定义了对应的用户可见的变量类型,这些类型与
长度明确的数据类型所不同的是增加了两个下划线前缀。
五)、char型符号问题
1、C标准表示char类型可以带符号也可以不带符号,由具体的编译器、处理器或由它们两者共同决定到底char是带符号还是不带符号。
2、大部分体系结构上,char默认是带符号的,它可以自-128 —127之间取值。也有一些列外,比如ARM体系结构上,插入就是不带符号的,它的取值范围是0-255。
四、数据对齐
一)、相关简介
1、对齐是跟数据块在内存中的位置相关的话题。如果一个变量的内存地址正好是它长度的整数倍,它就称作是自然对齐。也就是说,一个大小为2n字节的数据类型,它地址
的最低有效位的后n位都应该为0。
2、编写可移植高的代码要避免对齐问题,保证所有的类型都能够自然对齐。
二)、避免对齐引发的问题
1、编译器通常会通过让所有的数据自然对齐来避免引发对齐问题。
2、当程序员使用指针太多,多数据的访问方式查出编译器的预期时,就会引发对齐问题。
三)、非标准类型的对齐
1、非标准的C数据类型按照下列原则对齐:
1)、对于数组,只要按照基本数据类型进行对齐就可以了,随后的所有元素自然能够对齐。
2)、对于联合体,只要它包含的长度最大的数据类型能够对齐就可以了。
3)、对于结构体,只要结构体中每个元素能够正确地对齐就可以了。
四)、结构体填补
1、为了保证结构体中每一个成员都能够自然对齐,结构体要被填补。
2、可以重新排列结构体中的对象来避免填充。
五、字节顺序
1、字节顺序是指在一个字中各个字节的顺序。处理器在对字取值时即可能将最低有效位所在的字节当作第一个字节,也可能将其当作最后一个字节。
1)、如果最高有效位所在的字节放在低字节位置上,其他字节依次放在高字节位置上,那么该字节顺序称作高位优先。
2)、如果最低有效位所在的字节放在高字节位置上,其他字节依次放在低字节位置上,那么该字节顺序称作低位优先。
2、对于Linux支持的每一种体系结构,相应的内核都会根据机器使用的字节顺序在它的<asm/byteorder.h>中定义_BIG_ENDIAN或_LITTLE_ENDIAN中的一个。
3、<asm/byteorder.h>头文件还从include/linux/byteorder/中包含了一组宏命令用于完成字节顺序之间的相互转换。最常见的宏命令:
u32 __cpu_to_be32(u32);
u32 __cpu_to_le32(u32);
u32 __be32_to_cpu(u32);
u32 __le32_to_cpus(u32);
六、时间
1、时间测量是一个内核概念,它随着体系结构甚至内核版本的不同而不同。绝对不要假定时钟中断发生的频率,也就是每秒产生的jiffies数目。相反,应该是使用HZ来正确计
量时间。
2、计量时间的正确方法是乘以或除以HZ。
七、页长度
1、当处理用页组织管理的内存时,通过PAGE_SIZE以字节数来表示页长度。而PAGE_SHIRT这个值定义了从最右端屏蔽多少能够等到该地址对应的页的页号。
2、不同体系结构的页长度。(P320 表19-4)
八、处理器排序
九、SMP、内核抢占、高端内存
1、保证可移植性的规范
1)、假设你的代码会在SNP系统上运行,要正确的选择和使用锁。
2)、假设你的代码会在支持内核抢占的情况下运行,要正确的选择和使用锁和内核前瞻语句。
3)、假设你的代码会运行在使用高端内存(非永久映射内存)的系统上,必要时使用kmap()。