学习《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);
總結
以上是生活随笔為你收集整理的学习《apache源代码全景分析》之DSO概念的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: qsort()函数详解
- 下一篇: C语言宏与单井号(#)和双井号(##)