momo zone

调核人的blog

__KERNEL__ 宏作用是什么?

这个宏在内核及应用程序代码中均能看到。它仅起到判断作用,而不是在实际的代码逻辑中被替换,就如之前讲的避免define重复定义的用法一样。但不同的是这个宏的目的并不是避免重复定义,那么这个宏到底是什么意思?  先看下这一段:

cmd_kernel/sched.o := gcc -Wp,-MD,kernel/.sched.o.d  -nostdinc -isystem /usr/lib/gcc/i586-suse-linux/4.5/include -I/usr/src/linux-2.6.39.1-4/arch/x86/include -Iinclude  -include include/generated/autoconf.h -D__KERNEL__ -Wall -Wundef -Wstrict-prototypes -Wno-trigraphs -fno-strict-aliasing -fno-common -Werror-implicit-function-declaration -Wno-format-security -fno-delete-null-pointer-checks -O2 -m32 -msoft-float -mregparm=3 -freg-struct-return -mpreferred-stack-boundary=2 -march=i686 -mtune=core2 -mtune=generic -maccumulate-outgoing-args -Wa,-mtune=generic32 -ffreestanding -DCONFIG_AS_CFI=1 -DCONFIG_AS_CFI_SIGNAL_FRAME=1 -DCONFIG_AS_CFI_SECTIONS=1 -pipe -Wno-sign-compare -mno-sse -mno-mmx -mno-sse2 -mno-3dnow -Wframe-larger-than=2048 -fno-stack-protector -fno-omit-frame-pointer -fno-optimize-sibling-calls -fasynchronous-unwind-tables -g -Wdeclaration-after-statement -Wno-pointer-sign -fno-strict-overflow -fconserve-stack -DCC_HAVE_ASM_GOTO -fno-omit-frame-pointer    -D”KBUILD_STR(s)=\#s” -D”KBUILD_BASENAME=KBUILD_STR(sched)”  -D”KBUILD_MODNAME=KBUILD_STR(sched)” -c -o kernel/.tmp_sched.o kernel/sched.c

这是内核中编译kernel/sched.c 时的编译参数,可以看到gcc -D__KERNEL__  ,其实几乎所有内核编译参数都包括它。 再看看include/linux/sched.h

#ifndef _LINUX_SCHED_H
#define _LINUX_SCHED_H

/*
 * cloning flags:
 */
#define CSIGNAL		0x000000ff	/* signal mask to be sent at exit */
#define CLONE_VM	0x00000100	/* set if VM shared between processes */
.......
#define CLONE_DETACHED		0x00400000	/* Unused, ignored */
#define CLONE_UNTRACED		0x00800000	/* set if the tracing process can't force CLONE_PTRACE on this clone */
.......
#define CLONE_NEWPID		0x20000000	/* New pid namespace */
#define CLONE_NEWNET		0x40000000	/* New network namespace */
#define CLONE_IO		0x80000000	/* Clone io context */

/*
 * Scheduling policies
 */
#define SCHED_NORMAL		0
#define SCHED_FIFO		1
#define SCHED_RR		2
#define SCHED_BATCH		3
/* SCHED_ISO: reserved but not implemented yet */
#define SCHED_IDLE		5
/* Can be ORed in to make sure the process is reverted back to SCHED_NORMAL on fork */
#define SCHED_RESET_ON_FORK     0x40000000

#ifdef __KERNEL__

struct sched_param {
	int sched_priority;
};

#include <asm/param.h>	/* for HZ */

#include <linux/capability.h>
......
#endif

可以看到如果定义了 __KERNEL__ 则会多编译一段。而多编译的这一段是只有像内核这样的代码会用到的。
这样考虑一下:我为某个设备写了一个设备驱动,毫无疑问编译的时候肯定会加上__KERNEL__,然后这个驱动往往还要提供一个库文件,为应用程序提供访问某些变量或函数的接口。最后我们要写一个应用程序来操纵设备。那么在编写这个应用程序的时候假如库文件提供的东西还不够,比如库文件没有定义上述的#define CLONE_DETACHED 0x00400000,而库文件的API 函数包含返回CLONE_DETACHED 的可能,那么就无法用if(CLONE_DETACHED==fun(arg)) 来做判断了(当然你可以去扒内核代码去比较0x004000000)。那么应用程序代码中肯定要包含这内核头文件了(现在不推荐这样做了),那么就出现了一个问题,让应用程序引用内核头文件会暴露很多内核的细节和增加目标文件的大小,因为很多内核结构或变量,应用程序几乎用不着。那么就要设置一个边界,设定哪些是只有给内核代码可见的,哪些是开放给所有代码可见的。 这个边界就是__KERNEL__ 宏。其实实际的做法是所有该引用的内核头文件,变量或结构都要库的头文件中包含,这些属于内核的东东往往要重新定义在库的头文件中,然后再提供给应用程序去引用。

这里有另外一位牛人的解释:

Paul Mackerras writes:

> The only valid reason for userspace programs to be including kernel
> headers is to get definitions that are part of the kernel API. (And
> in fact others here will go further and assert that there are *no*
> valid reasons for userspace programs to include kernel headers.)
>
> If you want some atomic functions or whatever for your userspace
> program and the ones in the kernel look like they would be useful,
> then take a copy of the relevant kernel code if you like, but don’t
> include the kernel headers directly.

Sure. That copy belongs in /usr/include/asm for all programs
to use, and it should match the libc that will be linked against.
(note: “copy”, not a symlink)

Red Hat 7 gets this right:

$ ls -ldog /usr/include/asm /usr/include/linux
drwxr-xr-x 2 root 2048 Sep 28 2000 /usr/include/asm
drwxr-xr-x 10 root 10240 Sep 28 2000 /usr/include/linux

Debian’s “unstable” is correct too:

$ ls -ldog /usr/include/asm /usr/include/linux
drwxr-xr-x 2 root 6144 Mar 12 15:57 /usr/include/asm
drwxr-xr-x 10 root 23552 Mar 12 15:57 /usr/include/linux

> This is why I added #ifdef __KERNEL__ around most of the contents
> of include/asm-ppc/*.h. It was done deliberately to flush out those
> programs which are depending on kernel headers when they shouldn’t.

What, is </usr/src/linux/asm/foo.h> being used? I doubt it.

If /usr/include/asm is a link into /usr/src/linux, then you
have a problem with your Linux distribution. Don’t blame the
apps for this problem.

Adding “#ifdef __KERNEL__” causes extra busywork for someone
trying to adapt kernel headers for userspace use. At least do
something easy to rip out. Three lines, all together at the top:

#ifndef __KERNEL__
#error Raw kernel headers may not be compatible with user code.
#endif

Advertisements

发表评论

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / 更改 )

Twitter picture

You are commenting using your Twitter account. Log Out / 更改 )

Facebook photo

You are commenting using your Facebook account. Log Out / 更改 )

Google+ photo

You are commenting using your Google+ account. Log Out / 更改 )

Connecting to %s

%d 博主赞过: