メモ代わり。てきとーに。 いや、ですからてきとーですって。 2年前ぐらいにPythonあたりでメールくれた方、ごめんなさい。メール紛失してしまい無視した形になってしまいました。。。

2008年2月15日金曜日

[Apache][CodeReading] Apache2.2.8コードリーディング15日目

今日もApacheコードリーディング。

今日は昨日の続きから読み始めたんだけど、apr_atomic_init()から先に進めず。
apr_atomic_init()の中でapr_pool_cleanup_register()に入り、
さらにapr_pool_check_integrity()に入って、今DEBUGログ出力部分を読んでいるところ。

今日読めた部分は以下のとおり。

  • HAVE_BONE_VERSION定数/Apache2.2.8
  • BEOS定数/Apache2.2.8
  • file_unlockマクロ/Apache2.2.8
  • apr_file_flush_locked()/Apache2.2.8
  • apr_ssize_t/Apache2.2.8
  • APR_FILE_BUFSIZE定数/Apache2.2.8
  • HUGE_STRING_LEN定数/Apache2.2.8
  • apr_file_printf_data構造体/Apache2.2.8
  • apr_vformatter_buff_t構造体/Apache2.2.8
  • APR_DECLARE_NONSTDマクロ/Apache2.2.8
  • APR_POOL_DEBUG_VERBOSE_ALLローカル定数/Apache2.2.8
  • APR_POOL_DEBUG_VERBOSE_ALLOCローカル定数/Apache2.2.8
  • APR_POOL_DEBUG_VERBOSEローカル定数/Apache2.2.8
  • apr_pool_is_child_of()/Apache2.2.8
  • pool_is_child_of()/Apache2.2.8
  • apr_pool_walk_tree()/Apache2.2.8
  • APR_POOL_DEBUG_LIFETIMEローカル定数/Apache2.2.8
  • NUM_ATOMIC_HASHローカル定数/Apache2.2.8
BONEの意味がわからず時間がとられた。BeOS Network Environmentの略らしい。
BeOSではsys/socket.hでBONE_VERSIONという定数が定義されているとのこと。
環境がBeOSの場合、configure側ではこの定数を調べてBONEかどうか判断している。
BONE_VERSION定数がない場合はBeOS R5と認識するっぽい。


さて、今日読んだものをひとつづつ見ていく。PukiWikiに書き込めなかったようなことをつらつらと
書く感じでいきまっす。

file_unlockマクロ・file_lockマクロ
名前から察するにflockかfcntlでも使うのだろうかと思ったが、実はそうではなくて、
pthreadのmutexを使ってApache内部でapr_file_t構造体を1スレッドだけで使いたい
ときに使っている模様。
定義は

118 #define file_lock(f) do { \
119 if ((f)->thlock) \
120 apr_thread_mutex_lock((f)->thlock); \
121 } while (0)
122 #define file_unlock(f) do { \
123 if ((f)->thlock) \
124 apr_thread_mutex_unlock((f)->thlock); \
125 } while (0)

のとおり。
これとは別にflockやらfcntlを使うロック関数もあって(そりゃあるだろうが)、それは
apr_file_lock()という紛らわしい名前が付いている。



apr_file_flush_locked()
これは上記file_lockでロックされた状態のapr_file_tを使って、
バッファ内のデータを全てファイル/ソケットに吐き出す関数。

309 apr_status_t apr_file_flush_locked(apr_file_t *thefile)
310 {
311 apr_status_t rv = APR_SUCCESS;
312
313 if (thefile->direction == 1 && thefile->bufpos) {
314 apr_ssize_t written;
315
316 do {
317 written = write(thefile->filedes, thefile->buffer, thefile->bufpos);
318 } while (written == -1 && errno == EINTR);
319 if (written == -1) {
320 rv = errno;
321 } else {
322 thefile->filePtr += written;
323 thefile->bufpos = 0;
324 }
325 }
326
327 return rv;
328 }

