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;
}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值