利用 constructor 属性完成 module_init() 设计模式


一、简介

1. __attribute__语法格式为:__attribute__ (( attribute-list ))

若函数被设定为 constructor 属性,则该函数会在 main() 函数执行之前被自动的执行。类似的,若函数被设定为 destructor 属性,则该函数会在 main() 函数执行之后或者 exit() 被调用后被自动的执行。

2. 当存在多个 __attribute__((constructor)) 修饰的函数时,也不用持锁,因为是单线程执行的。

3. 还可以使用 __attribute__((constructor(prio))) 指定优先级,从而决定调用次序,优先级prio取值范围是 0--65535,其中 0--100 是预留的,不能使用,优先级数值越小优先级越高,越优先被执行调用。只要指定了优先级,就算是指定的优先级是65535也还是会比没有指定优先级的先调用。

二、 测试例子

1. C程序

#include

__attribute__((constructor)) void before_main()  
{  
   printf("before main.\n");  
}  
  
__attribute__((destructor)) void after_main()  
{  
   printf("after main.\n");  
}  
  
int main()  
{  
   printf("in main.\n");  
   return 0;  
}

/*
//执行结果:
$ ./pp
before main.
in main.
after main.
*/

2. C++程序

#include

using namespace std;


__attribute__((constructor)) void before_main() // void 在前后都行
{  
    //cout<<"Before Main"<//注释掉就不 Segmentation fault 了。
    int i;
    i++;
}

__attribute__((destructor)) void after_main()  
{  
    cout<<"After Main"<<endl;  
}


class AAA{  
public:  
    AAA(){  
        cout<<"AAA construct"<<endl;  
    }     
    ~AAA(){  
        cout<<"AAA destructor" <<endl;  
    }     
};

AAA A; //全局类对象


int main()  
{  
    cout<<"in main"<<endl;  
    return 0;  
}

/*
执行结果:
$ ./pp
AAA construct
in main
AAA destructor
After Main
*/

注:测试发现,C++中 __attribute__((constructor)) 修饰的函数中不能执行 cout<<"..."<


三、实现类似Linux内核中 module_init() 的设计模式

1. 实现

Linux内核中 module_init() 是通过链接器脚本实现的,用户空间程序可以使用 constructor 属性实现。

(1) core.c

#include 
#include 
#include "core.h"

struct function *g_functions[FUNC_NUM] = {NULL};

static int module_init()
{
    int i, ret = 0;

    for (i = 0; i < ARRAY_SIZE(g_functions); i++) {
        if (g_functions[i]) {
            ret = g_functions[i]->init();
        }
    }

    return ret;
}

static int module_exit()
{
    int i;

    for (i = 0; i < ARRAY_SIZE(g_functions); i++) {
        if (g_functions[i]) {
            g_functions[i]->release();
            g_functions[i] = NULL;
        }
    }

    return 0;
}

static int module_do_function(int code)
{
    int i, ret = 0;

    for (i = 0; i < ARRAY_SIZE(g_functions); i++) {
        if (g_functions[i] && g_functions[i]->id == code) {
            ret = g_functions[i]->execute(code);
        }
    }

    return ret;
}


int main(int argc, char *argv[])
{
    int ret, code = 0;

    if (argc == 2) {
        code = atoi(argv[1]);
    }

    module_init();
    module_do_function(code);
    module_exit();
}

(2) core.h

#define FUNC_NUM 16

#define ARRAY_SIZE(a) (sizeof(a) / sizeof(*a))

struct function {
    int id;
    int (*init)(void);
    int (*execute)(int code);
    void (*release)(void);
};

extern struct function *g_functions[FUNC_NUM];


#define function_register(name)                                    \
void __attribute__((constructor)) function_##name##_register(void) \
{                                                                  \
    int i;                                                         \
    for (i = 0; i < ARRAY_SIZE(g_functions); i++) {                \
        if (!g_functions[i]) {                                     \
            g_functions[i] = &func_##name;                         \
            break;                                                 \
        }                                                          \
    }                                                              \
    printf("%s, id=%d.\n", __func__, func_##name.id);              \
}

(3) camera.c

#include 
#include "core.h"

#define CAMERA_FUN_ID 1


static int camera_init(void) {
    int ret = 0;

    printf("camera_init called.\n");

    return ret;
}

static int camera_execute(int code) {
    int ret = 0;

    printf("camera_execute called.\n");

    return ret;
}

static void camera_release(void) {
    printf("camera_release called.\n");
}

static struct function func_camera = {
    .id = CAMERA_FUN_ID,
    .init = camera_init,
    .execute = camera_execute,
    .release = camera_release,
};

function_register(camera);

(4) led.c

#include 
#include "core.h"

#define LED_FUN_ID 2


static int led_init(void) {
    int ret = 0;

    printf("led_init called.\n");

    return ret;
}

static int led_execute(int code) {
    int ret = 0;

    printf("led_execute called.\n");

    return ret;
}

static void led_release(void) {
    printf("led_release called.\n");
}

static struct function func_led = {
    .id = LED_FUN_ID,
    .init = led_init,
    .execute = led_execute,
    .release = led_release,
};

function_register(led);

2. 测试

$ gcc *.c -o pp

$ ./pp
function_camera_register, id=1.
function_led_register, id=2.
camera_init called.
led_init called.
camera_release called.
led_release called.

$ ./pp 1
function_camera_register, id=1.
function_led_register, id=2.
camera_init called.
led_init called.
camera_execute called.
camera_release called.
led_release called.

3. 若需要再添加其它命令,值需要添加一个文件并注册即可,不用改原有文件。