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_tget_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_tcheck_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_tload_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_tcherokee_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;}