壊れたメガネ

ホッチキスの達人の意識の高いブログ。

mod_mathtex を作る(2) - 完成?

「出来た」と言いたいところだけど、まだまだ至らない点があるので「形になりつつある」といった感じ。

$ git clone https://github.com/oasynnoum/mod_mathtex.git
$ cd mod_mathtex
$ ./configure && make && make install 

一応まぐれで動いている。
というのもソースコードにはまだまだ沢山のグローバル変数や static 宣言された変数があるから。
mathtex はもともと CGI アプリケーションであって、シングルスレッドかつプロセスを再利用しない前提のため、そういった作りになっている。一方 Apache はプロセスの再利用を前提となっていて、マルチスレッドで動作させることも出来る。 こういうまぐれな状況だけどリポジトリは作ってある。
https://github.com/oasynnoum/mod_mathtex
リポジトリはあるが、これまでの大体のリビジョンは動かない。そういうコードを push したという事。あらまあ最低。

関数のローカル変数でも static なものを非static化

実際に次の関数でハマった。

char *makepath (char *path, char *name, char *extension) {
    static char namebuff[512]; /* buffer for constructed filename */
    char *filename = NULL;     /*ptr to filename returned to caller*/
    // ...
    filename = namebuff;
    return filename;
}

この関数は引数からパス文字列を組み立てて返すもので、その文字列のバッファが static で以下の様な状況でちぐはぐなことになっていた。

/* path_to_hoge と path_to_fuga の指すアドレスは同一 */
char *path_to_hoge = makepath("/path/to", "hoge", "c"); // return '/path/to/hoge.c' 
/* この呼び出しで path_to_hoge が指す中身も変わる。 */
char *path_to_fuga = makepath("/path/to", "fuga", "c"); // return '/path/to/fuga.c' 

printf("path_to_hoge: %s\n", path_to_hoge); // /path/to/hoge.c が出力されて欲しいけど、実際は /path/to/fuga.c
printf("path_to_fuga: %s\n", path_to_fuga);

namebuff の宣言を次のように置き換える。

char *makepath (char *path, char *name, char *extension) {
-    static char namebuff[512]; /* buffer for constructed filename */
+    char *namebuff = apr_pcalloc(pool, 512); /* buffer for constructed filename */
    char *filename = NULL;     /*ptr to filename returned to caller*/

これでこの箇所は直るんだけど、 C 言語よくわからないのでこれでいいのか感はある。

構造体 mathtex_object_t を定義し、主要なグローバル変数をこのメンバへと移動

static int imagetype   = IMAGETYPE;   /* 1=gif, 2=png */
static int imagemethod = IMAGEMETHOD; /* 1=dvipng, 2=dvips/convert */
static int latexmethod = LATEXMETHOD; /* 1=latex, 2=pdflatex */

といった感じのグローバル変数を、

typedef struct mathtex_object {
    int imagetype;
    int imagemethod;
    int latexmethod;
    int isdepth;
    char *query;
    char *latexwrapper;
    mathtex_config_t *conf;
    request_rec *r;
    FILE *process_log_file;
    FILE *math_log_file;
} mathtex_object_t;

このような構造体としてまとめ、リクエスト処理開始時にこの構造体のインスタンスを生成する。
グローバル変数をこのような形でまとめたので、元からあった大部分の関数の引数に mathtex_object_t *o を取る変更を加えている。

バグつぶし

仕様を把握せずに色々やったせいで出来たバグ。

autoconf による configure スクリプト生成

mathtex.o を静的リンクするための apxs -n name -g で生成される Makefile の変更。
生成された Makefile には幾つかの include ディレクティブが含まれていて、そこにシステムに依存する変数が定義されている。
以下のコマンドで include ディレクティブが指すファイルが入っているディレクトリが表示される。

$ apxs -q exp_installbuilddir

同様に、このコマンドの -q オプションを用いて ${exp_installbuilddir}/config_vars.mk 内で定義されている変数を表示できる。
ちなみに、 autoheader automake は使っていない。

指針

グローバル変数絶滅。

雑感

大分お勉強している感じがある。楽しい。
ただスレッドについて知識が皆無なので、「グローバル変数を利用しているコードはスレッドセーフではない」ということはなんとなく知っていても、きちんと理解していないので辛い。このへんは POSIX Threads を実際に利用したり、実装を見たりして今後勉強したい。