1. 程式人生 > >linux 熱替換so文件

linux 熱替換so文件

webkit commit != -s port white alt () discuss

http://www.zhaoch.top/操作系統/linux/熱替換so文件.html

熱替換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文件