lynx   »   [go: up one dir, main page]

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

ラベル Apache の投稿を表示しています。 すべての投稿を表示
ラベル Apache の投稿を表示しています。 すべての投稿を表示

2011年8月3日水曜日

[Apache] Apacheデバッグ(Debian squeeze)

DebianでのApacheデバッグ.

1) dbg関連をインストールしまっす.


# apt-get install apache2-dbg libapr1-dbg libaprutil1-dbg gdb
 


2) CoreDumpDirectoryディレクティブを指定しまーす.

# vi /etc/apache2/apache2.conf
 

いや

# vi /etc/apache2/sites-enabled/000-default
 

とかかな?

で、適当に

CoreDumpDirectory /tmp
 

を追加.

3)ulimit
rootで以下を実行.

# /etc/init.d/apache2 stop
# ulimit -c unlimited
# /etc/init.d/apache2 start
 


4) コアダンプ!

5) gdbでcoreをのぞく.

# gdb /usr/sbin/apache2 /tmp/core
 


6) dbg系パッケージのアンインストール

7) おしまい



ということは
/usr/share/doc/apache2-dbg/README.backtrace
に書いてあるよ.


.

2011年7月13日水曜日

[Apache][その他] r

それはもしかすると


request_rec *r


の"r"かもかもしれない

.

[Apache][その他] apacheのcoreファイル


CoreDumpDirectory /tmp
 

って書いておくと、/tmpに吐き出されるよ。


それでも出なきゃ、

$ ulimit -c
 

って叩くと何か分かるかもね。

とりあえずは

$ ulimit -c unlimited
 

でいいんじゃない?


で、core吐かれたら

$ gdb /usr/sbin/apache2 /tmp/core
 

でいいんじゃないかな。
環境によるけど。

.

2011年3月25日金曜日

[Apache] disk_cache

mod_disk_cache使って一旦キャッシュに入ると
以後fixup_headersが呼ばれない。。。

.

2011年3月12日土曜日

[Apache][mod_chxj] POST時微妙

POST時の動きが微妙なんだけど
クライアント側から送付された文字コードを変換したいからなんだよね・・・

header_fixup時にContent-Lengthを決めないといけないっぽいんだけど
そうするとPOSTデータはどっから持ってくるんだろう・・・

input filter側でPOSTデータは読めるんだけどそうすると
Content-Lengthを変更できないっぽい。

だもんでinput_filterは止めて、input_handlerで処理するように
し、serf使ってローカルに対してPOSTするようにしてる。 

1.3の時には変更(していいかどうかは別にして)できたんだけど、
2.xではできないみたい。(もっともっと調査必要)

なんだか、そもそも勘違いしていそうな気もするんだけど。

メーリングリストなんかでも、POSTデータを変更したい人はいるようで
質問投げてるみたいなんだけど、「何でそんなこと必要なのか」で終わっちゃっている。。。

えー。。。

。。。

。。



--
追記

apache付属のmod_charset_liteのinput filter部にも書いてあった。


A Content-Length header is present, but it won't be valid after
conversion because we're not converting between two single-byte
charsets. This will affect most CGI scripts and may affect
some modules.
Content-Length can't be unset here because that would break
being able to read the request body.
Processing of chunked request bodies is not impacted by this
filter since the the length was not declared anyway.
 

ま、無理やりセットしてもinput filterの時点では有効にならないようなんだけど。


ということから、やはり

1) Content-Lengthは無視する
2) 内部から外部リクエスト投げる
  

の2つぐらいしか解決策は思いつかない

.

2011年2月28日月曜日

[Apache] r->headers_outに出力するヘッダ

r->headers_outに出力するヘッダ情報ってvalにNULL出していいのかな。


apr_table_setn(r->headers_out, "User-Agent", NULL);


ってな感じで。


apache http server付属のmod_disk_cache.cを見ると
valの値を無条件でstrlenしてるんだよね。
(keyも)

ってことで余裕のSEGV。

ダメじゃんか。
.

[Apache] プロファイラ

gprofを利用するためにapache http server(以下apache)から-pgオプションをつけてコンパイルする、なんてことをやってたんだけど面倒くさ。
あっちゃこっちゃにgmon.outが作成されるし。
(もっと調べろっていう話は置いといて)

で、oprofileってやつに切り替えた。

gprofよりも精度は落ちるらしいんだけど、これは楽。


# opcontrol --no-vmlinuz
# opcontrol --start
# /etc/init.d/apache2 start


ってやって

$ ab うんたらかんたら

で、実行しまくって


# opcontrol --stop
# opreport -l /usr/lib/apache2/module/mod_chxj.so > erer


ってやるとそこそこ素晴らしいアウトプットが得られる。
さらに

# opannotate -a -s /usr/lib/apache2/module/mod_chxj.so | lv


なんてやるとコードも一緒に表示してくれる、と。


もちろんmod_chxj自体は-gオプションをつけてコンパイルだぜぇ。



