地方エンジニアの学習日記

興味ある技術の雑なメモだったりを書いてくブログ。たまに日記とガジェット紹介。

共有ライブラリをプロセスを再起動させずに更新させたい

動的ライブラリはプロセスの起動時にリンクされ以降はメモリにマップされたものを使い続けます。ただ動的とはいえプロセスを起動した後にライブラリを更新したとしても起動済みのプロセスには何もしなければ置き換わることはありません。再起動がしやすい環境であれば問題ないですがそうはいかないケースもあったりします(多分)。そういう時に使える仕組みがないかなぁと思ってTLPIを開いたらdlopen/dlcloseという仕組みがあることに気づきました。共有ライブラリの動的ロードを行うことができるようです。

linuxjm.osdn.jp

お試し

こんな感じでライブラリをかく

// mylibrary.c
#include <stdio.h>

void say_hello() {
    printf("Hello from the dynamic library!\n");
}

コンパイル

$ gcc -shared -o libmylibrary.so mylibrary.c

使用するプログラムを書く

#include <stdio.h>
#include <dlfcn.h>

int main() {
    void *handle;
    void (*say_hello)();

    // 共有ライブラリをロード
    handle = dlopen("./libmylibrary.so", RTLD_LAZY);
    if (!handle) {
        fprintf(stderr, "Error: %s\n", dlerror());
        return 1;
    }

    // 共有ライブラリ内の関数を取得
    say_hello = dlsym(handle, "say_hello");
    if (!say_hello) {
        fprintf(stderr, "Error: %s\n", dlerror());
        return 1;
    }

    // 関数を呼び出してメッセージを表示
    say_hello();

    // 共有ライブラリをアンロード
    if (dlclose(handle) != 0) {
        fprintf(stderr, "Error: %s\n", dlerror());
        return 1;
    }

    return 0;
}

これでlibmylibrary.soは動的にロードされるようになります。dlopenにRTLD_LAZYを指定しているので実際に呼び出すまではロードされないようになっています。/proc/$PID/mapsとかを見ると確かに呼び出す前にロードされていないのがわかります。シグナルを受けたらdlcloseしてdlopenするとかそういう使い方ができそうだったり色々な用途がありそうだなぁと思った。Redisとかはluaのロードに使っているようだった。再起動がしにくいプロセスで後から機能を足すとかで使えるのは便利そう。