最近在看内核中 qspinlock
相关的代码,发现了一些有意思的实现,尤其是在 kernel/locking/qspinlock.c
文件的最后几行,通过 #include "qspinlock.c"
语句又把这个 C
文件的内容包含了进来,但前提是在 #include
之前把某些关键的宏定义改了,这就使得在处理新包含进来的文件内容时,能够得到与上面第一次处理时不一样的结果,这在很大程度上复用了代码。
下面通过一个简化版的例子来展示上述实现的细节:
首先定义 file.c
文件,它的实现类似于上述 kernel/locking/qspinlock.c
文件:
#ifndef _GEN_PV_LOCK_SLOWPATH#include
#include
#include "file.h"static void __pv_init_node(void)
{printf("dummy\n");
}#define pv_enabled() false#define pv_init_node __pv_init_node#ifdef CONFIG_PARAVIRT_SPINLOCKS
#define queued_spin_lock_slowpath native_queued_spin_lock_slowpath
#endif#endif /* _GEN_PV_LOCK_SLOWPATH */EXPORT_SYMBOL(queued_spin_lock_slowpath);
void queued_spin_lock_slowpath(void)
{if (pv_enabled()) {printf("pv enabled\n");} else {printf("pv not enabled\n");}pv_init_node();printf("symbol of this function: %s\n", SYMBOL_NAME(queued_spin_lock_slowpath));
}#if !defined(_GEN_PV_LOCK_SLOWPATH) && defined(CONFIG_PARAVIRT_SPINLOCKS)
#define _GEN_PV_LOCK_SLOWPATH#undef pv_enabled
#define pv_enabled() true#undef pv_init_node
void pv_init_node(void)
{printf("not dummy\n");
}#undef queued_spin_lock_slowpath
#define queued_spin_lock_slowpath __pv_queued_spin_lock_slowpath#include "file.c"#endif
再定义与之配套的 file.h
文件
#ifndef _FILE_H_
#define _FILE_H_#define SYMBOL_NAME(name) __SYMBOL_NAME(name)
#define __SYMBOL_NAME(name) __sym_##name#define DECLARE_SYMBOL(name) char *SYMBOL_NAME(name)#define EXTERN_SYMBOL(name) extern DECLARE_SYMBOL(name)#define __EXPORT_SYMBOL(name) \DECLARE_SYMBOL(name) = #name#define EXPORT_SYMBOL(name) __EXPORT_SYMBOL(name)#endif
最后定义 main.c
文件
#include
#include "file.h"#ifdef CONFIG_PARAVIRT_SPINLOCKS
EXTERN_SYMBOL(native_queued_spin_lock_slowpath);
EXTERN_SYMBOL(__pv_queued_spin_lock_slowpath);
#else
EXTERN_SYMBOL(queued_spin_lock_slowpath);
#endifvoid test(void)
{
#ifdef CONFIG_PARAVIRT_SPINLOCKSnative_queued_spin_lock_slowpath();printf("=========================================================\n");__pv_queued_spin_lock_slowpath();
#elsequeued_spin_lock_slowpath();
#endif
}int main(void)
{test();return 0;
}
下面通过 CONFIG_PARAVIRT_SPINLOCKS
宏来展示两种不同的用法。
如果不定义 CONFIG_PARAVIRT_SPINLOCKS
宏,相当于 queued_spin_lock_slowpath()
只有一种实现: 即native_queued_spin_lock_slowpath()
。
而如果定义了 CONFIG_PARAVIRT_SPINLOCKS
宏,相当于 queued_spin_lock_slowpath()
有两种实现:即native_queued_spin_lock_slowpath()
和 __pv_queued_spin_lock_slowpath()
。
用法一:不定义 CONFIG_PARAVIRT_SPINLOCKS
宏
运行结果如下所示:
$ gcc -o main main.c file.c -I./
$ ./main
pv not enabled
dummy
symbol of this function: queued_spin_lock_slowpath
用法二:定义CONFIG_PARAVIRT_SPINLOCKS
宏
运行结果如下所示:
$ gcc -o main main.c file.c -I./ -DCONFIG_PARAVIRT_SPINLOCKS
$ ./main
pv not enabled
dummy
symbol of this function: native_queued_spin_lock_slowpath
=========================================================
pv enabled
not dummy
symbol of this function: __pv_queued_spin_lock_slowpath