使い終わったら

# opcontrol --shutdown


ですかね。
.

[Apache] なんか情報増えてるよね

Apacheモジュールに関する日本語の情報がやたらと増えてるよね。

以前は日本語情報といえば、Apacheモジュール本の著者の方のページとmod_uploaderの作者の方が公開している情報ぐらいだった。

さて、それは置いといて、


$ gdb /usr/sbin/apache2


と起動して


>run -X -f /etc/apache2/apache2.conf

なんてたたいてdebugするわけなんだが
module内で内部リクエストではなく外部リクエストとして
自分自身へリクエスト投げると、さあ大変。

お手軽デッドロック。

で?
.

2008年4月30日水曜日

[その他][Apache][mod_chxj] apr_memcache。。

うーぷす。

こちらの日記によると、


apr_memcache0.7.0リリースにはそもそも不具合があるので
 

だそうで・・・。
パッチあてようっと。

2008年3月8日土曜日

[Apache][CodeReading] Apache2.2.8コードリーディング -- 一時休止

デスマーチ中につき、一時休止。
隙をみて読む予定・・・・。



.

2008年3月1日土曜日

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

今日もApache2.2.8コードリーディング。

今日はちょっとだけ。

今日やったところは、

  • apr_cvt()/Apache2.2.8
らへん。

apr版printfの不動小数点数を文字列に変換するところ。

apr_cvt()
この関数は少々難しい。いかに自分が力不足か確認できた。。。

何をする関数かというと、与えられた浮動小数点数値を
与えられた精度で、文字列化するのだが、ここで小数点は文字列化しない。
小数点の位置は引数で関数に渡すパラメータにセットされ、呼び出し元に返される。
正負も引数で関数に渡すパラメータにセットされ、呼び出し元に返される。

たとえば、1234.5678という数値があったとする。
そして、eflags == 0、ndigits == 10でapr_cvt()をコールしたとする。
このときの関数の呼び出し結果は、

123456780000000
 

という文字列と、

4
 

という小数点の位置と、

0
 

という正負フラグ
になる。

あと、たとえば、0.9999という数値があったとして、
精度が4以下の場合、1に丸められる。


とりあえず、以下コード。

96 static char *apr_cvt(double arg, int ndigits, int *decpt, int *sign,
97 int eflag, char *buf)
98 {
99 register int r2;
100 double fi, fj;
101 register char *p, *p1;
102
103 if (ndigits >= NDIG - 1)
104 ndigits = NDIG - 2;
105 r2 = 0;
106 *sign = 0;
107 p = &buf[0];
108 if (arg < 0) {
109 *sign = 1;
110 arg = -arg;
111 }
112 arg = modf(arg, &fi);
113 p1 = &buf[NDIG];
114 /*
115 * Do integer part
116 */
117 if (fi != 0) {
118 p1 = &buf[NDIG];
119 while (p1 > &buf[0] && fi != 0) {
120 fj = modf(fi / 10, &fi);
121 *--p1 = (int) ((fj + .03) * 10) + '0';
122 r2++;
123 }
124 while (p1 < &buf[NDIG])
125 *p++ = *p1++;
126 }
127 else if (arg > 0) {
128 while ((fj = arg * 10) < 1) {
129 arg = fj;
130 r2--;
131 }
132 }
133 p1 = &buf[ndigits];
134 if (eflag == 0)
135 p1 += r2;
136 if (p1 < &buf[0]) {
137 *decpt = -ndigits;
138 buf[0] = '\0';
139 return (buf);
140 }
141 *decpt = r2;
142 while (p <= p1 && p < &buf[NDIG]) {
143 arg *= 10;
144 arg = modf(arg, &fj);
145 *p++ = (int) fj + '0';
146 }
147 if (p1 >= &buf[NDIG]) {
148 buf[NDIG - 1] = '\0';
149 return (buf);
150 }
151 p = p1;
152 *p1 += 5;
153 while (*p1 > '9') {
154 *p1 = '0';
155 if (p1 > buf)
156 ++ * --p1;
157 else {
158 *p1 = '1';
159 (*decpt)++;
160 if (eflag == 0) {
161 if (p > buf)
162 *p = '0';
163 p++;
164 }
165 }
166 }
167 *p = '\0';
168 return (buf);
169 }
 

引数は、
  • arg 変換対象の浮動小数点数値
  • ndigits 精度
  • decpt 出力パラメータ。小数点の位置
  • sign 出力パラメータ。正負。
  • eflag フォーマットが'e'か'E'の場合は、0以外の値を指定する。
  • buf 出力パラメータ。変換後文字列格納領域。
となっている。
さて、ややこしいので1つづつ見ていく。

99行目の

register int r2;
 

は、小数点の位置の算出に利用される。

103     if (ndigits >= NDIG - 1)
104 ndigits = NDIG - 2;
105 r2 = 0;
106 *sign = 0;
107 p = &buf[0];
 
 

