cherokee 插件加载器源码剖析
cherokee 服务器的绝大部分功能都是用插件实现的, 因此要理解cherokee的源码首先需要理解的就是cherokee的插件.
插件相关的主要结构体有以下几个.
// 插件, 对应于每个插件 typedef struct { cherokee_plugin_type_t type; void *instance; void *configure; const char *name; } cherokee_plugin_info_t; // 插件加载器实体, 对应于每个插件 typedef struct { cherokee_plugin_info_t *info; // 从动态库中读取的插件info void *dlopen_ref;// dlopen打开的动态链接库 cherokee_boolean_t built_in; } cherokee_plugin_loader_entry_t; // 插件加载器, 每个Server上只有一个, 对应于每个进程 typedef struct { cherokee_avl_t table; // AVL 树包含了所有插件名-实体的键值对 cherokee_buffer_t module_dir;// 模块目录 cherokee_buffer_t deps_dir; // 依赖插件目录 } cherokee_plugin_loader_t;
插件加载器各部分之间的关系
以下便是插件加载的过程, 注释上已经写得很清楚了.
static ret_t get_info (cherokee_plugin_loader_t *loader, const char *module, int flags, cherokee_plugin_info_t **info, void **dl_handler) { ret_t ret; cherokee_buffer_t info_name = CHEROKEE_BUF_INIT; /* Build the info struct string */ cherokee_buffer_add_va (&info_name, "cherokee_%s_info", module); /* Open it 加载动态链接库到dl_handler */ ret = dylib_open (loader, module, flags, dl_handler); if (ret != ret_ok) { cherokee_buffer_mrproper (&info_name); return ret_error; } // 从动态库中读取插件info 结构体(cherokee_plugin_info_t) // *info = get_sym_from_dlopen_handler (*dl_handler, info_name.buf); if (*info == NULL) { cherokee_buffer_mrproper (&info_name); return ret_not_found; } /* Free the info struct string */ cherokee_buffer_mrproper (&info_name); return ret_ok; } static ret_t check_deps_file (cherokee_plugin_loader_t *loader, const char *modname) { FILE *file; char temp[128]; cherokee_buffer_t filename = CHEROKEE_BUF_INIT; // 将路径名拷贝到buffer, cherokee_buffer_add_va (&filename, "%s/%s.deps", loader->deps_dir.buf, modname); file = fopen (filename.buf, "r"); if (file == NULL) goto exit; while (!feof(file)) { int len; char *ret; // 读取插件名 ret = fgets (temp, 127, file); if (ret == NULL) break; len = strlen (temp); if (len < 2) continue; if (temp[0] == '#') continue; if (temp[len-1] == '\n') temp[len-1] = '\0'; // 加载插件 cherokee_plugin_loader_load (loader, temp); temp[0] = '\0'; } fclose (file); exit: cherokee_buffer_mrproper (&filename); return ret_ok; } static ret_t load_common (cherokee_plugin_loader_t *loader, const char *modname, int flags) { ret_t ret; entry_t *entry = NULL; cherokee_plugin_info_t *info = NULL; void *dl_handle = NULL; /* If it is already loaded just return * 在AVL 树中查找插件名, 如果找到说明插件已经加载, 直接返回 */ ret = cherokee_avl_get_ptr (&loader->table, modname, (void **)&entry); if (ret == ret_ok) return ret_ok; /* Check deps * 加载依赖的其他插件, 从文件中读取插件名然后递归调用cherokee_plugin_loader_load 加载 */ ret = check_deps_file (loader, modname); if (ret != ret_ok) return ret; /* Get the module info * 加载插件对应的动态库文件, 并取得插件info 结构体 */ ret = get_info (loader, modname, flags, &info, &dl_handle); switch (ret) { case ret_ok: break; case ret_error: LOG_ERROR (CHEROKEE_ERROR_PLUGIN_NO_OPEN, modname); return ret; case ret_not_found: LOG_ERROR (CHEROKEE_ERROR_PLUGIN_NO_INFO, modname); return ret; default: SHOULDNT_HAPPEN; return ret_error; } /* Add new entry * 创建新的插件实体, 设置info 和dl_handle, 插入到AVL树中 */ entry = malloc (sizeof(entry_t)); if (entry == NULL) { return ret_nomem; } entry->dlopen_ref = dl_handle; entry->info = info; entry->built_in = false; ret = cherokee_avl_add_ptr (&loader->table, modname, entry); if (unlikely(ret != ret_ok)) { dlclose (entry->dlopen_ref); free(entry); return ret; } /* Execute init function * 从 dl_handle 中读出插件初始化函数cherokee_plugin_<name>_init, 并调用 */ ret = execute_init_func (loader, modname, entry); if (ret != ret_ok) { return ret; } return ret_ok; } // 取得插件结构体 ret_t cherokee_plugin_loader_get (cherokee_plugin_loader_t *loader, const char *modname, cherokee_plugin_info_t **info) { ret_t ret; // 加载插件动态链接库 ret = cherokee_plugin_loader_load (loader, modname); if (ret != ret_ok) return ret; // 取得结构体 ret = cherokee_plugin_loader_get_info (loader, modname, info); if (ret != ret_ok) return ret; return ret_ok; }