libplugin代码注释

使用到内核里的双向链表技术。

 

libplugin代码注释_第1张图片

 




libplugin.c

#include "libplugin.h"
#include 
#include 
#include 
#include 

struct plugin_manager *plugin_manager_create() // 创建插件管理链表
{
    struct plugin_manager *pm = CALLOC(1, struct plugin_manager); //calloc在动态分配完内存后,自动初始化该内存空间为零
    if (!pm) {
        printf("malloc failed!\n");
        return NULL;
    }
    INIT_LIST_HEAD(&pm->plugins);//初始化双向链表
    return pm;
}

void plugin_manager_destroy(struct plugin_manager *pm)
{
    if (!pm) {
        return;
    }
}

static void *plugin_get_func(struct plugin *p, const char *name)
{
    if (!p || !name) {
        return NULL;
    }
    // 函数 dlsym()获取 dlopen()返回的动态加载共享对象的“句柄”以及以空字符结尾的符号名称,并返回将该符号加载到内存中的地址。 
    // dlsym函数的返回值也就是  获取符号名为name 加载到内存中的地址。 而 struct plugin的首地址是名为name的地址,故可将dlsym的返回地址强制转换为 struct plugin
    struct plugin *q = dlsym(p->handle, name);
    if (!q) {
        printf("dlsym failed:%s\n", dlerror());
        return NULL;
    }
    return q;
}


struct plugin *plugin_lookup(struct plugin_manager *pm, const char *name)
{
    if (!pm || !name)
        return NULL;

    struct list_head* head = NULL;
    struct plugin* p = NULL;

    list_for_each(head, &pm->plugins) { //它实际上是一个 for 循环,利用传入的 head 作为循环变量,从表头 pm->plugins 开始,逐项向后(next方向)移动 pos,直至又回 pm->plugins.
        p = list_entry(head, struct plugin, entry); //获取 head 链表所在结构体的首地址,也就是 struct plugin。
        if (0 == strcmp(p->name, name)) { //查找的名字与已存在的名字是否一样
            return plugin_get_func(p, name); // 获取 .so 加载到内存中之后 struct plugin所定义变量的首地址。
        }
    }

    return NULL;
}

struct plugin *plugin_load(struct plugin_manager *pm, const char *path, const char *name)
{
    struct plugin *sym = NULL;
    struct plugin *p = NULL;
    void *handle = dlopen(path, RTLD_LAZY); // 打开 .so 文件
    if (!handle) {
        printf("dlopen failed: %s\n", dlerror());
        goto failed;
    }
    p = plugin_lookup(pm, name);// 目的是判断某个插件是否加载到内存中
    if (p) {
        printf("plugin %s has already loaded!\n", name);
        return p;
    }
    sym = dlsym(handle, name);// dlsym函数的返回值也就是  获取符号名为name 加载到内存中的地址。 而 struct plugin的首地址是名为name的地址,故可将dlsym的返回地址强制转换为 struct plugin
    if (!sym) {
        printf("incompatible plugin, dlsym failed: %s\n", dlerror());
        goto failed;
    }
    p = CALLOC(1, struct plugin);
    if (!p) {
        goto failed;
    }
    p->handle = handle;
    p->name = strdup(name);
    p->path = strdup(path);
    list_add(&p->entry, &pm->plugins);//添加到链表里,方便查询
    return p;

failed:
    if (handle) dlclose(handle);
    if (p) {
        free(p->name);
        free(p->path);
        free(p);
    }
    return NULL;
}

void plugin_unload(struct plugin_manager *pm, const char *name) //释放已加载的插件
{
    struct plugin *p, *tmp;
    list_for_each_entry_safe(p, tmp, &pm->plugins, entry) {
        dlclose(p->handle);
        list_del(&p->entry); // 链表删除
        free(p->name);
        free(p->path);
        free(p);
    }
}

struct plugin *plugin_reload(struct plugin_manager *pm, const char *path, const char *name)
{
    plugin_unload(pm, name);
    return plugin_load(pm, path, name);
}



