(14.3) タイムアウト処理
ここで、スキップリストを処理する。
タイムアウトに至ったコールバック関数を実行している。
先にタイムアウトイベントまでの時間をチェックして、epollでは最大その時間を待つように
していた。
先のepoll_waitでタイムアウトが発生していれば、ここでタイムアウトの処理が実行されるはずだ。
もし、監視対象のソケットでイベントが発生していれば、タイムアウトより早く処理を終えているので、ここでのタイムアウト処理が行われない可能性がある。
しかし、既にタイムアウト時刻を過ぎて、timeout_intervalに1がセットされていた場合は、ここでタイムアウトが発生するだろう。
1480 now = apr_time_now();
1481 apr_thread_mutex_lock(g_timer_skiplist_mtx);
1482 ep = apr_skiplist_peek(timer_skiplist);
1483 while (ep) {
1484 if (ep->when < now + EVENT_FUDGE_FACTOR) {
このif文では、スキップリストに登録されていたタイムアウト処理の実行時刻が、現在時刻(now)から
EVENT_FUDGE_FACTORまでの範囲に収まっているか、既に過ぎていた場合に、タイムアウト処理を開始する。
1485 apr_skiplist_pop(timer_skiplist, NULL);
スキップリストからタイムアウトイベント(ep)を取り出す。
1486 push_timer2worker(ep);
push_timer2worker()は、タイムアウトイベントepをworkerスレッドとの通信用のメッセージキューに登録している。
workerスレッド側ではこれをap_queue_pop_something()で取り出す。
ここで、タイムアウトイベントは、第5引数(timer_event_t **te)に渡される。
以下 workerスレッド内の該当の処理だ。
1773 rv = ap_queue_pop_something(worker_queue, &csd, &cs, &ptrans, &te); : 1803 if (te != NULL) {
この変数teにタイムアウトイベントがセットされる。
このif文にはタイムアウトイベントが渡されてきたときに入ることになる。
1804 te->cbfunc(te->baton);
1805
これが、そのタイムアウトイベントに登録されているコールバック関数の実行だ。
以下では、実行後に処理済みのタイムアウトイベントを再利用できるように、timer_free_ringに返している。
1806 {
1807 apr_thread_mutex_lock(g_timer_skiplist_mtx);
1808 APR_RING_INSERT_TAIL(&timer_free_ring, te, timer_event_t, link);
1809 apr_thread_mutex_unlock(g_timer_skiplist_mtx);
1810 }
1811 }
1487 }
1488 else {
1489 break;
1490 }
1491 ep = apr_skiplist_peek(timer_skiplist);
そして、次のタイムアウトイベントをチェックする。
この1483行目からのwhile()ループで、タイムアウトしたタイムアウトイベントがworkerスレッドに全て渡されている。
1492 } 1493 apr_thread_mutex_unlock(g_timer_skiplist_mtx); 1494
次は、イベント処理に進む。
0 件のコメント:
コメントを投稿