linux 熱替換so文件
熱替換so文件
www.zhaoch.top > 操作系統 > linux
發現nginx的動態模塊無法熱更新,於是研究了一下相關的問題。
代碼準備
reload.c, 啟動文件,用來模擬正在運行的程序,不斷重建加載so.so文件
#include <dlfcn.h> #include <stdio.h> typedef void (*F)(); int my_dlopen() { void* h = dlopen("so.so", RTLD_NOW|RTLD_GLOBAL); if (!h) { fprintf(stderr, "%s\n", dlerror()); return 1; } F f = (F)dlsym(h, "action"); f(); return 0; } int main(int argc, char const *argv[]) { printf("start...\n"); while (1) { printf("run\n"); if (my_dlopen() != 0) { return 1; } sleep(2); } return 0; }
so1.c 模擬其中一個so文件
#include <stdio.h> void action() { printf("11111111111111111\n"); }
so2.c 模擬其中另一個so文件,接口相同,打印內容不同
#include <stdio.h> void action() { printf("222222222222222222222\n"); }
編譯
gcc reload.c -ldl -o reload gcc -fPIC -shared so1.c -o so1.so gcc -fPIC -shared so2.c -o so2.so
註意
所有的實驗需要 export LD_LIBRARY_PATH=./
第一次嘗試,直接cp替換
先將 so1.so 設置成默認的 so文件
cp so1.so so.so
啟動程序, 然後執行 cp so2.so so.so
./reload start... run 11111111111111111 run 11111111111111111 run 11111111111111111 run 11111111111111111 <-- 執行 cp so2.so so.so run [1] 38314 segmentation fault (core dumped) ./reload
程序直接崩潰
同時測試了下,rm so.so
並不影響執行,但是停止程序再啟動顯示so.so: cannot open shared object file: No such file or directory
這個可能說明,so文件被打開一次後句柄並不會關閉,下次打開任然用這個句柄。只是重新讀取文件。cp 改變文件內容,並不改變文件inode。
先rm再cp
cp so1.so so.so ./reload start... run 11111111111111111 run 11111111111111111 run 11111111111111111 run 11111111111111111 run 11111111111111111 <-- rm so.so;cp so2.so so.so run 11111111111111111 run 11111111111111111 run 11111111111111111
結果就是更新無效,猜想還是句柄沒關閉的原因。rm的後,程序還指向原來的文件(這個文件外界看不到), cp產生了一個新的文件,程序根本沒有理睬這個文件。
dlclose 再加載
在代碼中加入 dlclose(h),如下:
int my_dlopen() { void* h = dlopen("so.so", RTLD_NOW|RTLD_GLOBAL); if (!h) { fprintf(stderr, "%s\n", dlerror()); return 1; } F f = (F)dlsym(h, "action"); f(); dlclose(h); // <-- return 0; }
這次可以了
./reload start... run 11111111111111111 run 11111111111111111 run 11111111111111111 run 11111111111111111 <-- cp so2.so so.so run 222222222222222222222 run 222222222222222222222 run 222222222222222222222 run 222222222222222222222
說明確實時句柄的問題,這裏涉及到linux inode的問題。每個文件都會對應一個inode, 內部都是按照inode來處理的,同一個文件名的不一定是同一個inode。一個文件只有在沒有任何引用的時候才被刪除,當程序打開一個so文件,這個文件就被引用了,即使外部刪除這個文件,程序還是在使用這個so文件,這個文件只有在程序關閉時才被系統回收。cp過來時個全新的文件,只是文件名相同,inode並不相同,其實程序還是用著老的so文件。dlclose恰恰時關閉了這個文件,之後再次按文件名打開就是新的文件。
備註
看了下nginx的代碼,貌似先dlopen之後再close舊的handle,這樣是無法熱更新的,不太清楚處於什麽考慮。
The End
- My github location
- View Source of this website GhostZch.github.io
- Commit issues to discuss with me and others
linux 熱替換so文件