APR_DECLAREをつけてないので、一応APRの外に公開していないことになっている。
mutexロックされているのが前提っぽい名前なので直接使わないでほしいのに違いない。

で、やっていることはパラメータで渡されたthefileが書き込み用途でなければ何もしないで終了。
書き込み用途(direction==1)で且つバッファにデータがたまっている(bufpos > 0)のであれば
書き込み処理を行う。
その後、filePtrを書き込めたバイト数分加算し、bufposは0にする。

もうちょっと先を読まないとわからないが、多分、
filePtrは現在の論理的なファイルのオフセットを保持、
bufposは現在バッファに持っているデータのバイト数
であっているんじゃないかなー。



pool_is_child_of()
これはAPR_POOL_DEBUGに0x02ビットを立てないと定義されない。
0x02はAPR_POOL_DEBUG_LIFETIMEとなっている。
多分だけど、親プールが死んでいるのに子プールが存在していたり、バグで切り離されちゃったプール
なんかを発見する手段なんじゃないかな?
そんなときはCPPFLAGS=-DAPRPOOL_DEBUG=0x02とかでconfigureする感じか。

その「ちゃんとプール同士がつながっている?」をチェックするのがapr_pool_check_integrity()
という関数なんだけど、とりあえず置いといて、以下がpool_is_child_of関数のコード。


1174 static int pool_is_child_of(apr_pool_t *parent, void *data)
1175 {
1176 apr_pool_t *pool = (apr_pool_t *)data;
1177
1178 return (pool == parent);
1179 }


この関数は名前と処理にずれがある感じがする。処理はパラメータの値を直接比較しているだけ。
なんとなく変なのは、次のapr_poll_walk_tree()関数と、apr_pool_is_child_of()関数を見ればわかる。
実はこの関数はis_child_of関係の関数の内部からコールバックされるもので、
parentには本当はparentじゃなくてchildがわたってくる。(parentがわたってくる場合もあるが)


apr_pool_walk_tree()

プールの子を辿っていって、パラメータで渡された関数fnが真のときか、子がいなくなったときに
処理を終了する。

コードは、

1082 static int apr_pool_walk_tree(apr_pool_t *pool,
1083 int (*fn)(apr_pool_t *pool, void *data),
1084 void *data)
1085 {
1086 int rv;
1087 apr_pool_t *child;
1088
1089 rv = fn(pool, data);
1090 if (rv)
1091 return rv;
1092
1094 if (pool->mutex) {
1095 apr_thread_mutex_lock(pool->mutex);
1096 }
1099 child = pool->child;
1100 while (child) {
1101 rv = apr_pool_walk_tree(child, fn, data);
1102 if (rv)
1103 break;
1104
1105 child = child->sibling;
1106 }
1107
1109 if (pool->mutex) {
1110 apr_thread_mutex_unlock(pool->mutex);
1111 }
1113
1114 return rv;
1115 }


な感じ。見にくいのでコメントと#if/#endifは削除した。
再帰的にapr_pool_walk_treeが呼ばれる。ま、なんてことは無いtreeな処理。


apr_pool_is_child_of()
1181 static int apr_pool_is_child_of(apr_pool_t *pool, apr_pool_t *parent)
1182 {
1183 if (parent == NULL)
1184 return 0;
1185
1186 return apr_pool_walk_tree(parent, pool_is_child_of, pool);
1187 }



pool_is_child_of関数がパラメータ2つをただ単に比較していただけなのも、
この関数と、前のapr_pool_walk_treeを見れば一目瞭然。
やっていることは、パラメータのparentがNULLの場合、そのままapr_pool_walk_treeに渡してしまう
と、運が良くてSegmentation Faltしちゃうので、NULLチェックして、apr_pool_walk_treeを呼ぶだけ。

APR_POOL_DEBUGのフラグが立っているときのみ、この関数は呼ばれるようだが、
ここで偽(0)を返すとApacheはabort()する。


とりあえず本日読んだところはここまで。



おしまい。
.

0 コメント: