现在的位置: 首页 > 综合 > 正文

__context__属性

2013年10月19日 ⁄ 综合 ⁄ 共 1704字 ⁄ 字号 评论关闭

 在分析自旋锁代码时,最终跟踪下来,会在 include/linux/compiler.h 中看到下面的代码:

1
2
3
4
5
6
7
8
9
10
11
12
#ifdef __CHECKER__
...
# define __acquire(x)    __context__(x,1)
# define __release(x)    __context__(x,-1)
...
#else
# define __acquire(x) (void)0
# define __release(x) (void)0
  
  
...
#endif

其中含有 __context__ 这种属性。刚开始时认为这也是 gcc 支持的属性一种,其实不然。在应用程序里,模拟上面宏定义并包含 __context__ ,然后用 gcc 编译一下,会有错误提示。

实际上,该属性是提供给一种叫 sparse 的工具进行代码的静态检查的。关于 sparse 的介绍可参考:

引用

在我们编译内核代码时,在 make 时使用 C=1 或者 C=2 选项时都会对 sparse 工具的调用。

sparse 进行代码静态检查并不会对代码进行编译,也不会进行相关宏的处理,它的工作只是检查而已。那么可能会有疑问,检查后,那最终还不是要用 gcc 来编译么?那这样一来不是还不能编译通过?这里需要注意到,像 # define __acquire(x)    __context__(x,1) 这个宏,需要在 __CHECKER__ 这个宏定义下才能使用。那么搜遍整个内核代码,会发现没有 __CHECKER__ 的定义。但是回过头来查看 sparse 相关的源码时,会发现在对 sparse 初始化的函数里有这么一段(位于
lib.c 中):

1
2
3
4
5
6
struct
symbol_list *sparse_initialize(int
argc, char
**argv,
struct
string_list **filelist)
{
     ....
     add_pre_buffer("#define __CHECKER__ 1\n");
     ...
}

再看 add_pre_buffer() 函数:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
void
add_pre_buffer(
const
char
*fmt, ...)
{
        va_list
args;
        unsigned
int size;
        struct
token *begin, *end;
        char
buffer[4096];
  
  
        va_start(args, fmt);
        size = vsnprintf(buffer,
sizeof(buffer), fmt, args);
        va_end(args);
        begin = tokenize_buffer(buffer, size, &end);
        if
(!pre_buffer_begin)
                pre_buffer_begin = begin;
        if
(pre_buffer_end)
                pre_buffer_end->next = begin;
        pre_buffer_end = end;
}

上面,就是将 "#define __CHECKER__ 1" 这一个字符串通过 vsnprintf(buffer, sizeof(buffer), fmt, args); 拷贝到缓冲区中。

一般的,对代码的静态检查工具,基本工作原理是将要检查的源代码读入缓冲区中在进行比较。所以,__CHECKER__ 这个定义是先在 sparse 的工具的缓冲区中定义好,这样,我们自然就能够使用带有 __context__ 属性的宏了。需要注意一点,带有 __context__ 的宏,只能在缓冲区中比较,在内核中最后仍然是使用没有 __context__ 这种属性的宏的,也就是说最终用到的是:

1
2
# define __acquire(x) (void)0
# define __release(x) (void)0

抱歉!评论已关闭.