あたりは特に難しくない。精度が、上限値(NDIG==80)を超えていたらセットしなおしている。
r2(小数点の位置)は0クリア。
sign(正負フラグ)も0クリア。
pを出力領域の先頭アドレスにセット。

108     if (arg < 0) {
109 *sign = 1;
110 arg = -arg;
111 }
  

ここは、変換対象の浮動小数点数が負の値で合った場合の処理。
signに1をセットし、argは正の値にセットしなおす。



112 arg = modf(arg, &fi);
 
 
ここで整数部と小数部を分離。
fiには整数部、argには小数部が入る。

113     p1 = &buf[NDIG];
 

ここで、p1に出力領域(buf)の最後尾のアドレスをセットしている。


117     if (fi != 0) {
118 p1 = &buf[NDIG];
119 while (p1 > &buf[0] && fi != 0) {
120 fj = modf(fi / 10, &fi);
121 *--p1 = (int) ((fj + .03) * 10) + '0';
122 r2++;
123 }
124 while (p1 < &buf[NDIG])
125 *p++ = *p1++;
126 }
 

ここで、整数部を文字列に変換する。
118行目は必要なコードでは無いと思う。
whileループは整数部が無くなるまで繰り返す。
120行目で10分の1にすることで、整数部の1の位を取り出している。
1の位はfjに10分の1の値で設定される。

そして、面白いのがここ。
121             *--p1 = (int) ((fj + .03) * 10) + '0';
 
 
10分の1にして取り出した1の位の値に0.03を加算後、10倍しているのだが、
この0.03が無いと結果が変わってしまう。
たとえば、1234.0という値を変換しようとした場合、0.03を加算しないと
p1には1134という値がセットされてしまう。
0.03を加算することで、doubleやfloatの問題を回避している。

124行目からは、121行目で作成した文字列をbufの先頭領域にコピーしている。


127     else if (arg > 0) {
128 while ((fj = arg * 10) < 1) {
129 arg = fj;
130 r2--;
131 }
132 }
 


は、整数部が無かった場合の処理で、
小数点以下第一位の位に0以外の数値を持ってきている。
位を移動した分だけr2も更新。

133     p1 = &buf[ndigits];
134 if (eflag == 0)
135 p1 += r2;
136 if (p1 < &buf[0]) {
137 *decpt = -ndigits;
138 buf[0] = '\0';
139 return (buf);
140 }
 
 
p1に指定精度になるようにbuf[ndigits]へのアドレスをセット。
135行目で、整数部の桁数分p1を後ろにずらしている。

141     *decpt = r2;
142 while (p <= p1 && p < &buf[NDIG]) {
143 arg *= 10;
144 arg = modf(arg, &fj);
145 *p++ = (int) fj + '0';
146 }
 

ここで、decptをセット。r2には小数点の位置(整数部の桁数)がセットされているので
その値をそのままdecptの指す先へセットしている。

142から146行目の処理では小数点以下の値を文字列化している。

仮にndigitsの値分の精度が必要なかった場合、あまった領域には'0'がセットされる。

147     if (p1 >= &buf[NDIG]) {
148 buf[NDIG - 1] = '\0';
149 return (buf);
150 }
 

で、領域を壊して突き進んでいたら、出力領域の最後尾にヌル文字をセットして
呼び出し元へ返る。


151     p = p1;
152 *p1 += 5;
153 while (*p1 > '9') {
154 *p1 = '0';
155 if (p1 > buf)
156 ++ * --p1;
157 else {
158 *p1 = '1';
159 (*decpt)++;
160 if (eflag == 0) {
161 if (p > buf)
162 *p = '0';
163 p++;
164 }
165 }
166 }
 

ここは、簡単に言うと、丸め処理をしている部分。
出力精度が4桁で、渡された値が99999であった場合、
このループに入るときのp1は、最後の'9'を指している。
そして、その'9'に5を加算する。('>'になる)
'>'は'9'より大きいので、このループが実行される。
このループの実行が終わると
99999であった値は100000に変わる。
それに伴ってdepctの値も更新。

最後にbuf[ndigits]にヌル文字をセットし、
bufを返す。



多分大体こんな感じの処理であっていると思う・・・。
うーむ。
ややこしいー。


おしまい。
.

2008年2月29日金曜日

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

今日もApache2.2.8コードリーディング。
ひらメソッドでリーディング。

今日はapr_vformatterがコールしている関数群を中心に読んだ。
で、

  • NDIGローカルマクロ(apr_snprintf)/Apache2.2.8
  • HAVE_ISINFマクロ/Apache2.2.8
  • HAVE_ISNANマクロ/Apache2.2.8
  • S_NULL_LENローカルマクロ(apr_snprintf)/Apache2.2.8
  • S_NULLローカルマクロ(apr_snprintf)/Apache2.2.8
  • conv_p2_quad()/Apache2.2.8
  • conv_p2()/Apache2.2.8
らへん。

S_NULLは"(null)"っていう文字列。
S_NULL_LENはその文字列長。