libplugin.h

#ifndef LIBPLUGIN_H
#define LIBPLUGIN_H

#include 
#include 

#ifdef __cplusplus
extern "C" {
#endif

struct version {
    int major;
    int minor;
    int patch;
};

struct plugin {
    char *name;
    char *path;
    struct version version;

    void *(*open)(void *arg);
    void (*close)(void *arg);
    void *(*call)(void *arg0, ...);

    void *handle;
    struct list_head entry;
};

struct plugin_manager {
    struct list_head plugins;
};

struct plugin_manager *plugin_manager_create();
void plugin_manager_destroy(struct plugin_manager *);

struct plugin *plugin_lookup(struct plugin_manager *pm, const char *name);
struct plugin *plugin_load(struct plugin_manager *pm, const char *path, const char *name);
void plugin_unload(struct plugin_manager *pm, const char *name);
struct plugin *plugin_reload(struct plugin_manager *pm, const char *path, const char *name);

/*
 * using HOOK_CALL(func, args...), prev/post functions can be hook into func
 */
#define HOOK_CALL(fn, ...)                                \
    ({                                                    \
        fn##_prev(__VA_ARGS__);                           \
        __typeof__(fn) *sym =  dlsym(RTLD_NEXT, #fn);     \
        if (!sym) {return NULL;}                          \
        sym(__VA_ARGS__);                                 \
        fn##_post(__VA_ARGS__);                           \
    })

/*
 * using CALL(fn, args...), you need override api
 */
#define CALL(fn, ...)                                     \
    ({__typeof__(fn) *sym = (__typeof__(fn) *)            \
                            dlsym(RTLD_NEXT, #fn);        \
     sym(__VA_ARGS__);})


#ifdef __cplusplus
}
#endif
#endif



plugin_ipc.c


#include "../libplugin.h"

static void *ipc_open(void *arg)
{
    printf("ipc_open\n");
    return NULL;
}

struct plugin plugin_ipc = {
    .name = "plugin_ipc",
    .version = {1, 0, 0},
    .open = ipc_open,
};


test_libplugin.c

#include "libplugin.h"
#include 
#include 

struct plugin_info {
    char *path;
    char *name;
};

struct plugin_info p_info[] = {
    {"./modules/plugin_log.so", "plugin_log"},
    {"./modules/plugin_ipc.so", "plugin_ipc"},
    {"./modules/plugin_skt.so", "plugin_skt"},
};

#define SIZEOF(array)       (sizeof(array)/sizeof(array[0]))
static struct plugin_manager *pm = NULL;
void init()
{
    int i = 0;
    struct plugin *p = NULL;
    pm = plugin_manager_create(); // 创建插件管理链表
    if (!pm) {
        printf("plugin_manager_create failed!\n");
        return;
    }
    for (i = 0; i < SIZEOF(p_info); i++) {
        p = plugin_load(pm, p_info[i].path, p_info[i].name); //加载动态库。 初始化,并注册到链表里
        if (!p) {
            printf("plugin_load failed!\n");
            return;
        }
    }
}

void deinit()
{
    int i = 0;
    for (i = 0; i < SIZEOF(p_info); i++) {
        plugin_unload(pm, p_info[i].name); 释放已加载的插件
    }
    plugin_manager_destroy(pm);
}

void foo()
{
    char *name = "plugin_ipc";
    struct plugin *p = plugin_lookup(pm, name); // 根据名字,找到struct plugin的首地址
    if (!p) {
        printf("plugin_lookup %s failed!\n", name);
        return;
    }
    p->open(NULL); // 调用 plugin_ipc 的 open函数
    printf("name=%s, version=%d,%d,%d\n", p->name, p->version.major, p->version.minor, p->version.patch);
}

int main(int argc, char **argv)
{
    init();
    foo();
    deinit();
    return 0;
}

你可能感兴趣的:(gear-lib的使用)