2014年10月27日月曜日

リクエスト処理の流れ: listener_thread(1) メインループの開始

listenerスレッドは各子プロセスに1つ存在している。
worker MPMでは、listenしているサーバ用のソケットを監視して、クライアントからの接続を受け付け通信用のソケットを用意し、これをworkerスレッドにスレッド間通信用のキューを介して引き渡していた。
これが、event MPMでは、そのほかにも、クライアントからのFIN待ちや、Keep-Alive接続における、次のリクエストの受信待ち等の監視も行うようになっている。

(14) listener_thread


(httpd-2.4.9/server/mpm/event/event.c)
   1368 static void * APR_THREAD_FUNC listener_thread(apr_thread_t * thd, void *dummy)
   1369 {

init_pollset()関数では、Listenディレクティブで設定されているサーバソケットでlistener_poll_type情報を作成する。
初期設定では、このListenソケットはすべてlistenerスレッドでのイベント監視対象。

   1399     rc = init_pollset(tpool);
   1400     if (rc != APR_SUCCESS) {
   1401         ap_log_error(APLOG_MARK, APLOG_ERR, rc, ap_server_conf,
   1402                      "failed to initialize pollset, "
   1403                      "attempting to shutdown process gracefully");
   1404         signal_threads(ST_GRACEFUL);
   1405         return NULL;
   1406     }


引き続き主ループに進む。
今回はここを見ていく。

長い関数なので、投稿を分けたい。

(1)メインループの開始(本投稿)

(14.1) 主ループ


   1414     for (;;) {
   1415         int workers_were_busy = 0;

workers_were_busyは、この子プロセスのworkerスレッドに処理可能な空きがあるかどうかのフラグだ。
0は空きがある(ビジーではない)。
get_worker()関数でセットされる。

get_worker()関数は、workerスレッドの空き(アイドルスレッド)の有無をチェックする。
これは2つのモードで動作する。

  • 空きがない場合に、空きができるまでブロックするのがブロックモード(第2引数が1)
  • 空きがなければ、APR_EAGAINで直ちに返ってくるのが非ブロックモード(第2引数が0)

このlistenerスレッド関数ではいずれのモードも利用されている。

そして、get_worker()で第3引数に与えられている workers_were_busy は以下のケースで1がセットされる。

  • ブロックモードで、アイドルworkerスレッドがなく空き待ちを実行した場合
    (ブロックモードの場合、アイドルworkerスレッドがなく空き待ちを実行すると、正常な状態なら実際にアイドルworkerスレッドが得られてからreturnする)
  • 非ブロックモードでアイドルworkerスレッドがなく、直ちにAPR_EAGAINで返った場合


   1416         if (listener_may_exit) {

listener_may_exit はプロセスの終了フラグ。
このフラグが立っている場合、listenerスレッドは終了処理を始める。
このif文は終了処理だ。

とりあえず、今回はリクエスト処理の流れを追いたいので見ない。

   1417             close_listeners(process_slot, &closed);
   1418             if (terminate_mode == ST_UNGRACEFUL
   1419                 || apr_atomic_read32(&connection_count) == 0)
   1420                 break;
   1421         }
   1422
   1423         if (conns_this_child <= 0)

conns_this_childは、MaxConnectionsPerChildのチェック用の変数だ。
初期値にMaxConnectionsPerChildをセットし、接続を受け付けるごとにカウントダウンする(1630行目)。
値が0以下だと、処理数がMaxConnectionsPerChildを越えたことになる。
以下の関数check_infinite_requests()では、MaxConnectionsPerChildに0以外の値が指定されていた場合に、停止処理を実行している。
(MaxConnectionsPerChildが0の場合は無制限にリクエストを処理できる)

   1424             check_infinite_requests();
   1425
   1426         now = apr_time_now();

現在時刻を変数nowにセット。

   1427         if (APLOGtrace6(ap_server_conf)) {

このif文はTRACEログの出力が有効な場合に実行される。
LogLevel mpm_event:trace6
と指定してやると、この条件に入る(省略)。

   1443         }
   1444

以下ではスキップリストのチェックを行っている。
スキップリストはタイムアウト処理を管理している。
これは apr_skiplist とmod_dialupモジュールで簡単には見ている。

スキップリストをチェックして、次のタイムアウト処理までの時間を確認する。

   1445         apr_thread_mutex_lock(g_timer_skiplist_mtx);
   1446         te = apr_skiplist_peek(timer_skiplist);
   1447         if (te) {
   1448             if (te->when > now) {
   1449                 timeout_interval = te->when - now;
   1450             }
   1451             else {
   1452                 timeout_interval = 1;
   1453             }
   1454         }
   1455         else {
   1456             timeout_interval = apr_time_from_msec(100);
   1457         }
   1458         apr_thread_mutex_unlock(g_timer_skiplist_mtx);
   1459

timeout_interval 変数に、その時間をセットする。
既に指定のタイムアウト時刻を過ぎていた場合には、1をセットしている。
タイムアウトイベントがなければ、100ミリ秒がセットされる。

続いて、イベントチェック処理に進む。


0 件のコメント:

コメントを投稿