Linux内核的显著特性
1.GCC特性
(1)基本功能——(功能扩展、性能优化)
通过变量的引用识别类型:typeof 如 #define min(x,y) ({typeof(x) _min1=(x); typeof(y) _min2=(y); (void) (&_min1==&_min2); _min1<_min2? _min1:_min2;} )
支持switch case 8...15: 的格式,代码更简洁
(2)属性—— __attribute__((ARRIBUTE)) 支持函数、变量和类型等声明特殊属性
ARRIBUTE可以为一个、多个,多个逗号隔开。常用的ARRIBUTE有
a. noreturn; b.format(archetype,string-index,first-to-check):用于函数,表示函数使用printf、scanf、strftime或strfmon风格的参数,并可以让编译器检查函数声明和函数实体调用参数之间的格式化字符串是否匹配;(如 static inline int printk(const char *s,...) __attribute__(format(printf,1,2)); 从第2个参数开始根据格式化字符串检查参数)c.unused 表示变量或者函数可能并不使用,避免警告;d.aligned(ALIGNMENT):按照字节数对齐变量、结构或联合,这受连接器最大对齐字节的限制;d.packed 对变量和类型中,不填充空的字节,让结构等内部按1字节对齐。
(3)内建函数,形如 __builtin_xxx(),比如 __builtin_expect(long exp,long c) 在include/linux/compiler.h中 #define likely(x) __builtin_expect(!!(x),1)
#define unlikely(x) __builtin_expect(!!(x),0) 用于条件语句中,if语句不变,如果if条件为1的可能性非常小时候,可以在条件表达式外面包装一个unlikely()
,反之可能性非常大,则使用likely().
2.链表的重要性
include/linux/list.h中
struct list_head{struct list_head *next,*prev;};此用法在描述数据类型的结构中包含链表。
(1)声明与初始化:静态声明和初始化使用 LIST_HEAD;动态声明和初始化用INIT_LIST_HEAD()。
#define LIST_HEAD_INIT(name) {&(name),&(name)}
#define LIST_HEAD(name) stuct list_head name=LIST_HEAD_INIT(name)
static inline void INIT_LIST_HEAD(stuct list_head *list) {list->next=list; list->prev=list;}
(2)判断链表为空
static inline int list_empty(const struct list_head *head){return head->next==head;}
(3)插入操作
static inline void list_add(struct list_head *new,struct list_head *head){ __list_add(new,head,head->next);}
static inline void list_add_tail(struct list_head *new,struct list_head *head){ __list_add(new,head->prev,head);}
(4)删除操作
static inline void list_replace_init(struct list_head *old,struct list_head *new){ list_replace(old,new); INIT_LIST_HEAD(old);}
(5)遍历操作
#define list_entry(ptr,type,member) container_of(ptr,type,member)
如:
struct list_head *tmp;
struct usb_hub *hub;
tmp = hub_event_list.next;
hub = list_entry(tmp,struct usb_hub,hub_event_list);
3. Kconfig和Makefile
(1)Kconfig结构,详细文档在Documentation/kbuild/kconfig-language.txt
a.菜单项 关键字config 菜单项名
config MODVERSIONS
bool "Set version information on all module symbols"
depends on MODULES
help
Usually,modules have to be recompiled whenever you switch to a new kernel,...
后面的代码定义了该菜单项的属性,包括类型、依赖关系、选择提示、帮助信息和默认值等;常用类型bool tristate string hex和int,其中tristate比bool多了一个编译成内核模块的选项;依赖关系 depends on 或 requires;帮助信息用help或--help--。
b.菜单组织结构
第一 显示声明菜单,
menu "Bus options (PCI,PCMIA,EISA,MCA,ISA)"
config PCI
...
endmenu
第二 通过依赖关系确定菜单结构
c.Kconfig的关键字
Kconfig文件描述了一系列的菜单选项,除帮助信息外,文件中的每一行都以一个关键字开始,主要有config,menuconfig,choice/endchoice,comments,menu/endmenu,if/endif,source等,只有前面5个可以用在菜单项定义的开始,它们都可以结束一个菜单项。
(2)Makefile
Linux内核的Makefile分为如下5个组成部分:
Makefile :最顶层的Makefile.
.config:内核的当前配置文档,编译时成为顶层Makefile的一部分;
arch/$(ARCH)/Makefile:和体系结构相关的Makefile;
Makefile.*:一些特定Makefile的规则;
kbuild级别Makefile:各级目录下的大概有约500个文档,编译时候根据上层Makefile传下来的宏定义和其他编译规则,将源代码编译成模块或编入内核。顶层的Makefile文档读取.config文档的内容,并总体上负责build内核和模块。Arch Makefile则提供补充体系结构相关的信息。其中,.config的内容是在make menuconfig时候,通过Kconfig文档配置的结果。
比如要编译/driver/mtd/maps/flashtest.c,需要在/driver/mtd/maps/目录下修改增加Kconfig 和makefile,
前者添加
config MTD_flashtest
tristate "ap71 flash"
后者makefile添加 obj-$(CONFIG_MTD_flashtest) += flashtest.o