(14.5) タイムアウトキューの処理
次は、4つ用意されているタイムアウトキューに対する、タイムアウト処理だ。
タイムアウトに至る前にイベントが発生して、1655行目までのソケットイベント処理で消化されれば
特に何も行われない。
タイムアウトに至るまでに、ソケットの読み込み/書き出しが可能とならなかった場合に、それらソケットが次の処理の対象となる。
1656
1657 /* XXX possible optimization: stash the current time for use as
1658 * r->request_time for new requests
1659 */
1660 now = apr_time_now();
まず、現在時刻を取得する。単位はマイクロ秒だ。
1661 /* we only do this once per 0.1s (TIMEOUT_FUDGE_FACTOR) */
1662 if (now > timeout_time) {
timeout_timeは初期値は0なので、最初はこのif文に必ず入る。
そして、timeout_timeに現在時刻のTIMEOUT_FUDGE_FACTOR後にセットしている(1664行目)。
定義を見ると、100000マイクロ秒なので、0.1秒。
1396 #define TIMEOUT_FUDGE_FACTOR 100000
おおむね、0.1秒以上間隔をあけてチェックするということだろう。
1663 struct process_score *ps;
1664 timeout_time = now + TIMEOUT_FUDGE_FACTOR;
1665
1666 /* handle timed out sockets */
1667 apr_thread_mutex_lock(timeout_mutex);
1668
1669 /* Step 1: keepalive timeouts */
1670 /* If all workers are busy, we kill older keep-alive connections so that they
1671 * may connect to another process.
1672 */
(1)KeepAliveタイムアウト
keepalive_qキューを処理する。 1673 if (workers_were_busy && keepalive_q.count) {
この時点でworkers_were_busyが1の場合(アイドルworkerスレッドがいない場合)で、
KeepAliveタイムアウトキューに登録がある場合(次のリクエストを待っている場合)、
現在時刻(+0.1秒)からKeepAliveTimeOut先までのタイムアウトイベントを先取りして
リンガリングクローズを実行している。
上記のコメントによれば、すべてのworkerがビジーなら、古いKeep-Alive接続を終了し、
クライアントが必要になった時点で別のプロセスに接続できるようにするということだ。
しかし、KeepAliveTimeOut先でこのkeepalive_qキューのタイムアウトは登録されるのだから、
古いというか、おそらくこの時点で登録済みのすべてのKeepAlive待ちイベントが
全てstart_lingering_close_nonblocking()関数処理されると考えられる。
start_lingering_close_nonblocking()関数は、
既に見た
start_lingering_close_blocking
と異なり、shutdown(SHUT_WR)の前に未出力のデータのフラッシュを試みない。
それ以外は同様で、この処理によって、ソケットはLINGER待ちになりlinger_qキュー、またはshort_linger_qキューに
登録される。
1674 ap_log_error(APLOG_MARK, APLOG_TRACE1, 0, ap_server_conf, 1675 "All workers are busy, will close %d keep-alive " 1676 "connections", 1677 keepalive_q.count); 1678 process_timeout_queue(&keepalive_q, 1679 timeout_time + ap_server_conf->keep_alive_timeout, 1680 start_lingering_close_nonblocking); 1681 } 1682 else {
こちらは、通常の場合で、
timeout_time(現在時刻+0.1秒)時点でタイムアウトしているタイムアウトイベントを
同じく、start_lingering_close_nonblocking()関数処理している。
1683 process_timeout_queue(&keepalive_q, timeout_time, 1684 start_lingering_close_nonblocking); 1685 } 1686 /* Step 2: write completion timeouts */
(2)書き込み完了タイムアウト
ここは、write_completion_qキューを処理する。
タイムアウト時間が来ていた場合に行う処理は、start_lingering_close_nonblocking()で、
これはKeepAlive待ちと同じだ。
通常は、shutdown(SHUT_WR)が行われ、linger_qキューに登録される。
1687 process_timeout_queue(&write_completion_q, timeout_time, 1688 start_lingering_close_nonblocking); 1689 /* Step 3: (normal) lingering close completion timeouts */
(3)リンガリングクローズタイムアウト(標準)
linger_qキューの処理だ。ここでのタイムアウト時の処理は、stop_lingering_close()だ。
この処理は、ソケットをクローズする。
1690 process_timeout_queue(&linger_q, timeout_time, stop_lingering_close); 1691 /* Step 4: (short) lingering close completion timeouts */
(4)リンガリングクローズタイムアウト(短時間)
short_linger_qキューの処理だ。ここでのタイムアウト時の処理も、linger_qキューと同じで、stop_lingering_close()だ。
ソケットをクローズする。
1692 process_timeout_queue(&short_linger_q, timeout_time, stop_lingering_close); 1693
ここまででタイマーキューの処理は終わりになる。
以下は、いくつかの管理情報の更新処理だ。
1694 ps = ap_get_scoreboard_process(process_slot); 1695 ps->write_completion = write_completion_q.count; 1696 ps->keep_alive = keepalive_q.count; 1697 apr_thread_mutex_unlock(timeout_mutex); 1698 1699 ps->connections = apr_atomic_read32(&connection_count); 1700 ps->suspended = apr_atomic_read32(&suspended_count); 1701 ps->lingering_close = apr_atomic_read32(&lingering_count); 1702 } 1703 if (listeners_disabled && !workers_were_busy 1704 && (int)apr_atomic_read32(&connection_count) 1705 - (int)apr_atomic_read32(&lingering_count) 1706 < ((int)ap_queue_info_get_idlers(worker_queue_info) - 1) 1707 * worker_factor / WORKER_FACTOR_SCALE + threads_per_child) 1708 { 1709 listeners_disabled = 0; 1710 enable_listensocks(process_slot); 1711 } 1712 /* 1713 * XXX: do we need to set some timeout that re-enables the listensocks 1714 * XXX: in case no other event occurs? 1715 */ 1716 } /* listener main loop */
ここまでで主ループは終わる。
listenerスレッドの終了処理では、Listenソケットをクローズし、workerスレッド向けのメッセージキューに終了通知を登録する。
1717 1718 close_listeners(process_slot, &closed); 1719 ap_queue_term(worker_queue); 1720 1721 apr_thread_exit(thd, APR_SUCCESS); 1722 return NULL; 1723 }
これで、listener_threadの処理を終わる。
0 件のコメント:
コメントを投稿