メインはconv_p2_quad()とconv_p2()あたりか。

conv_p2_quad()
conv_p2_quad()は、64ビット整数を、8進表記文字列か16進表記文字列へ変換する関数。
以下、その関数。

638 static char *conv_p2_quad(apr_uint64_t num, register int nbits,
639 char format, char *buf_end, register apr_size_t *len)
640 {
641 register int mask = (1 << nbits) - 1;
642 register char *p = buf_end;
643 static const char low_digits[] = "0123456789abcdef";
644 static const char upper_digits[] = "0123456789ABCDEF";
645 register const char *digits = (format == 'X') ? upper_digits : low_digits;
646
647 if (num <= APR_UINT32_MAX)
648 return(conv_p2((apr_uint32_t)num, nbits, format, buf_end, len));
649
650 do {
651 *--p = digits[num & mask];
652 num >>= nbits;
653 }
654 while (num);
655
656 *len = buf_end - p;
657 return (p);
658 }
 

パラメータのnumを、nbits、formatの値に従って文字列に変換する。
nbitsが3の場合は8進に、nbitsが4の場合は16進表記になる。
nbitsが4の場合で、formatが'X'(大文字のX)である場合は、
0xa~0xfまでの数字に大文字が使われる。

numがINT32の範囲内であれば、conv_p2()を使用して変換する。

conv_p2()
ほとんどconv_p2_quad()と一緒。
で、以下コード。

619 static char *conv_p2(register apr_uint32_t num, register int nbits,
620 char format, char *buf_end, register apr_size_t *len)
621 {
622 register int mask = (1 << nbits) - 1;
623 register char *p = buf_end;
624 static const char low_digits[] = "0123456789abcdef";
625 static const char upper_digits[] = "0123456789ABCDEF";
626 register const char *digits = (format == 'X') ? upper_digits : low_digits;
627
628 do {
629 *--p = digits[num & mask];
630 num >>= nbits;
631 }
632 while (num);
633
634 *len = buf_end - p;
635 return (p);
636 }
 

こちらは32ビット整数を8進表記文字列か16進表記文字列に変換する関数になっている。
型が違うだけでconv_p2_quad()と一緒。


あとは特になしな感じ。



おしまい。
.

2008年2月28日木曜日

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

今日もApache2.2.8コードリーディング。

今日も、昨日と同じくDEBUGログまわり。
printf書式を実装している部分。

今日読んだところは、

  • FIX_PRECISIONローカルマクロ(apr_snprintf)/Apache2.2.8
  • conv_10_quad()/Apache2.2.8
  • conv_10()/Apache2.2.8
  • FALSEローカルマクロ(apr_snprintf)/Apache2.2.8
  • INT32_MINローカルマクロ(apr_snprintf)/Apache2.2.8
  • INT32_MAXローカルマクロ(apr_snprintf)/Apache2.2.8
  • APR_INT64_T_FMTマクロ/Apache2.2.8
らへん。
これらはapr_vformatterという関数からコールされている。

conv_10_quad()とconv_10()は、数値を数字列に変換する関数。
10進表記の文字列に変換する。
conv_10_quad()とconv_10()の違いは、64ビットか32ビットかの違い。
その名のとおり、quadは64ビットに対応する。

conv_10_quad()
この関数は"%lld"フォーマットに対応する。
で、以下、そのソース。

383 static char *conv_10_quad(apr_int64_t num, register int is_unsigned,
384 register int *is_negative, char *buf_end,
385 register apr_size_t *len)
386 {
387 register char *p = buf_end;
388 apr_uint64_t magnitude = num;
389
390 /*
391 * We see if we can use the faster non-quad version by checking the
392 * number against the largest long value it can be. If <=, we
393 * punt to the quicker version.
394 */
395 if ((magnitude <= APR_UINT32_MAX && is_unsigned)
396 || (num <= INT32_MAX && num >= INT32_MIN && !is_unsigned))
397 return(conv_10((apr_int32_t)num, is_unsigned, is_negative, buf_end, len));
398
399 if (is_unsigned) {
400 *is_negative = FALSE;
401 }
402 else {
403 *is_negative = (num < 0);
404
405 /*
406 * On a 2's complement machine, negating the most negative integer
407 * results in a number that cannot be represented as a signed integer.
408 * Here is what we do to obtain the number's magnitude:
409 * a. add 1 to the number
410 * b. negate it (becomes positive)
411 * c. convert it to unsigned
412 * d. add 1
413 */
414 if (*is_negative) {
415 apr_int64_t t = num + 1;
416 magnitude = ((apr_uint64_t) -t) + 1;
417 }
418 }
419
420 /*
421 * We use a do-while loop so that we write at least 1 digit
422 */
423 do {
424 apr_uint64_t new_magnitude = magnitude / 10;
425
426 *--p = (char) (magnitude - new_magnitude * 10 + '0');
427 magnitude = new_magnitude;
428 }
429 while (magnitude);
430
431 *len = buf_end - p;
432 return (p);
433 }
 

とりたてて面白いことをやっているわけではない。
あえて言うなら、
元の値から、10で割った後、10でかけて1桁目を0にした値を差し引いて
1桁目を取得していることぐらいか。
値そのものが、32ビットの範囲内であれば、conv_10()をコールする。

conv_10()
conv_10は大体conv_10_quad()と一緒。
やっていることもほぼ一緒。

APR_INT64_T_FMT
これは、"lld"と記述されている。それだけ。

他は特になし。



今日の分はここまで。

おしまい。
.

2008年2月27日水曜日

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

今日もApache2.2.8コードリーディング。
ひらメソッドでリーディング。

さて、まだApache起動直後の初期化中。
デバッグログを出力しようとしているところで、
printfのAPR版部分で、そのコア部分。

今日やったところは以下のとおり。

  • INS_CHARローカルマクロ(apr_snprintf)/Apache2.2.8
  • boolean_e列挙型/Apache2.2.8
  • NUM_BUF_SIZEローカルマクロ(apr_snprintf)/Apache2.2.8
  • apr_uint64_t/Apache2.2.8
  • apr_islowerマクロ/Apache2.2.8
  • NULローカルマクロ(apr_snprintf)/Apache2.2.8
  • apr_isdigitマクロ/Apache2.2.8
  • NUMローカルマクロ(apr_snprintf)/Apache2.2.8
  • STR_TO_DECローカルマクロ(apr_snprintf)/Apache2.2.8
らへん。

INS_CHARマクロ
バッファに1文字セットするマクロ。
中で、file_printf_flushがコールされる。
コードは、

255 #define INS_CHAR(c, sp, bep, cc) \
256 { \
257 if (sp) { \
258 if (sp >= bep) { \
259 vbuff->curpos = sp; \
260 if (flush_func(vbuff)) \
261 return -1; \
262 sp = vbuff->curpos; \
263 bep = vbuff->endpos; \
264 } \
265 *sp++ = (c); \
266 } \
267 cc++; \
268 }
 

な感じ。flush_funcは、関数へのポインタで、今回の場合は
file_printf_flush。

バッファがいっぱいになったら、file_printf_flushがコールされる。
file_printf_flush内で、バッファを出力すると、vbuffのcurposは
バッファの先頭をさすように更新されるので、262行目でspの値を
更新している。file_printf_flush内でバッファを出力しなかった場合は
curposは259行目で代入した値のままで、262行目で代入しても
値は同じ。

で、spのさしている先にc(文字)を代入している。
代入後sp++。ccの値も更新。

ccが何なのかは今のところ良く分からない。が、多分出力文字数ではないかと
思う。多分。

263行目の

263 bep = vbuff->endpos; \
 

の部分。
endposか、bepがどこかで更新されているのであれば、
ここでendposの値をbepに入れるのは分かるのだが、
少なくともINS_CHARマクロ、apr_vformatter関数では
endposも、bepも触っていないようだ。

このマクロは別のところでも使っているのだろうか・・・?

後のために、一応
  • INS_CHARマクロの263行目は必要なのか?
という疑問をメモっておく。
file_printf_flushでは触っていないが、snprintf用とかvnprintf用とかで
endposかbepどちらかが更新されるのだろうか。



apr_islower、apr_isdigit
この辺はctype.hのislower、isdigitそのまま。
#defineしているだけ。


NUMマクロ
'0'を差し引いて数字を数値にしているだけ。

STR_TO_DECマクロ
数字列をNUMマクロを使用して数値にしているだけ。


今日のところはここまで。
apr_vformatterは時間がかかりそう。。



おしまい。
.

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

昨日はさぼり。でもちょっと読んだ。

読んだところは、

  • file_printf_flush()/Apache2.2.8
  • apr_file_write_full()/Apache2.2.8
だけ。

apr_file_write_full()は、apr_file_writeを使って、指定したバイト数を
がんばって出力する関数。
apr_file_writeはwriteシステムコールでEAGAINとかが返ってくると、
出力バイト数を減らしてリトライする。
apr_file_write_fullは、apr_file_writeで書き込めたバイト数を保持していて、
当初予定していた指定バイト数が全て出力されるまでがんばる。


file_printf_flushの方は、
apr_file_printf関数の中でも呼ばれているが、
多分主はapr_vformatter関数の中で呼ばれる方。

apr_vformatter関数は未読なので今のところ不明。

な感じ。

.

2008年2月25日月曜日

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

今日もApache2.2.8コードリーディング。

やっとこさっとこデバッグログ実出力完了。
場所はApache起動直後の初期化部分。
allocator、poolの初期化が終わって、
apr_thread_mutex_createをしようかというところ。

その中で、apr_pcallocという関数がコールされているんだけど、
APR_POOL_DEBUGを有効にしてコンパイルすると
apr_pcallocの代わりにapr_pcalloc_debugという関数が呼ばれるようになる。
んで、この関数の中をいくと、デバッグログを出力するところがあるんだけど、
そこ。


今日読んだところは、

  • apr_file_write()/Apache2.2.8
  • apr_wait_for_io_or_timeout()/Apache2.2.8
  • APR_STATUS_IS_EINTRマクロ(その他)/Apache2.2.8
  • APR_STATUS_IS_EINTRマクロ(NETWARE)/Apache2.2.8
  • APR_STATUS_IS_EINTRマクロ(WIN32)/Apache2.2.8
  • APR_STATUS_IS_EINTRマクロ(OS2)/Apache2.2.8
  • SOCEINTRマクロ/Apache2.2.8
  • SOCBASEERRマクロ/Apache2.2.8
  • APR_EINTRマクロ/Apache2.2.8
  • apr_pollset_poll()(select)/Apache2.2.8
  • apr_pollset_poll()(poll)/Apache2.2.8
  • get_revent()(poll)/Apache2.2.8
  • apr_pollset_poll()(port)/Apache2.2.8
  • get_revent()(port)/Apache2.2.8
  • APR_EGENERALマクロ/Apache2.2.8
  • apr_pollset_poll()(kqueue)/Apache2.2.8
  • apr_time_usecマクロ/Apache2.2.8
  • apr_time_secマクロ/Apache2.2.8
  • APR_USEC_PER_SECマクロ/Apache2.2.8
  • APR_TIME_Cマクロ/Apache2.2.8
  • APR_INT64_Cマクロ/Apache2.2.8
  • get_kqueue_revent()/Apache2.2.8
らへん。

やっとapr_pollset_poll全種類読破。
そして、apr_pollset_pollが読み終わったことで、apr_wait_for_io_or_timeout()も終了。

今日のメインはapr_file_write。
apr_file_writeは、簡単に言うと、バッファリングありの出力と、バッファリングなしの出力をこなす。
バッファリングありかどうかは、apr_file_t構造体にそういう設定があるので、
その設定値によって決まる。

書き込み時にEAGAINやEWOULDBLOCKを伴ってエラーになった場合、
apr_wait_for_io_or_timeout()をコールする。
リソースが一時的に使用不可になっているので、使用可能になるまで待つ。

使用可能になるまで待つのだが、その後使用可能になったのにもかかわらず
また一時的にリソースが使用不可になると、出力バイト数を半分にしてしまう。
半分にしては書き込み、また半分にしては書き込み、というのを、書き込めるか、エラーが
発生するか、writeシステムコールが0を返すまで繰り返される。

通常のファイルの場合、出力予定バイト数が0にさえなれば、
writeシステムコールは0を返すのだが、特殊ファイルの場合は
下手をすると無限ループってことも有り得るじゃないかなー。
確か、特殊ファイルの場合の出力バイト数が0だったときの動作って
未定義だった気がする。

まぁ、それは置いといて、
apr_file_writeを使って書き込みをした場合、
書き込めたバイト数が、書き込みたいバイト数(パラメータに渡したバイト数)と
違っていた場合、リソースが頻繁に「一時的に使用不可」になっている
ということか。


明日はこのapr_file_writeを使っているところから読む予定。



おしまい。
.

2008年2月24日日曜日

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

今日もひらメソッドにてApache2.2.8コードリーディング。

今日読んだところは

  • apr_pollset_poll()(epoll)/Apache2.2.8
  • APR_RING_CONCATマクロ/Apache2.2.8
  • get_epoll_revent()/Apache2.2.8
  • apr_get_netos_errorマクロ(その他)/Apache2.2.8
  • apr_get_netos_errorマクロ(netware)/Apache2.2.8
  • apr_get_netos_errorマクロ(win32)/Apache2.2.8
  • apr_get_netos_errorマクロ(os2)/Apache2.2.8
  • apr_pollset_poll()(os2)/Apache2.2.8
  • sock_errnoマクロ/Apache2.2.8
  • apr_os2_sock_errno()/Apache2.2.8
  • APR_FROM_OS_ERRORマクロ/Apache2.2.8
  • APR_OS_START_EAIERRマクロ/Apache2.2.8
  • make_pollset()/Apache2.2.8
らへん。
pollしているところ。

場所はApacheの初期化部。
APR_POOL_DEBUGでAPR_POOL_DEBUG_VERBOSE_ALLOCをしている場合でDEBUGログを出力しようとしているところ。出力終わるのをpollして待っている感じ(だっけ?)。

apr_pollset_poll()(epoll版)
今日読んだ中では、まあ一番面白いかなぁ。
といっても、epoll_waitしているだけ。

面白いのはepollじゃなくて、やはりリング部。

apr_pollset_addなんかで、ファイルディスクリプタを監視対象に追加するんだけど、
その追加に失敗した場合、pfd_elem_t領域をdead_ringにつないでおく。

