最近在看内核中 qspinlock
相关的代码,发现了一些有意思的实现,尤其是在 kernel/locking/qspinlock.c
文件的最后几行,通过 #include "qspinlock.c"
语句又把这个 C
文件的内容包含了进来,但前提是在 #include
之前把某些关键的宏定义改了,这就使得在处理新包含进来的文件内容时,能够得到与上面第一次处理时不一样的结果,这在很大程度上复用了代码。
下面通过一个简化版的例子来展示上述实现的细节:
首先定义 file.c
文件,它的实现类似于上述 kernel/locking/qspinlock.c
文件:
#ifndef _GEN_PV_LOCK_SLOWPATH
#include <stdbool.h>
#include <stdio.h>
#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 <stdio.h>
#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);
#endif
void test(void)
{
#ifdef CONFIG_PARAVIRT_SPINLOCKS
native_queued_spin_lock_slowpath();
printf("=========================================================\n");
__pv_queued_spin_lock_slowpath();
#else
queued_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