http://linuxkernel.net/faq/index.php?cmd=read§ion=kernel-general2&num=4
Q: 소스 중에 보면 어떤 함수들은 함수 이름 앞에 __init라고 붙어있거나, 함수의 프로토타입을 __initfunc() 매크로로 둘러싸고 있는 것이 있습니다. 이것의 역할은 무엇입니까?
A: 소스를 보다 보면 함수 이름앞에 __init라고 되어 있거나, 변수 이름 뒤에 __initdata라고 적힌 것을 볼 수 있습니다.
예를 들어 init/main.c에서 :
asmlinkage void __init start_kernel(void);
static void __init smp_init(void);
static void __init do_basic_setup(void);
static struct dev_name_struct { ... } root_dev_names[] __initdata;
여기에 나오는 __init나 __initdata는 해당하는 함수나 변수가 운영체제의 초기화 과정에만 사용된다는 것을 의미합니다. start_kernel()이나 kernel/sched.c에 있는 sched_init(), arch/i386/mm/init.c에 있는 mem_init() 처럼 초기화 과정에만 사용되는 함수는 일단 초기화 과정이 끝나면 더이상 필요가 없습니다. 초기화를 마친 후에 이들을 계속해서 메모리에 남겨두고 있을 필요가 없다는 것이죠. 그래서 이런 초기화에만 필요한 함수나 변수를 별도의 영역에 따로 모아두었다가, 초기화를 마친 후 이 영역의 메모리를 해제합니다. 그렇게 하면 필요없는 메모리를 제거하여 커널이 차지하는 메모리의 양을 줄일 수 있게 됩니다. 이를 위해 초기화에만 관련되어 있는 함수나 변수를 따로 표시하기 위해서 __init나 __initdata라는 것을 사용합니다.
이들은 2.4.x 커널에서는 include/linux/init.h에 정의가 되어 있고 2.2.x 커널에서는 include/linux/init.h와 include/asm/init.h에 정의되어 있습니다.
include/linux/init.h 소스를 살펴보면 :
/* These macros are used to mark some functions or
* initialized data (doesn't apply to uninitialized data)
* as `initialization' functions. The kernel can take this
* as hint that the function is used only during the initialization
* phase and free up used memory resources after
*
* Usage:
* For functions:
*
* You should add __init immediately before the function name, like:
*
* static void __init initme(int x, int y)
* {
* extern int z; z = x * y;
* }
*
* If the function has a prototype somewhere, you can also add
* __init between closing brace of the prototype and semicolon:
*
* extern int initialize_foobar_device(int, int, int) __init;
*
* For initialized data:
* You should insert __initdata between the variable name and equal
* sign followed by value, e.g.:
*
* static int init_variable __initdata = 0;
* static char linux_logo[] __initdata = { 0x32, 0x36, ... };
*
* For initialized data not at file scope, i.e. within a function,
* you should use __initlocaldata instead, due to a bug in GCC 2.7.
*/
여기서는 __init나 __initdata를 사용하는 방법을 말하고 있습니다. __init는 함수를 정의할 때는 함수의 이름 앞에 들어가지만, 프로토타입이 이미 다른 곳에서 선언되어 있는 경우에는 프로토타입의 끝과 세미콜론 사이에 넣을 수 있습니다. 초기화되는 변수의 경우에는 변수의 이름과 변수에 초기값을 지정하는 '=' 사이에 __initdata를 넣습니다.
계속해서 :
#ifndef MODULE
/*
* Mark functions and data as being only used at initialization
* or exit time.
*/
#define __init __attribute__ ((__section__ (".text.init")))
#define __exit __attribute__ ((unused, __section__(".text.exit")))
#define __initdata __attribute__ ((__section__ (".data.init")))
#define __exitdata __attribute__ ((unused, __section__ (".data.exit")))
#define __initsetup __attribute__ ((unused,__section__ (".setup.init")))
#define __init_call __attribute__ ((unused,__section__ (".initcall.init")))
/* For assembly routines */
#define __INIT .section ".text.init","ax"
#define __FINIT .previous
#define __INITDATA .section ".data.init","aw"
#define module_init(x) __initcall(x);
#define module_exit(x) /* nothing */
#else
#define __init
#define __exit
#define __initdata
#define __exitdata
#define __initcall(fn)
/* For assembly routines */
#define __INIT
#define __FINIT
#define __INITDATA
#define module_init(x) int init_module(void) __attribute__((alias(#x)));
#define module_exit(x) void cleanup_module(void) __attribute__((alias(#x)));
#endif
여기서는 각각이 어떤 섹션에 들어가는지를 지정합니다. __init로 정의된 함수들은 .text.init 섹션에, __initdata로 정의된 변수는 .data.init에 들어갑니다. 여기에서 __exit, __exitdata라는 것을 볼 수 있는데 이들은 종료를 할 때 불리는 함수나 이와 관련된 변수들을 지정할 때 사용합니다. 어떤 드라이버가 커널에 포함되어 있는 경우 시스템을 종료할 때 각각의 종료함수를 부르지 않아도 되기 때문에 이들 역시 메모리에서 제거될 수 있습니다. 커널은 시스템 초기화를 마친 직후 이들 버릴 수 있는 섹션에 있는 메모리들을 해제합니다.
이러한 기능은 커널에만 해당하지 모듈에는 해당하지 않습니다. 위의 코드에서 보듯이 모듈인 경우에는 이들은 아무 역할도 하지 않도록 되어 있습니다. 모듈에서는 이와 같은 기능을 제공하지 않기 때문입니다.
어떤 함수는 __initfunc()라는 매크로에 둘러 싸여있는 것도 있습니다. 예를 들어 2.4.x 커널의 driver/block/lvm.c를 보면 :
#ifdef __initfunc
__initfunc(int lvm_init(void))
#else
int __init lvm_init(void)
#endif
__initfunc()은 해당 함수가 초기화에 관련된 함수라는 것을 알려줍니다. 이것은 __init라고 지정하는 것과 같은 일을 하는 것으로 옛날 코드의 잔재라고 생각하면 됩니다. 이렇게 정의되는 함수들은 대부분 디바이스 드라이버의 초기화와 setup에 관련된 함수입니다. 이들 역시 초기화 이후에 필요가 없으므로 제거될 수 있습니다.
by flyduck 2000/06/28