このapr_pollset_pollの中で、epoll_waitが終わると、
dead_ringにつないでいた失敗時に作成したpfd_elem_tをfree_ringにつなぎ、
当のdead_ringは空にセット。

うーむ。なるほど。
ここでdead_ringをfree_ringにつなぎなおすのね。

次に同じapr_pollset_tを使用して
apr_pollset_add等をすると、
このfree_ringからpfd_elem_t領域が取得される。

ふーん。

今日はこんだけ。

おしまい。
.

2008年2月23日土曜日

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

今日もApache2.2.8コードリーディング。

ちょっと気になったので、今どのぐらいこなしたのか大雑把に計算してみた。
Apacheには、ざっと20000シンボルあって、で読破した分は294シンボル。
23日間で約1.3%終えたことになる。

すると、ざっと4.5年かかる計算。
今のところ毎日できているが、もうじき毎日読めなくなりそうなので
4.5年以上はかかることに。

まぁ、面白いから別にいいや。

で、今日は

  • apr_pollset_add()(select)/Apache2.2.8
  • HAS_SOCKETマクロ/Apache2.2.8
  • HAS_PIPESマクロ/Apache2.2.8
  • APR_FILES_AS_SOCKETSマクロ/Apache2.2.8
  • get_event()(port)/Apache2.2.8
  • get_epoll_event()(epoll)/Apache2.2.8
  • apr_pollset_add()(poll)/Apache2.2.8
  • get_event()(poll)/Apache2.2.8
  • APR_POLLNVALマクロ/Apache2.2.8
  • APR_POLLHUPマクロ/Apache2.2.8
  • APR_POLLERRマクロ/Apache2.2.8
  • APR_POLLPRIマクロ/Apache2.2.8
らへんを読んだ。
昨日読んだapr_pollset_add()の別バージョン。
処理内容はほぼ一緒。

apr_pollset_add()のselectバージョンは、
リングを持っていない。その代わりreadset、writeset、exceptsetを持っていて、
リングに追加する代わりにそれらのビットをオン・オフする感じ。


まぁ、昨日やったところなんで、特に面白いところは無い感じ。


おしまい
.

2008年2月22日金曜日

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

今日もApache2.2.8コードリーディング。

今日やったところは、

  • apr_pollset_add()(kqueue)/Apache2.2.8
  • apr_pollset_add()(epoll)/Apache2.2.8
  • APR_EBADFマクロ/Apache2.2.8
  • apr_pollset_remove()/Apache2.2.8
  • apr_os_sock_t/Apache2.2.8
  • NETWAREマクロ/Apache2.2.8
  • __BEOS__マクロ/Apache2.2.8
  • OS2マクロ/Apache2.2.8
  • WIN32マクロ/Apache2.2.8
  • pollset_unlock_rings()/Apache2.2.8
  • APR_RING_INSERT_TAILマクロ/Apache2.2.8
  • APR_RING_SPLICE_TAILマクロ/Apache2.2.8
  • APR_RING_SPLICE_BEFOREマクロ/Apache2.2.8
あたり。

で、まだ初期化部分。
DEBUGログを出力後にIOWAITするところ。
IOWAITするためにpollするんだけど、それを実行しようとしている部分。

リングの構造はさらっと19日目ぐらいにやった。
apr_pollset_tは環境により5種類の実装のうちひとつがconfigureなりで選択される。
今日読んだapr_pollset_add()もapr_pollset_remove()も5種類。

apr_pollset_remove()
apr_pollset_removeは、指定されたポールセット(apr_pollset_t)から指定されたディスクリプタ(apr_pollfd_t)を削除する。
ringをapr_pollset_t構造体に持つパターン(epoll、kqueue、portが使える環境)の場合は、
query_ringというリングから対象ディスクリプタを削除し、dead_ringというリングに対象ディスクリプタを登録する、
ということをやっている。
もちろん、epoll、kqueue、portからも削除する。


epoll、kqueue、portのいずれも使えず、poll関数が使える場合はringを保持しない。
代わりにquery_setというapr_pollfd_t構造体へのポインタの配列を保持する。
その配列から、対象ディスクリプタを削除する。

epoll、kqueue、portのいずれも使えず、さらにpoll関数も使用不可の場合も、ringを保持しないapr_pollset_tが使用される。
またpoll関数が使える場合と同様に、query_setほ保持し、apr_pollfd_t構造体へのポインタの配列から対象ディスクリプタを削除する。



apr_pollset_add()
まだ、epoll版とkqueue版しか読んでいない。

まず最初にfree_ringから空き領域を取得する。
空きが無ければapr_palloc()で領域を確保後、その領域を初期化(APR_RING_ELEM_INIT)する。
その領域にパラメータで指定されたディスクリプタをセットし、epoll_ctlを使用してepollにイベントを追加する。
うまく追加できればquery_ringにfree_ringから取得した領域を追加し、
うまく追加できなければfree_ringに取得した領域を返す。

で、そのソースが以下。

