8288分类目录 8288分类目录 8288分类目录
  当前位置:海洋目录网 » 站长资讯 » 站长资讯 » 文章详细 订阅RssFeed

写文章 聊一聊linux内核中的基础工具库(2) Sparse

来源:本站原创 浏览:32次 时间:2023-05-20

在看linux源码的时候,经常能看到一类type,例如__user,__kernel,__safe,__force等,在compiler_type.h的头文件中,我找到了它们的定义。看到两个很奇怪的现象,一个是只有在__CHECKER__宏打开的情况下,他们的定义才会被实现,否则他们的定义是空的。第二个是它们的attribute的定义,并不是gcc支持的属性。那到底是哪里使用到了呢?原来linux的作者们自己开发了一套编译期代码检查的工具Sparse,可以用于在编译阶段快速发现代码中隐含的问题。lwn上有一篇关于这个工具的讨论[1]。

如compiler_type.h文件中所示,下面通过注释说明sparse在linux内核中的一些简单用法:

#ifdef __CHECKER__// noderef 代表该指针不能被解引用,也就是不能*ptr这样访问。// address_space定义了指针能指向的内存的类型,0代表kernel space,1代表user space,// 2代表设备地址空间,3代表cpu局部的内存空间# define __user__attribute__((noderef, address_space(1)))# define __kernel__attribute__((address_space(0)))// safe表示变量可以为空# define __safe__attribute__((safe))// force表示变量可以强制类型转换# define __force__attribute__((force))// nocast表示参数类型必需和实际类型一致# define __nocast__attribute__((nocast))// io设备的地址空间# define __iomem__attribute__((noderef, address_space(2)))// __attribute__((context(x, in, out))表示要保证x在调用前值是in,调用后值是out// 举个例子,在调用某个函数时,需要检查是否lock一直被持有,就可以使用__must_hold(lock),// 保证调用时锁是被持有的。// 如果要保证函数在调用前lock是未被持有的,调用结束后,lock必需被持有,// 就可以使用__acquire(lock)// 举个内核里的例子:// static struct binder_thread *binder_get_txn_from_and_acq_inner(//struct binder_transaction *t)//        __acquires(&t->from->proc->inner_lock)// {//    ... // 在函数的实现中,最后一定会获取到&t->from->proc->inner_lock// }# define __must_hold(x)__attribute__((context(x,1,1)))# define __acquires(x)__attribute__((context(x,0,1)))# define __releases(x)__attribute__((context(x,1,0)))// __context__(x,v) 表示对x加上v,在上下文退出时,sparse会检查x值是否为0,不为0会报错# define __acquire(x)__context__(x,1)# define __release(x)__context__(x,-1)// 如果c为true,对x加1# define __cond_lock(x,c)((c) ? ({ __acquire(x); 1; }) : 0)# define __percpu__attribute__((noderef, address_space(3)))

除了在linux内核中使用外,其实我们如果有需求,也是可以单独使用的,安装编译和用法在这个链接里[2] [3]

在大型项目中为了保证代码质量,会加入很多防御性编程代码,这样能够即时的把问题暴露出来。例如:

// 函数本身是非线程安全的,需要在外边上锁保护void dothing_unsafe(){  ASSERT(lock == 1); // 确保函数调用时,锁是成功加上的。  ... // 执行函数逻辑  ASSERT(lock == 0); // 最后返回时,需要确保lock已被释放,否则说明代码逻辑存在bug}

例子中dothing_unsafe中典型的防御性编程的代码就是通过assert调用,保证函数在调用时lock是持有状态的。但是assert本身调用会带来除函数逻辑以外的额外开销,因此会对性能造成影响。影响包括几个方面,一个是assert中的if判断有可能会对流水线并行造成不好的影响,这个影响可以通过gcc的__builtin_expect内置函数,提前告知编译器代码生成来规避。另外一个不好的影响是会增加可执行代码的大小,影响指令cache的局部性。

但其实更好的做法是,通过编译期的静态检查,将问题提前暴露出来,而不是留到运行期再发现问题。例如还是上述的例子,通过sparse的静态检查,可以这样写:

// 函数本身是非线程安全的,需要在外边上锁保护void dothing_unsafe() __attribute__((context(lock,1,0))){  ... // 执行函数逻辑}

这样就可以在编译期发现问题。


[1] https://lwn.net/Articles/87538/

[2] https://www.kernel.org/doc/html/v5.3/dev-tools/sparse.html

[3] https://www.man7.org/linux/man-pages/man1/sparse.1.html




  推荐站点

  • At-lib分类目录At-lib分类目录

    At-lib网站分类目录汇集全国所有高质量网站,是中国权威的中文网站分类目录,给站长提供免费网址目录提交收录和推荐最新最全的优秀网站大全是名站导航之家

    www.at-lib.cn
  • 中国链接目录中国链接目录

    中国链接目录简称链接目录,是收录优秀网站和淘宝网店的网站分类目录,为您提供优质的网址导航服务,也是网店进行收录推广,站长免费推广网站、加快百度收录、增加友情链接和网站外链的平台。

    www.cnlink.org
  • 35目录网35目录网

    35目录免费收录各类优秀网站,全力打造互动式网站目录,提供网站分类目录检索,关键字搜索功能。欢迎您向35目录推荐、提交优秀网站。

    www.35mulu.com
  • 就要爱网站目录就要爱网站目录

    就要爱网站目录,按主题和类别列出网站。所有提交的网站都经过人工审查,确保质量和无垃圾邮件的结果。

    www.912219.com
  • 伍佰目录伍佰目录

    伍佰网站目录免费收录各类优秀网站,全力打造互动式网站目录,提供网站分类目录检索,关键字搜索功能。欢迎您向伍佰目录推荐、提交优秀网站。

    www.wbwb.net