学习《apache源代码全景分析》之DSO概念

        DSO的产生当然离不开操作系统的支持。目前不管是UNIX还是Linux,大多都提供了对动态共享对象或动态链接库进行加载和卸载的机制。加载的方法通常有两种:其一是在可执行文件启动时由系统程序ld.so自动加载;其二是在执行程序过程中手工通过Unix提供的动态链接库加载接口进行加载。

1.Linux下的DSO

     Linux下的DSO操作函数主要包括以下几个:

  •     void *dlopen(const char *pathname, int mode);  

           该函数用来加载动态库,其中pathname是需要加载的库的路径名称,mode则是加载的方式。可以为三个值:RTLD_LAZY表示未定义的符号是来自动态链接库的代码;RTLD_NOW表示要在dlopen返回前确定所有未定义的符号,如不能完成,则执行失败;而RTLD_GLOBAL则表示动态链接库中定义的外部符号可以被随后加载的库使用。如果函数执行成功,将返回动态链接库中的一个句柄。一旦对动态库进行了加载,就可以通过dlsym函数获取库中的函数调用及各种定义的符号等。

  •     void *dlsym(void *handle, char *symbol);

           其中,handle是加载的动态链接库的句柄,它通常是dlopen函数的操作结果;symbol是要得到的动态链接库中的符号名称。如果找不到symbol,函数将返回NULL。

           在所有的操作结束后,Linux可以通过dlclose将dlopen先前打开的共享对象从当前进程断开,但只有当动态链接库的使用计数为0时,该共享对象才会真正被卸载。

  •     int dlclose(void *handle);

           一旦使用dlclose关闭了对象,dlsym就再也不能使用它的符号了。

       简单演示dlopen、dlsym、dlclose三部曲的使用:

void *handle, *handle2;
handle = dlopen("libdisplay.so", RTLD_LAZY);
if (handle != NULL) {
    handle2 = dlsym(handle, "draw");
    if (handle2 != NULL) {
        ......      /* use the function */
    }
    /* When finished, unload the shared library */
    dlclose(handle);
}

2.APR DSO封装

    Apache中提供了统一的DSO操作接口,以便在不同的操作系统平台上执行相同的操作,这四个接口分别为:

     (1) APR_DECLARE(apr_status_t)apr_dso_load(apr_dso_handle_t **res_handle, const char *path, apr_pool_t *ctx);

          apr_dso_load函数实现对so文件的动态加载。path是so文件的绝对路径,ctx则是其使用的内存池,该函数用来载入DSO动态共享库。res_handle_Location用来存储新的DSO的处理句柄,path则是DSO库的路径位置。

         apr_dso_load的实现分为7种平台:AIX、beos、netware、OS2、OS390、Unix及Win32.

         apr_dso_load内部首先调用dlopen对模块进行加载,然后返回加载后的句柄os_handle,同时将句柄保存在apr_dso_handle_t类型变量res_handle的handle中。res_handle需要的所有资源来自内存池ctx.最后调用apr_pool_cleanup_register函数注册内存池ctx的清除函数dso_cleanup。下面是apr_dso_load加载的示例代码:

const char fname[] = "libm.so";
apr_dso_handle_t *dso_h;
apr_dso_load(&dso_h, fname, pool);

           apr_dso_load()失败的原因通常是找不到动态读文件。运行时动态库文件的搜索路径依赖于操作系统。在GNU/Linux中,它依赖于LD_LIBRARY_PATH环境变量。在MS-Windows中,它依赖于PATH环境变量。

    (2) APR_DECLARE(apr_status_t) apr_dso_unload(apr_dso_handle_t *handle);

         apr_dso_unload用以完成对指定so文件的卸载,handle是apr_dso_load返回的加载句柄。apr_dso_unload的实现则更简单,它只是调用了apr_pool_cleanup_run函数清除分配的内存池,同时调用dso_cleanup函数进行模块卸载。

    (3) APR_DECLARE(apr_status_t)apr_dso_sym(apr_dso_handle_sym_t *ressym,

                                                                                 apr_dso_handle_t *handle,

                                                                                 const char *symname);

         在apr_dso_load()返回成功之后,我们须调用apr_dso_sym()。apr_dso_sym()可以通过符号的名字得到符号对象,第一个参数是结构参数,第二个参数是DSO的处理句柄(handle),我们可以使用apr_dso_open()获得DSO的句柄,第三个参数是符号名称。

         下面是apr_dso_sym的调用代码,它用于从dso中获取符号名称是"pow"的函数指针,因为我们知道pow()的接口,定义一个pow_fn_t类型:

typedef double(*pow_fn_t)(double x, double y);
pow_fn_t pow_fn;
apr_dso_sym((apr_dso_handle_sym_t *)&pow_fn, dso_h, "pow");
printf("%d ^ %d = %f\n", 2, 2, pow_fn(2,2));

     (4) APR_DECLARE(const char *)apr_dso_error(apr_dso_handle_t *dso, char *buf, apr_size_t bufsize);

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

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值