apacheモジュールで共有メモリを使ったプロセス間通信

apacheモジュールでプロセス間通信を行う場合、共有メモリを使ってやる手法がある。

apacheモジュールでよく使われるaprで、共有メモリ用の関数が用意されているため、実装に問題が無い以上はaprを使った方が楽だ。

では具体的な使い方を。

apacheモジュールで共有メモリを使う場合は、apache起動時のレジスターフックのpost_configのタイミングで共有メモリ領域を確保してやるといい。

後は、確保時にディレクティブ毎の共有メモリの領域を覚えておき、起動後のリクエスト・レスポンス時のハンドラーで、それぞれの共有メモリ領域を呼び出してやればいい。

まずは、グローバルで共有メモリ領域へのポインタのベースとなる変数と、共有メモリ領域を宣言しておく。

typedef struct shm_data_str {
    char file_stat_shm[10];
    int file_counter;
} SHM_DATA;

apr_shm_t *shm;
SHM_DATA *shm_base          = NULL;

次に、以下のようにpost_configのタイミングで共有メモリを確保する。

    apr_status_t status;
    apr_size_t shm_size;
    int i,t;

    SHM_DATA *shm_data = NULL;

    shm_size = (apr_size_t) sizeof(shm_data) * (conf_counter + 1);

    // apacehが何らかの理由で共有メモリ領域を確保しっぱなしだった時のために領域の削除
    if (shm) {
        status = apr_shm_destroy(shm);
        if (status != APR_SUCCESS) {
            DEBUG_SYSLOG("init: ", "Couldn't destroy old memory block", p);
            return status;
        } else {
            DEBUG_SYSLOG("init: ", "Old Shared memory block, destroyed.", p);
        }
    }

    // 共有メモリ領域生成
    status = apr_shm_create(&shm, shm_size, NULL, p);
    if (status != APR_SUCCESS) {
        DEBUG_SYSLOG("init: ", "Error creating shm block", p);
        return status;
    }

    // 共有メモリのポインタを取得
    shm_base = apr_shm_baseaddr_get(shm);
    if (shm_base == NULL) {
        DEBUG_SYSLOG("init", "Error creating status block.", p);
        return status;
    }

    // 領域初期化
    memset(shm_base, 0, retsize);

    // ディレクティブの数だけ確保したので、それぞれのディレクティブ用の領域のデータを初期化
    for (t = 0; t <= conf_counter; t++) {
        // このtが各ディレクティブのユニークなidとなるので、create_dir_config辺りでディレクティブ毎に値を保存しておく。
        shm_data = shm_base + t;
        for (i = 0; i < MAX_CLIENTS; i++) {
           // 何かしら各ディレクティブの初期化処理
           shm_data->file_stat_shm = "¥0";
           shm_data->file_counter    = 0;
        }
    }

上記処理で共有メモリを確保した後は、apache起動後の例えばアクセス制限の処理をした実装部分で、共有メモリ領域を呼び出す。

    // cfg->conf_idにディレクィブ毎のid(上記実装のtの値)をいれておく。
    // shm_baseをcof_if分進めた領域がディレクティブに与えられた共有メモリになる。
    SHM_DATA *limit_stat;
    limit_stat = shm_base + cfg->conf_id;

    //以下limit_statにデータを書き込んで、他のプロセスとデータのやりとりをする。

どうですか?
結構簡単にプロセス間通信ができてしまうんです。