ImageVerifierCode 换一换
格式:DOCX , 页数:7 ,大小:20.81KB ,
资源ID:11802863      下载积分:3 金币
快捷下载
登录下载
邮箱/手机:
温馨提示:
快捷下载时,用户名和密码都是您填写的邮箱或者手机号,方便查询和重复下载(系统自动生成)。 如填写123,账号就是123,密码也是123。
特别说明:
请自助下载,系统不会自动发送文件的哦; 如果您已付费,想二次下载,请登录后访问:我的下载记录
支付方式: 支付宝    微信支付   
验证码:   换一换

加入VIP,免费下载
 

温馨提示:由于个人手机设置不同,如果发现不能下载,请复制以下地址【https://www.bdocx.com/down/11802863.html】到电脑端继续下载(重复下载不扣费)。

已注册用户请登录:
账号:
密码:
验证码:   换一换
  忘记密码?
三方登录: 微信登录   QQ登录  

下载须知

1: 本站所有资源如无特殊说明,都需要本地电脑安装OFFICE2007和PDF阅读器。
2: 试题试卷类文档,如果标题没有明确说明有答案则都视为没有答案,请知晓。
3: 文件的所有权益归上传用户所有。
4. 未经权益所有人同意不得将文件中的内容挪作商业或盈利用途。
5. 本站仅提供交流平台,并不能对任何下载内容负责。
6. 下载文件中如有侵权或不适当内容,请与我们联系,我们立即纠正。
7. 本站不保证下载资源的准确性、安全性和完整性, 同时也不承担用户因使用这些下载资源对自己和他人造成任何形式的伤害或损失。

版权提示 | 免责声明

本文(Linux 内核中的GCC特性了解用于C语言的GCC扩展.docx)为本站会员(b****5)主动上传,冰豆网仅提供信息存储空间,仅对用户上传内容的表现方式做保护处理,对上载内容本身不做任何修改或编辑。 若此文所含内容侵犯了您的版权或隐私,请立即通知冰豆网(发送邮件至service@bdocx.com或直接QQ联系客服),我们立即给予删除!

Linux 内核中的GCC特性了解用于C语言的GCC扩展.docx

1、Linux 内核中的GCC特性了解用于C语言的GCC扩展GCC 和 Linux 是出色的组合。尽管它们是独立的软件,但是 Linux 完全依靠 GCC 在新的体系结构上运行。Linux 还利用 GCC 中的特性(称为扩展)实现更多功能和优化。本文讨论一些重要的扩展,讲解如何在 Linux 内核中使用它们。GCC 当前的稳定版本(版本 4.3.2)支持 C 标准的三个版本:International Organization for Standardization (ISO) 最初的 C 语言标准(ISO C89 或 C90)带修正 1 的 ISO C90当前的 ISO C99(这是 GCC 使

2、用的默认标准,本文也假设采用这种标准)注意:本文假设使用 ISO C99 标准。如果指定比 ISO C99 版本旧的标准,那么可能无法使用本文描述的一些扩展。可以在命令行上使用 -std 选项指定 GCC 使用的实际标准。可以通过 GCC 手册查看哪个标准版本支持哪些扩展。可以以几种方式对可用的 C 扩展进行分类。本文把它们分为两大类:功能性 扩展提供新功能。优化 扩展帮助生成更高效的代码。功能性扩展先讨论一些扩展标准 C 语言的 GCC 扩展。类型发现GCC 允许通过变量的引用识别类型。这种操作支持泛型编程。在 C+、Ada 和 Java 语言等许多现代编程语言中都可以找到相似的功能。Lin

3、ux 使用 typeof 构建 min 和 max 等依赖于类型的操作。清单 1 演示如何使用 typeof 构建一个泛型宏(见 ./linux/include/linux/kernel.h)。清单 1. 使用 typeof 构建一个泛型宏#definemin(x,y)(typeof(x)_min1=(x);typeof(y)_min2=(y);(void)(&_min1=&_min2);_min1_min2?_min1:_min2;)范围扩展GCC 支持范围,在 C 语言的许多方面都可以使用范围。其中之一是 switch/case 块中的 case 语句。在复杂的条件结构中,通常依靠嵌套的

4、if 语句实现与清单 2(见 ./Linux/drivers/scsi/sd.c)相同的结果,但是清单 2 更简洁。使用 switch/case 也可以通过使用跳转表实现进行编译器优化。清单 2. 在 case 语句中使用范围staticintsd_major(intmajor_idx)switch(major_idx)case0:returnSCSI_DISK0_MAJOR;case1.7:returnSCSI_DISK1_MAJOR+major_idx-1;case8.15:returnSCSI_DISK8_MAJOR+major_idx-8;default:BUG;return0;/*s

5、hutupgcc*/还可以使用范围进行初始化,如下所示(见 ./linux/arch/cris/arch-v32/kernel/smp.c)。在这个示例中,spinlock_t 创建一个大小为 LOCK_COUNT 的数组。数组的每个元素初始化为 SPIN_LOCK_UNLOCKED 值。/*Vectoroflocksusedforvariousatomicoperations*/spinlock_tcris_atomic_locks=0.LOCK_COUNT-1=SPIN_LOCK_UNLOCKED;范围还支持更复杂的初始化。例如,以下代码指定数组中几个子范围的初始值。intwidths=0

6、.9=1,10.99=2,100=3;零长度的数组在 C 标准中,必须定义至少一个数组元素。这个需求往往会使代码设计复杂化。但是,GCC 支持零长度数组的概念,这对于结构定义尤其有用。这个概念与 ISO C99 中灵活的数组成员相似,但是使用不同的语法。下面的示例在结构的末尾声明一个没有成员的数组(见 ./Linux/drivers/IEee1394/raw1394-private.h)。这允许结构中的元素引用结构实例后面紧接着的内存。在需要数量可变的数组成员时,这个特性很有用。structiso_block_storeatomic_trefcount;size_tdata_size;quad

7、let_tdata0;判断调用地址在许多情况下,需要判断给定函数的调用者。GCC 提供用于此用途的内置函数 _builtin_return_address。这个函数通常用于调试,但是它在内核中还有许多其他用途。如下面的代码所示,_builtin_return_address 接收一个称为 level 的参数。这个参数定义希望获取返回地址的调用堆栈级别。例如,如果指定 level 为 0,那么就是请求当前函数的返回地址。如果指定 level 为 1,那么就是请求进行调用的函数的返回地址,依此类推。void*_builtin_return_address(unsignedintlevel);在下面

8、的示例中(见 ./linux/kernel/softirq.c),local_bh_disable 函数在本地处理器上禁用软中断,从而禁止在当前处理器上运行 softirqs、tasklets 和 bottom halves。使用 _builtin_return_address 捕捉返回地址,以便在以后进行跟踪时使用这个地址。voidlocal_bh_disable(void)_local_bh_disable(unsignedlong)_builtin_return_address(0);常量检测在编译时,可以使用 GCC 提供的一个内置函数判断一个值是否是常量。这种信息非常有价值,因为可以

9、构造出能够通过常量叠算(constant folding)优化的表达式。_builtin_constant_p 函数用来检测常量。_builtin_constant_p 的原型如下所示。注意,_builtin_constant_p 并不能检测出所有常量,因为 GCC 不容易证明某些值是否是常量。int_builtin_constant_p(exp)Linux 相当频繁地使用常量检测。在清单 3 所示的示例中(见 ./linux/include/linux/log2.h),使用常量检测优化 roundup_pow_of_two 宏。如果发现表达式是常量,那么就使用可以优化的常量表达式。如果表达式

10、不是常量,就调用另一个宏函数把值向上取整到 2 的幂。清单 3. 使用常量检测优化宏函数#defineroundup_pow_of_two(n)(_builtin_constant_p(n)?(n=1)?1:(1ULlen,skb-csum);if(likely(!sum)if(unlikely(skb-ip_summed=CHECKSUM_HW)netdev_rx_csum_fault(skb-dev);skb-ip_summed=CHECKSUM_UNNECESSARY;returnsum;预抓取另一种重要的性能改进方法是把必需的数据缓存在接近处理器的地方。缓存可以显著减少访问数据花费的时

11、间。大多数现代处理器都有三类内存:一级缓存通常支持单周期访问二级缓存支持两周期访问系统内存支持更长的访问时间为了尽可能减少访问延时并由此提高性能,最好把数据放在最近的内存中。手工执行这个任务称为预抓取。GCC 通过内置函数 _builtin_prefetch 支持数据的手工预抓取。在需要数据之前,使用这个函数把数据放到缓存中。如下所示,_builtin_prefetch 函数接收三个参数:数据的地址rw 参数,使用它指明预抓取数据是为了执行读操作,还是执行写操作locality 参数,使用它指定在使用数据之后数据应该留在缓存中,还是应该清除void_builtin_prefetch(const

12、void*addr,intrw,intlocality);Linux 内核经常使用预抓取。通常是通过宏和包装器函数使用预抓取。清单 6 是一个辅助函数示例,它使用内置函数的包装器(见 ./linux/include/linux/prefetch.h)。这个函数为流操作实现预抓取机制。使用这个函数通常可以减少缓存缺失和停顿,从而提高性能。清单 6. 范围预抓取的包装器函数#ifndefARCH_HAS_PREFETCH#defineprefetch(x)_builtin_prefetch(x)#endifstaticinlinevoidprefetch_range(void*addr,size_

13、tlen)#ifdefARCH_HAS_PREFETCHchar*cp;char*end=addr+len;for(cp=addr;cpend;cp+=PREFETCH_STRIDE)prefetch(cp);#endif变量属性除了本文前面讨论的函数属性之外,GCC 还为变量和类型定义提供了属性。最重要的属性之一是 aligned 属性,它用于在内存中实现对象对齐。除了对于性能很重要之外,某些设备或硬件配置也需要对象对齐。aligned 属性有一个参数,它指定所需的对齐类型。下面的示例用于软件暂停(见 ./Linux/arch/i386/mm/init.c)。在需要页面对齐时,定义 PAGE

14、_SIZE 对象。char_nosavedataswsusp_pg_dirPAGE_SIZE_attribute_(aligned(PAGE_SIZE);清单 7 中的示例说明关于优化的两点:packed 属性打包一个结构的元素,从而尽可能减少它们占用的空间。这意味着,如果定义一个 char 变量,它占用的空间不会超过一字节(8 位)。位字段压缩为一位,而不会占用更多存储空间。这段源代码使用一个 _attribute_ 声明进行优化,它用逗号分隔的列表定义多个属性。清单 7. 结构打包和设置多个属性staticstructswsusp_headercharreservedPAGE_SIZE-20-sizeof(swp_entry_t);swp_entry_timage;charorig_sig10;charsig10;_attribute_(packed,aligned(PAGE_SIZE)swsusp_header;结束语本文只讨论了在 Linux 内核中可以使用的几个 GCC 特性。可以通过 GNU GCC 手册进一步了解针对 C 和 C+ 语言的所有扩展。另外,尽管 Linux 内核经常使用这些扩展,但是也可以在用户自己的应用程序中使用它们。随着 GCC 的发展,肯定会出现新的扩展,它们会进一步改进性能和增加 Linux 内核的功能。

copyright@ 2008-2022 冰豆网网站版权所有

经营许可证编号:鄂ICP备2022015515号-1