一、向量定义 在某些情况下,数据结构的末端定义一个可选的区块,增加其灵活性:
struct abc{
int age;
char *name[20];
……
char placeholder[0];
}
可选区域从placeholder开始,定义为大小为0的数组。因此当abc被分配带有可选区块时,就指向此区块的起始处,否则指向此结构的尾端。从而可以灵活分配负载的长度。
二、编译条件指令(#ifdef及其系列指令)
#ifdef 或 #if defined用于指示C预处理程序完成检查的功能
如:struct sk_buff {
……
#ifdef CONFIG_NTFLITER_DEBUG
unsigned int nf_debug;
#endif
……
}
还可以用于选择编译语句,屏蔽另一些语句。或者选择函数原型
三、编译期间的条件检查优化
多数情况下,当内核用某些外部值比较一个变量以了解是否满足给定条件时,其结果极有可能是可预测的。内核分别使用likely和unlikely宏,进行返回真或假的比较。这些宏会利用gcc编译器的功能依据该项信息使代码的编译最优化。
如,假设需要调用do_something函数,在调用失败时,必须使用handle_error函数进行处理:
err = do_something(x, y, z);
if(err)
handle_error(err);
假设do_something很少失败,则可以按下列方式重写代码:
err = do_something(x, y, z);
if(unlikely(err))
handle_error(err);
linkly和unikely宏其实是用gcc的内置__builtin_expect功能来做程序的优化。likely是指为真的机会更大,而unlikely是指为假的机会更大。这样编译器可以将机会更大机器码直接紧跟其后,减少跳转的次数。
四、互斥
在网络代码中广泛使用上锁,对众多程序设计类型而言,尤其是针对内核的程序设计,互斥、上锁机制以及同步都是一般性主题相当复杂而有趣。在网络代码猪常见的可选互斥方法有:
自旋锁:在某一时刻只能由一个执行的县城所持有的锁。自旋锁只用于多处理器系统中,且应该在预期该锁只会被短期持有的时候。
读写锁:当给定的使用可以明确分为只读和读写时,应该先使用读写锁。多个读者可以同时持有该锁,而同一时刻的持有者只有一个可以写入,当该锁被一个写者持有时,其他读者和写者都不能获得该锁。读者的优先级高于写者,因此当读者的数目远远大于写者时,这种类型的锁可以很好地工作。
但该锁在只读模式下时,不能直接提升为读写模式,需要先释放该锁,在以读写模式获取。
RCU(Read-Copy-Update)
RCU是Linux 2.6中一个最新的互斥机制,在下列特定条件下工作非常好:
1.与只读锁的请求相比,读写锁的请求很少见
2.持有该锁的代码以原子的形式执行,而且不能休眠
3.由该锁保护的数据结构是通过指针访问的
五、主机和网络字节序直接的转化
超过一个字节的数据结构可以以大端和小端两种方式存放在内存中。小端是将最低字节存放在最低内存地址中,大端恰好相反。Intel处理器遵循小端模式,TCP/IP网络字节序是大端模式。所以,所有的网络协议都会明确定义字节的字节序。
为了代码的可移植性,都会定义主机和网络字节序之间的转换函数,只是若主机和网络为同一字节序,则为空操作。否则,将字节序进行转换。
htons\ntohs、htonl\ntohl分别为2字节和四字节转换函数。
六、捕获BUG
内核使用BUG_ON和BUG_TRAP来捕获条件不满足的情况。当传给BUG_TRAP的输入条件为假时,内核会打印警告信息。对于BUG_ON的则打印出错误消息,然后系统崩溃。
七、内核时间
内核空间中时间用嘀嗒(tick)来计算。一个嘀嗒是连续到期的定时器中断之间的时间长度。定时器会负责各种不同任务,而且每秒会固定到期HZ次。HZ是一个变量,由系统体系依赖的代码进行初始化。如在i386机器上,它被初始化为每秒1000次,所以i386机器上,定时器每秒中断1000次。
每次定时器到期,就是一个名为jiffies的全局变量递增。因此,任何时刻,jiffies代表从系统引导后所经过的嘀嗒次数,通用值n*HZ代表的就是n秒。
文献:
1.
阅读(2858) | 评论(0) | 转发(0) |