138 APR_DECLARE(apr_status_t) apr_pollset_add(apr_pollset_t *pollset,
139 const apr_pollfd_t *descriptor)
140 {
141 struct epoll_event ev;
142 int ret = -1;
143 pfd_elem_t *elem;
144 apr_status_t rv = APR_SUCCESS;
145
146 pollset_lock_rings();
147
148 if (!APR_RING_EMPTY(&(pollset->free_ring), pfd_elem_t, link)) {
149 elem = APR_RING_FIRST(&(pollset->free_ring));
150 APR_RING_REMOVE(elem, link);
151 }
152 else {
153 elem = (pfd_elem_t *) apr_palloc(pollset->pool, sizeof(pfd_elem_t));
154 APR_RING_ELEM_INIT(elem, link);
155 }
156 elem->pfd = *descriptor;
157
158 ev.events = get_epoll_event(descriptor->reqevents);
159 ev.data.ptr = elem;
160 if (descriptor->desc_type == APR_POLL_SOCKET) {
161 ret = epoll_ctl(pollset->epoll_fd, EPOLL_CTL_ADD,
162 descriptor->desc.s->socketdes, &ev);
163 }
164 else {
165 ret = epoll_ctl(pollset->epoll_fd, EPOLL_CTL_ADD,
166 descriptor->desc.f->filedes, &ev);
167 }
168
169 if (0 != ret) {
170 rv = APR_EBADF;
171 APR_RING_INSERT_TAIL(&(pollset->free_ring), elem, pfd_elem_t, link);
172 }
173 else {
174 pollset->nelts++;
175 APR_RING_INSERT_TAIL(&(pollset->query_ring), elem, pfd_elem_t, link);
176 }
177
178 pollset_unlock_rings();
179
180 return rv;
181 }
 

APR_RING_EMPTYで空かどうかチェックし、空でなければ先頭の領域を取得する。
空だった場合は、領域確保後、APR_RING_ELEM_INITマクロで初期化するのだが、
この、APR_RING_ELEM_INITが良くわからない。
やっていることは、elem->link->nextとelem->link->prevにelemを代入しているだけ。
その初期化自体は良いのだが、epoll_ctl後、free_ringか、query_ringにすぐに追加してしまうので
APR_RING_ELEM_INIT自体無意味に思える。
最初はAPR_RING_INSERT_TAILマクロでnextとprevに何かしらのポインタが必要なのかと思ったが、
そうでもない。

APR_RING_INSERT_TAILは、

#define APR_RING_SPLICE_BEFORE(lep, ep1, epN, link) do { \
APR_RING_NEXT((epN), link) = (lep); \
APR_RING_PREV((ep1), link) = APR_RING_PREV((lep), link); \
APR_RING_NEXT(APR_RING_PREV((lep), link), link) = (ep1); \
APR_RING_PREV((lep), link) = (epN); \
} while (0)
 

こんな感じに置き換わる。
で、

APR_RING_NEXT((epN), link) = (lep)
 

は、

elem->link = APR_SENTINEL(hp)
 

に、そして、

APR_RING_PREV((ep1), link = APR_RING_PREV((lep), link);
 

は、

elem->link->prev = APR_SENTINEL(hp)->link->prev;
 

に置き換わる。
つまり、せっかく初期化してもすぐに上書きしてしまうので、
無意味な気がする・・・・。

理由があるとすれば、RINGを構成する構造体に何かしらの変更が加わった場合に対処しやすいように
といった感じか。
といってもそれも考えにくい・・・。

うーむ。

わからん。
とりあえず、今度APR_RING_ELEM_INITをコメントアウトして動かしてみようかと思う。

いつかやるタスク。
  • APR_RING_ELEM_INITをapr_pollset_add関数から削除して動かしてみる。
あと、ついでに、
apr_palloc()関数も。
apr_palloc()は空きノードが無かった場合allocator_alloc()をつかってmallocするんだが、
このときNULLが返ってきた場合apr_palloc()はNULLを返す。
なのにもかかわらず、apr_palloc()を使用しているところのほとんどがNULLチェックをしていない。
うーむ。
Segmentation Faltですか??
ということで、
  • malloc失敗するパターンで、apr_palloc()を読んでみる。
というのもやってみようと思う。





おしまい。
.

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

昨日もApache2.2.8コードリーディング。

昨日はメモするの忘れた。

昨日やった分は、

  • APR_RING_REMOVEマクロ/Apache2.2.8
  • APR_RING_UNSPLICEマクロ/Apache2.2.8
  • APR_RING_PREVマクロ/Apache2.2.8
  • APR_RING_EMPTYマクロ/Apache2.2.8
  • APR_NOTFOUND定数/Apache2.2.8
  • APR_POLL_SOCKET定数/Apache2.2.8
あたり。
マクロだけしかページは作ってない。

で、これはどの辺かというと、
Apacheの初期化部分・・・。
まだ初期化。
まだListenしてない。。


詳細は今日の分も合わせてメモ予定。




.

 
Лучший частный хостинг