2014年9月4日木曜日

リクエスト処理の流れ: process_socket に戻る

(3)event MPM: process_socket関数 (再)


process_socket()関数は、workerスレッドが実行するリクエスト処理の起点だ。
リクエストの処理の流れ で見ている。

(httpd-2.4.9/server/mpm/event/event.c)
    881 static void process_socket(apr_thread_t *thd, apr_pool_t * p, apr_socket_t * sock,
    882                           event_conn_state_t * cs, int my_child_num,
    883                           int my_thread_num)

第1引数のapr_thread_t構造体は、pthread_tをメンバに持つスレッド情報。
第2引数のapr_pool_t構造体は、このトランザクションで使用するメモリプール情報。transactionメモリプールである。
第3引数のapr_socket_t構造体は、通信用のソケット情報。
第4引数のevent_conn_state_t構造体は、eventMPMの状態管理情報。
第5引数のint型は、子プロセスの管理番号。スコアボードのプロセス情報のインデックスになる。
第6引数のint型は、ワーカスレッドの管理番号。スコアボードのワーカ情報のインデックスになる。



第2引数のメモリプール、第3引数のソケット、第4引数の接続状態は、listenerスレッドから通信用のキュー(worker_queue)を経由して受け取る。
新規の接続の場合、第4引数の接続状態はNULLが渡ってくるので、新規に作成することになる。

    884 {
    885     conn_rec *c;
    886     long conn_id = ID_FROM_CHILD_THREAD(my_child_num, my_thread_num);

このマクロは次の計算を行う:my_child_num * thread_limit + my_child_num
thread_limitはThreadLimitディレクティブで指定された値。

    887     int rc;
    888     ap_sb_handle_t *sbh;
    889
    890     /* XXX: This will cause unbounded mem usage for long lasting connections */
    891     ap_create_sb_handle(&sbh, p, my_child_num, my_thread_num);

ap_sb_handle_t *sbhは子プロセスのインデックスとワーカのインデックスを保持している。
この関数で領域を確保し、引数のmy_child_numとmy_thread_numが、sbhにセットされる。
この情報は、ap_update_child_status()等の関数の引数に使用され、スコアボードの更新対象のインデックスを指定する。
スコアボードの説明も書いていないようだが、
簡単に書くと、statusモジュールなどでも参照できるプロセス/ワーカスレッドの実行状態などを管理している共有メモリ上の表だ。
これはプロセスのメンテナンス(余剰プロセスの終了や不足分プロセスの生成の処理)でも参照される。

    892
    893     if (cs == NULL) {           /* This is a new connection */

ここは新規接続の場合に行われる分岐となる。

    894         listener_poll_type *pt = apr_pcalloc(p, sizeof(*pt));
    895         cs = apr_pcalloc(p, sizeof(event_conn_state_t));

apr_pcalloc()とapr_palloc()の違いは、
apr_pcalloc()ではapr_palloc()を行った後で確保した領域を0x0で初期化している。

    896         cs->bucket_alloc = apr_bucket_alloc_create(p);
    897         c = ap_run_create_connection(p, ap_server_conf, sock,
    898                                      conn_id, sbh, cs->bucket_alloc);

create_connectionフック関数を実行する。
戻り値のcはconn_rec情報。
cs->bucket_allocは、生成されるconn_recのbucket_alloc情報にセットされる(core_create_conn()関数)。
bucket_allocはbucket brigadeの生成に使用するメモリの確保や再利用のために使用される。
利用済みのメモリなどは再利用可能なメモリ領域としてこのbucket_allocが管理する。

core_create_conn()はcoreモジュールが提供するcreate_connectionのフック関数だが、
httpdのソースに同梱されている中では、create_connectionフック関数はこのcore_create_conn()しか見当たらない。
(mod_example_hooks.cにも定義はあるが、有効な処理ではない)

(httpd-2.4.9/server/core.c)

   4592 static conn_rec *core_create_conn(apr_pool_t *ptrans, server_rec *server,
   4593                                   apr_socket_t *csd, long id, void *sbh,
   4594                                   apr_bucket_alloc_t *alloc)
   4595 {
   4596     apr_status_t rv;
   4597     conn_rec *c = (conn_rec *) apr_pcalloc(ptrans, sizeof(conn_rec));
   4598
   4599     c->sbh = sbh;
   4600     (void)ap_update_child_status(c->sbh, SERVER_BUSY_READ, (request_rec *)NULL);
   4601
   4602     /* Got a connection structure, so initialize what fields we can
   4603      * (the rest are zeroed out by pcalloc).
   4604      */
   4605     c->conn_config = ap_create_conn_config(ptrans);
   4606     c->notes = apr_table_make(ptrans, 5);
   4607
   4608     c->pool = ptrans;
   4609     if ((rv = apr_socket_addr_get(&c->local_addr, APR_LOCAL, csd))
   4610         != APR_SUCCESS) {
   4611         ap_log_error(APLOG_MARK, APLOG_INFO, rv, server, APLOGNO(00137)
   4612                      "apr_socket_addr_get(APR_LOCAL)");
   4613         apr_socket_close(csd);
   4614         return NULL;
   4615     }
   4616
   4617     apr_sockaddr_ip_get(&c->local_ip, c->local_addr);
   4618     if ((rv = apr_socket_addr_get(&c->client_addr, APR_REMOTE, csd))
   4619         != APR_SUCCESS) {
   4620         ap_log_error(APLOG_MARK, APLOG_INFO, rv, server, APLOGNO(00138)
   4621                      "apr_socket_addr_get(APR_REMOTE)");
   4622         apr_socket_close(csd);
   4623         return NULL;
   4624     }
   4625
   4626     apr_sockaddr_ip_get(&c->client_ip, c->client_addr);
   4627     c->base_server = server;
   4628
   4629     c->id = id;
   4630     c->bucket_alloc = alloc;
   4631
   4632     c->clogging_input_filters = 0;
   4633
   4634     return c;
   4635 }

core_create_conn()では、conn_rec情報の初期値がいくつかセットされる。
まず、領域がapr_pcalloc()で確保されるので、領域全体は0x0で初期化される。
pool変数には第一引数のp(transactionメモリプール)がセットされる。
server_rec *base_server変数には第2引数のap_server_conf(メインサーバのserver_rec)がセットされる。
apr_sockaddr_t* 型のlocal_addrとclient_addrの各変数は第3引数の、sock(apr_socket_t情報)から取得し、セットされる。
char * 型変数の client_ipとlocal_ipも同様。
long idには、第4引数のconn_idがセットされる。
void *sbhには、第5引数のsbhがセットされる。


以下の 899行目からのif文は、create_connectionフック関数が失敗した場合の処理になる。
確保したbucket_allocを破棄し、transactionメモリプールをクリアする(clearの場合は、中身を消すだけで、プールそのものは残っている)。
そして、transactionメモリプールをworker_queue_infoに返している。
event MPMの子プロセスはworker_queue_infoでアイドル状態のワーカ数や再利用可能なtransactionメモリプールを管理している。

上記のcore_create_conn()の返り値を見ると、apr_socket_addr_get()が失敗してソケットを閉じた場合にこの経路に入っている(return NULL)。
ざっと眺めると、これはgetsockname()が失敗した場合に相当しそうだ。
ちゃんとしたソケットがlistenerスレッドから渡ってくるはずなので、メモリ不足などでも起きない限りこの経路には入りそうではない。

    899         if (!c) {
    900             apr_bucket_alloc_destroy(cs->bucket_alloc);
    901             apr_pool_clear(p);
    902             ap_push_pool(worker_queue_info, p);
    903             return;
    904         }

以下は、connection_count変数の加算を行い減算の準備をしている。
減算は、メモリプール(c->pool)を破棄するときに実行されるcleanup関数に登録している(906行目)。
connection_countはこのevent.cファイルのファイルスコープで定義された32ビット符号なし整数。
この子プロセスの持つ接続数が保持されることになる。

    905         apr_atomic_inc32(&connection_count);
    906         apr_pool_cleanup_register(c->pool, cs, decrement_connection_count,
    907                                   apr_pool_cleanup_null);

conn_rec情報と、event_conn_state_t情報に初期設定を行われる。

    908         c->current_thread = thd;
    909         cs->c = c;
    910         c->cs = &(cs->pub);

conn_rec構造体のcs変数には、cs->pubがセットされている。

    911         cs->p = p;
    912         cs->pfd.desc_type = APR_POLL_SOCKET;
    913         cs->pfd.reqevents = APR_POLLIN;
    914         cs->pfd.desc.s = sock;
    915         pt->type = PT_CSD;
    916         pt->baton = cs;
    917         cs->pfd.client_data = pt;
    918         TO_QUEUE_ELEM_INIT(cs);
    919
    920         ap_update_vhost_given_ip(c);

ソケットの接続情報(ローカルIPアドレス、ポート番号)をもとに、
対応するIPベースのVirtualHostの設定を確認し、あれば、その情報をconn_recのbase_server情報にセットする。
(初期設定はメインサーバになっている)

    921
    922         rc = ap_run_pre_connection(c, sock);

pre_connectionフック関数を実行する。
pre_connectionフック関数はcoreモジュール以外からもフック関数が登録される。

  • coreモジュールが提供するcore_pre_connection()
  • mod_sslが提供する ssl_hook_pre_connection()
  • mod_logioが提供する logio_pre_conn()
  • mod_dumpioが提供する dumpio_pre_conn()

最低限coreモジュールのフック関数だけ登録されていればHTTPリクエストは処理できる。

(httpd-2.4.9/server/core.c)
   4637 static int core_pre_connection(conn_rec *c, void *csd)

第1引数はconn_rec情報、第2引数はapr_socket_t情報が与えられている。

   4638 {
   4639     core_net_rec *net = apr_palloc(c->pool, sizeof(*net));
   4640     apr_status_t rv;
   4641
   4642     /* The Nagle algorithm says that we should delay sending partial
   4643      * packets in hopes of getting more data.  We don't want to do
   4644      * this; we are not telnet.  There are bad interactions between
   4645      * persistent connections and Nagle's algorithm that have very severe
   4646      * performance penalties.  (Failing to disable Nagle is not much of a
   4647      * problem with simple HTTP.)
   4648      */
   4649     rv = apr_socket_opt_set(csd, APR_TCP_NODELAY, 1);

ソケットに対するTCP_NODELAYオプションを有効にする。
これはデフォルトで有効なっているNagle(ネーグル)アルゴリズムを無効にする。
Nagleアルゴリズムは、細かい点はさておいて、データの送信時にあまり小さなデータをそのまま送信するのではなく、ある程度まとめて送信するために
少し待つ。この結果、小さいデータを細切れのパケットで送るのではなく、大きめのデータをひとつのパケットで送ることができる。
これにはネットワーク帯域の利用効率を高める効果がある。
これを無効にするということは、小さなデータであっても直ちに送信する、ということになる。
コメントにある、持続的(Keep-Alive)接続とNagleアルゴリズムの悪い相互作用というのは、おそらく、Apache httpdがレスポンスを返すとき、
何度か送信する最後のレスポンスの断片の送信処理で、十分なサイズのデータが残っていなければ、Nagleアルゴリズムによって送信が遅延し、
つまり、リクエスト/レスポンスのやり取りの完了が遅延してしまう可能性があるということではないか。
(ソケットを閉じるなら、未送信の小さなデータがあっても送信される)

   4650     if (rv != APR_SUCCESS && rv != APR_ENOTIMPL) {
   4651         /* expected cause is that the client disconnected already,
   4652          * hence the debug level
   4653          */
   4654         ap_log_cerror(APLOG_MARK, APLOG_DEBUG, rv, c, APLOGNO(00139)
   4655                       "apr_socket_opt_set(APR_TCP_NODELAY)");

エラーの場合は、DEBUGログを出力するだけ。

   4656     }
   4657
   4658     /* The core filter requires the timeout mode to be set, which
   4659      * incidentally sets the socket to be nonblocking.  If this
   4660      * is not initialized correctly, Linux - for example - will
   4661      * be initially blocking, while Solaris will be non blocking
   4662      * and any initial read will fail.
   4663      */
   4664     rv = apr_socket_timeout_set(csd, c->base_server->timeout);

タイムアウトを設定する。
ここでは、apr_socket_t構造体(*csd)のtimeout変数に c->base_server->timeoutをセットする。

   4665     if (rv != APR_SUCCESS) {
   4666         /* expected cause is that the client disconnected already */
   4667         ap_log_cerror(APLOG_MARK, APLOG_DEBUG, rv, c, APLOGNO(00140)
   4668                       "apr_socket_timeout_set");
   4669     }
   4670

core_net_rec構造体 *net に値をセットする。

   4671     net->c = c;
   4672     net->in_ctx = NULL;
   4673     net->out_ctx = NULL;
   4674     net->client_socket = csd;
   4675
   4676     ap_set_core_module_config(net->c->conn_config, csd);

csdをconn_recのconn_configのcoreモジュール情報領域に登録する。

   4677     ap_add_input_filter_handle(ap_core_input_filter_handle, net, NULL, net->c);

入力フィルタ ap_core_input_filter_handle("CORE_IN")を登録する。
実体は ap_core_input_filter()関数だ。
net情報がフィルタ処理のコンテキスト情報として渡されている。


   4678     ap_add_output_filter_handle(ap_core_output_filter_handle, net, NULL, net->c);

出力フィルタ ap_core_output_filter_handle("CORE")を登録する。
実体は ap_core_output_filter()関数だ。
こちらでも、net情報がフィルタ処理のコンテキスト情報として渡されている。

   4679     return DONE;
   4680 }

mod_sslのpre_connectionフック関数ではHTTPSリクエスト処理のために必要なフィルタが追加されるが、これは改めて確認して書くことにする。

以下の923行目からのif文は、pre_connectionフック関数が失敗した場合の処理だ。
ただし、ここでは、conn_recのabortedフラグに1をセットするだけで、関数処理が終了していない。
create_connectionフック関数の失敗時とは異なっている。

    923         if (rc != OK && rc != DONE) {
    924             ap_log_cerror(APLOG_MARK, APLOG_DEBUG, 0, c, APLOGNO(00469)
    925                           "process_socket: connection aborted");
    926             c->aborted = 1;
    927         }
    928
    929         /**
    930          * XXX If the platform does not have a usable way of bundling
    931          * accept() with a socket readability check, like Win32,
    932          * and there are measurable delays before the
    933          * socket is readable due to the first data packet arriving,
    934          * it might be better to create the cs on the listener thread
    935          * with the state set to CONN_STATE_CHECK_REQUEST_LINE_READABLE
    936          *
    937          * FreeBSD users will want to enable the HTTP accept filter
    938          * module in their kernel for the highest performance
    939          * When the accept filter is active, sockets are kept in the
    940          * kernel until a HTTP request is received.
    941          */
    942         cs->pub.state = CONN_STATE_READ_REQUEST_LINE;
    943
    944         cs->pub.sense = CONN_SENSE_DEFAULT;

942行目で接続状態の初期値がセットされる(接続を受け付けた状態)。
cs->pubの値は、作成したconn_rec情報のcs変数で参照できる。

ここまでで、conn_rec情報のセットアップが完了する。

    945     }
    946     else {

こちらはKeepAlive接続の場合や、書込み可能が検知された場合の条件(この接続がworkerスレッドで処理されるのが2回目以上)となる。
conn_rec情報は、event_conn_state_t情報に既に持っているものをセットする。
sbh情報は、前回の処理時とは異なるスレッドで実行されると別の値になるので、改めてセットされている。

    947         c = cs->c;
    948         c->sbh = sbh;
    949         c->current_thread = thd;
    950     }

    951
    952     if (c->clogging_input_filters && !c->aborted) {

ここは同期型のリクエスト処理を行う場合の条件分岐になる。
event MPMは基本的には非同期型のリクエスト処理なので、ここには来ない。
httpd-2.4.6ではmod_sslのpre_connectionフック関数内の処理でclogging_input_filtersに1がセットされていたが、2.4.9では0だ。

    953         /* Since we have an input filter which 'clogs' the input stream,
    954          * like mod_ssl used to, lets just do the normal read from input
    955          * filters, like the Worker MPM does. Filters that need to write
    956          * where they would otherwise read, or read where they would
    957          * otherwise write, should set the sense appropriately.
    958          */
    959         apr_atomic_inc32(&clogged_count);
    960         ap_run_process_connection(c);

process_connectionフック関数を実行する。
非同期の場合の経路なので、http_coreモジュールのprocess_connectionフック関数である
ap_process_http_connection() で実行されるのは ap_process_http_sync_connection()の方になる。

    961         if (cs->pub.state != CONN_STATE_SUSPENDED) {
    962             cs->pub.state = CONN_STATE_LINGER;
    963         }
    964         apr_atomic_dec32(&clogged_count);
    965     }
    966
    967 read_request:

このラベルは、1017行目から使用されている。
既に読込可能なデータ(リクエスト等)がソケットに到着していた場合、
同じスレッドで同じconn_recを処理するので、直ちにここから処理を開始するために使用されている。
この場合1011行目の条件に該当しないので、c->abortedフラグは立っていない。

    968     if (cs->pub.state == CONN_STATE_READ_REQUEST_LINE) {

新規接続の受付か、Keep-Aliveな接続での次のリクエストの受付の場合の処理となる
Keep-Aliveな接続で次のリクエストを待っていて、TCPコネクション断(EOF)となった場合もここに来る。

    969         if (!c->aborted) {
    970             ap_run_process_connection(c);

process_connectionフック関数を実行する。
1件のリクエストの処理が、ここで行われる。
event MPMで、通常の処理なので、ap_process_http_async_connection()が実行される。
終了時にはcs->pub.stateは

  • CONN_STATE_WRITE_COMPLETION
  • CONN_STATE_SUSPENDED
  • CONN_STATE_LINGER

のいずれかとなっている。

ap_process_http_async_connection()の最後で実行されるap_process_request_after_handler()の処理でCONN_STATE_WRITE_COMPLETION がセットされる。通常はこの状態だ。
httpd-2.4.9でCONN_STATE_SUSPENDEDを返す可能性があるのはmod_dialupだけのようだ。
ここでのCONN_STATE_LINGERは何らかのエラーで接続を閉じるべき状態となったケースだ。

    971
    972             /* state will be updated upon return
    973              * fall thru to either wait for readability/timeout or
    974              * do lingering close
    975              */
    976         }
    977         else {

pre_connectionフック関数の実行で問題があった場合はこの分岐に入る(926行目)。

    978             cs->pub.state = CONN_STATE_LINGER;
    979         }
    980     }
    981
    982     if (cs->pub.state == CONN_STATE_WRITE_COMPLETION) {

正常にリクエスト処理を終えている場合はこの分岐に入る。

ここで、conn_recの出力フィルタ(コネクションフィルタ)の最下層のフィルタ(通常なら"CORE"出力フィルタ)に対して bucket brigade を NULLで引き渡し処理を行っている。
未処理のbucket brigadeが出力フィルタのコンテキストデータ内に保持されているのでこれを処理するためだと考えられる。

    983         ap_filter_t *output_filter = c->output_filters;
    984         apr_status_t rv;
    985         ap_update_child_status_from_conn(sbh, SERVER_BUSY_WRITE, c);
    986         while (output_filter->next != NULL) {
    987             output_filter = output_filter->next;
    988         }
    989         rv = output_filter->frec->filter_func.out_func(output_filter, NULL);
    990         if (rv != APR_SUCCESS) {

処理エラーの場合はCONN_STATE_LINGERが状態にセットされる。

    991             ap_log_cerror(APLOG_MARK, APLOG_DEBUG, rv, c, APLOGNO(00470)
    992                           "network write failure in core output filter");
    993             cs->pub.state = CONN_STATE_LINGER;
    994         }
    995         else if (c->data_in_output_filters) {

出力フィルタが正常に処理終了して、conn_rec情報のdata_in_output_filtersが1の場合の処理
通常は、出力がブロックされて(ソケットへの書き込みが不可)、未送信のデータが残っている状態と考えられる。

    996             /* Still in WRITE_COMPLETION_STATE:
    997              * Set a write timeout for this connection, and let the
    998              * event thread poll for writeability.
    999              */

この場合、書込み可能になるまで待機する。
4つのタイムアウトキュー(event MPMのタイムアウトキュー http://ohgrkrs-blog.blogspot.com/2014/04/event-mpm.html)
のうちのwrite_completion_qに対して、タイムアウトイベントを登録する。
また、listenerスレッドの監視対象のソケットにcs情報が持っているソケット(cs->pfd)を追加し、書込み可能になるのを監視する。

   1000             cs->expiration_time = ap_server_conf->timeout + apr_time_now();
   1001             apr_thread_mutex_lock(timeout_mutex);
   1002             TO_QUEUE_APPEND(write_completion_q, cs);
   1003             cs->pfd.reqevents = (
   1004                     cs->pub.sense == CONN_SENSE_WANT_READ ? APR_POLLIN :
   1005                             APR_POLLOUT) | APR_POLLHUP | APR_POLLERR;
   1006             cs->pub.sense = CONN_SENSE_DEFAULT;
   1007             rc = apr_pollset_add(event_pollset, &cs->pfd);
   1008             apr_thread_mutex_unlock(timeout_mutex);
   1009             return;

ここでは、接続の状態はWRITE_COMPLETION_STATEのままとなっている。
ここで、process_socket()関数の処理が終了する。

   1010         }
   1011         else if (c->keepalive != AP_CONN_KEEPALIVE || c->aborted ||
   1012             listener_may_exit) {

Keep-Alive接続でない場合、接続が異常な場合、プロセスの終了指示があった場合はこの分岐になる。

   1013             cs->pub.state = CONN_STATE_LINGER;

接続の状態にCONN_STATE_LINGERがセットされる。

   1014         }
   1015         else if (c->data_in_input_filters) {

読込可能なデータがあった場合がこの分岐になる。
ap_process_http_async_connection()関数の最後に実施されたap_process_request_after_handler()の処理でセットされている。

   1016             cs->pub.state = CONN_STATE_READ_REQUEST_LINE;

接続の状態をCONN_STATE_READ_REQUEST_LINEにする。

   1017             goto read_request;

ただちに(この同じworkerスレッドの処理で)、処理を継続する。
リクエストパイプラインで、リクエストを順次送りつけてくる場合はこの経路になる。
また、通常のKeep-Alive処理でも、タイミングによっては(レスポンスを返すのと次のリクエストを受けるのが同時程度か、リクエストの方が早い状態)、この経路になる。
漠然とした印象としては、そんな場合にもいったん上位のイベント取得に戻されるべきのような気もするが、部分最適にはなっているのだろう。

   1018         }
   1019         else {

それ以外の条件。
Keep-Alive接続だが、この時点では受信データが確認できていない場合だ。

   1020             cs->pub.state = CONN_STATE_CHECK_REQUEST_LINE_READABLE;

接続の状態をCONN_STATE_CHECK_REQUEST_LINE_READABLEにする。

   1021         }
   1022     }
   1023
   1024     if (cs->pub.state == CONN_STATE_LINGER) {

この分岐では、接続を終了する。

   1025         if (!start_lingering_close_blocking(cs))

ここでは、csで扱われているソケットの書き込み停止が指示される(shutdown(SHUT_WR))。
処理中、問題が生じた場合にはソケットは閉じられ(close())、この関数の処理を抜ける(1026行目)。

   1026             return;
   1027     }
   1028     else if (cs->pub.state == CONN_STATE_CHECK_REQUEST_LINE_READABLE) {
   1029         /* It greatly simplifies the logic to use a single timeout value here
   1030          * because the new element can just be added to the end of the list and
   1031          * it will stay sorted in expiration time sequence.  If brand new
   1032          * sockets are sent to the event thread for a readability check, this
   1033          * will be a slight behavior change - they use the non-keepalive
   1034          * timeout today.  With a normal client, the socket will be readable in
   1035          * a few milliseconds anyway.
   1036          */

ここでは、Keep-Alive接続上での次のリクエストの受信待ちを待機する。
4つのタイムアウトキュー(event MPMのタイムアウトキュー) のうちのkeepalive_qに対して、タイムアウトイベントを登録する。
また、listenerスレッドの監視対象のソケットにcs情報が持っているソケット(cs->pfd)を追加し、読込可能になるのを監視する。

   1037         cs->expiration_time = ap_server_conf->keep_alive_timeout +
   1038                               apr_time_now();
   1039         c->sbh = NULL;
   1040         apr_thread_mutex_lock(timeout_mutex);
   1041         TO_QUEUE_APPEND(keepalive_q, cs);
   1042
   1043         /* Add work to pollset. */
   1044         cs->pfd.reqevents = APR_POLLIN;
   1045         rc = apr_pollset_add(event_pollset, &cs->pfd);
   1046         apr_thread_mutex_unlock(timeout_mutex);
   1047
   1048         if (rc != APR_SUCCESS) {
   1049             ap_log_error(APLOG_MARK, APLOG_ERR, rc, ap_server_conf,
   1050                          "process_socket: apr_pollset_add failure");
   1051             AP_DEBUG_ASSERT(rc == APR_SUCCESS);
   1052         }
   1053         return;

接続の状態はCONN_STATE_CHECK_REQUEST_LINE_READABLEのままとなっている。
ここで、process_socket()関数の処理が終了する。

   1054     }
   1055     else if (cs->pub.state == CONN_STATE_SUSPENDED) {

SUSPENDED状態の場合は、何も処理しない。

   1056         apr_atomic_inc32(&suspended_count);
   1057     }
   1058     /*
   1059      * Prevent this connection from writing to our connection state after it
   1060      * is no longer associated with this thread. This would happen if the EOR
   1061      * bucket is destroyed from the listener thread due to a connection abort
   1062      * or timeout.
   1063      */
   1064     c->sbh = NULL;
   1065     return;
   1066 }


これで、process_socket関数は終了となる。

0 件のコメント:

コメントを投稿