まず最初に、前のサブスレッド実行操作には関与しないコンテンツ ngx_process_events_and_timers があることを思い出してください。今日はこの関数を学習します。
この記事の引用元: http://blog.csdn.net/lengzijian/article/details/7601730
セクション 19 のスクリーンショットをいくつか見てみましょう:
今日はイベント駆動関数、図の赤い部分を中心に説明します:
[cpp]ビュー
普通のコピープリント?
- src/event/ngx_event.c
-
- void
- ngx_process_events_and_timers(ngx _cycle_t *サイクル)
- {
- ngx_uint_t フラグ
- ngx_msec_t タイマー、デルタ;
-
- (ngx_timer_resolution) { 時間 r = NGX_TIMER_INFINITE ;
- } 他の
{ - タイマー = ngx_event_find_timer();
- フラグ = NGX_UPDATE_TIME } /*
ngx_use_accept_mutex 変数は、ミューテックス -
を使用するかどうかを表します
- はデフォルトで使用され、accept_mutex off コマンドを使用してオフにできます。
-
ngx_accept_disabled 変数は ng で計算されます。 x_event_accept 関数。
-
ngx_accept_disabled が 0 より大きい場合、プロセスが受け入れるリンクが多すぎることを意味します。
-
したがって、受け入れミューテックスを獲得するために競合する機会を放棄し、自分自身を 1 つ減らします。
-
次に、既存の接続でイベントの処理を続けます。
-
nginx はこれを利用して、継承された接続の基本的な負荷分散を実装します。
-
ngx_accept_disabled-- ;
- /* ミューテックスのロックを正常に取得した場合にのみ、Listen は EPOLL にワードを入れることができます。
- したがって、これにより、1 つのプロセスだけが listen ソケットを持つことが保証されるため、すべてのプロセスが epoll_wait でブロックされた場合でも、
- はグループパニックを引き起こしません。
- プロセスがロックを取得すると、NGX_POST_EVENTS フラグが追加されます。
-
このフラグの機能は、生成されたすべてのイベントを キュー に入れ、イベントが解放された後にゆっくりと処理することです。 - - 処理される、処理されるなど。効率は低い。 ️
-
} else{
未取得 結果のプロセスには、当然のことながら、NGX_POST_EVENTS フラグは必要ありません。
-
ただし、ロックを争う前に遅延時間を設定する必要があります。
- */
- (タイマー == ngx_timer_infinite
- || タイマー & gt; ex_dlay) {
-
タイマー = ngx_acceth_mutex_lay
-
-
delta = ngx_current_msec;
-
-
/*次に、epoll は待機イベントを開始します
-
ngx_process_events の具体的な実装epoll モジュールの ngx_epoll_process_events 関数に対応します
ここで詳しく説明します - */
- ( void
) ngx_process_events(cycle, timer, flags); - / / 統計この待機イベントの消費時間
- delta = ngx_current_msec-delta
- ngx_log_debug1(NGX_LOG_DEBUG_EVENT,cycle->log, 0,
- /*
ngx_posted_accept_events はイベント - queue であり、リッスンソケットからの受け入れイベント epoll 待機を一時的に保存します。
上記の NGX_POST_EVENTS フラグが使用された後、すべての受け入れイベントはこの - キューに一時的に保存されます
*/-
- if
(ngx_posted_accept_events ) { - ngx_event_process_posted(cycle, &ngx_posted_accept_events);
- } //すべての受け入れイベントが処理された後、ロックが保持されている場合は解放します。
- if (ngx_accept_mutex_held) {
- ngx_shmtx_unlock(&ngx_accept_mutex) }
-
-
/*
-
デルタは前です統計的に時間がかかる場合は、ミリ秒レベルの時間がかかる場合は、すべての時刻のタイマーを確認します。
-
タイムアウトの場合は、時間切れのタイマーを時間 rbtree から削除し、そのハンドラー関数を呼び出します。処理する対応するイベント
- */
- if
(delta) { - ngx_event_expire_timers();
} ngx_log_debug1 (NGX_LOG_DEBUG_EVENT、サイクル>ログ、0、 - /*
- 通常のイベントの処理 (接続イベントで取得されたデータの読み取りおよび書き込み)、
- 各イベントには独自のハンドラー メソッド、
- */
-
if
- (ngx_posted_events) {
- if (ngx_threaded) {
ngx_wakeup_worker_thread(cycle); : - } }
- 受け入れイベントについては以前お話しましたが、実際には、ソケット上に新しいイベントがあるかどうかを監視します。受け入れ時のハンドラーメソッド:
ngx_event_accept:
- [cpp] view
普通のコピープリント?
- src/event/ngx_event_accept.c
-
- void
- ngx_event_accept(ngx_even t_t *ev)
- {
- socklen_t socklen;
- ngx_err_t エラー;
- ngx_log_t *ログ;
- ngx_socket_t s;
- ngx_event_t *rev、*wev;
- ngx_listening_t *ls;
- ngx_connection_t *c, *lc;
- ngx_event_conf_t *ecf;
- u_char sa[NGX_SOCKADDRLEN];
-
- //一部省略
-
- lc = ev->data;
- ls = lc->リスニング;
- ev->ready = 0;
-
- ngx_log_debug2(NGX_LOG_DEBUG_EVENT, ev->log, 0,
- "%V で受け入れます、準備完了: %d", &ls->addr_text, ev->利用可能);
-
- do {
- socklen = NGX_SOCKADDRLEN;
- //新しい接続を受け入れます
- s = accept(lc->fd, (struct sockaddr *)さ、&socklen);
- //一部省略
-
- /*
- 新しい接続を受け入れた後、新たに計算ngx_accept_disabledの值、
-
- ここでは、私たちは他の内容を閲覧できます。只今
-
「总接続数的」 8分の1 - 残りの接続数「
-
すべての接続は、各プロセスで設定された最大接続数を指し、この数字はファイル内で再構成できます。合計接続数の 7/8 を超えると、NGX_ACCEPT_DISABLED が 0 より大きくなり、接続が過負荷になります
-
-
*/
-
- ngx_accept_disabled = ngx_cycle->connection_n / 8
- ngx_cycle->free_connection_n c = ngx_get_connection(s, ev- >ログ); -
- //接続が閉じられた場合にのみ解放 pool
-
- if (c->pool == NULL ) {
ngx _close_accepted_connection(c); - ); ;
if (log == null) {- ngx_close_accepted_connection (c);
-
- /* aio にはブロッキング モードを設定し、その他にはノンブロッキング モードを設定します*/
-
- if (ngx_inherited_nonblocking) {
- if (ngx_event_flags & NGX_USE_AIO_EVENT) {
-
if (ngx_blocking(s) == -1) {
- ngx_log_error(NGX_LOG_ALERT, ev->log, ngx_socket_errno,
- ngx_blocking_n " 失敗しました");
- ngx_close_accepted_connection(c);
- 戻る;
- }
- }
-
- } else {
- //我们epollモデルを使用、这里我们设置连接はノンブロッキングです
- if (!(ngx_event_flags & (NGX_USE_AIO_EVENT|NGX_USE_RTSIG_EVENT))) {
- if (ngx_nonblocking(s) == -1) {
- ngx_log_error(NGX_LOG_ALERT, ev-> ;log、ngx_socket_errno、
- ngx_nonblocking_n " 失敗しました");
- ngx_close_accepted_connection(c);
- 戻る;
- }
- }
- }
-
- *log = ls->log;
- //初化新的接続
- c->recv = ngx_recv;
- c->send = ngx_send;
- c->recv_chain = ngx_recv_chain;
- c->send_chain = ngx_send_chain;
-
- c->log = log;
- c->pool->log = log;
-
- c->socklen = socklen;
- c->listening = ls;
- c->local_sockaddr = ls->sockaddr;
-
- c->unexpected_eof = 1;
-
- #if (NGX_HAVE_UNIX_DOMAIN)
- if (c->sockaddr-&g t;sa_family == AF_UNIX) {
- c->tcp_nopush = NGX_TCP_NOPUSH_DISABLED;
- c->tcp_nolay = NGX_TCP_NODELAY_DISABLED;
- #if (NGX_SOLARIS)
- /* Solaris の sendfilev() は AF_NCA、 AF_INET、および AF_INET6 をサポートしています */
- c->sendfile = 0;
- #endif
- }
- #endif
-
- rev = c->read;
- wev = c->write;
-
- wev->ready = 1;
-
- if (ngx_event_flags & (NGX_USE_AIO_EVENT|NGX_USE_RTSIG_EVENT)) {
- /* rtsig, aio, iocp */
- rev->ready = 1;
- }
-
- if (ev->deferred_accept) {
- rev->ready = 1;
- #if (NGX_HAVE_KQUEUE)
- rev->available = 1;
- #endif
- }
-
- rev->log = log;
- wev->log = log;
-
- /*
- * TODO: MT: - ngx_atomic_fetch_add()
- * または クリティカルセクションまたはライトミューテックスによる保護
-
*
- * TODO: MP: - 共有メモリに割り当てられています
-
* - ngx_atomic_fetch_add()
- * またはクリティカルセクションまたはライトミューテックスによる保護
- */
-
- c->number = ngx_atomic_fetch_add(ngx_connection_counter, 1);
-
-
if (ngx_add_conn && (ngx_event_flags & NGX_USE_EPOLL_EVENT) == 0) {
- if (ngx_add_conn(c) == NGX_ERROR) {
- ngx_close_accepted_connection (c);
- 戻る;
- }
- }
-
- log->data = NULL;
- log->handler = NULL;
-
- /*
- このリスン ハンドラー重要、新しい接続の最後の初期化作業を完了します,
- 同時に受け入れられた新しい接続がepollに投入されます中;挂在このハンドラー上の関数,
- 就是ngx_http_init_connection 在之后http模块中在详细介绍
- */
- ls->handler(c);
-
- if (ngx_event_flags & NGX_USE_KQUEUE_EVENT) {
- ev-> ;利用可能--;
- }
-
- } その間 (EV->利用可能);
- }
accpt イベントのハンドラー メソッドもこのとおりです。その後は、各接続のコメント イベント ハンドラー メソッドであり、この部分は http モジュールに直接導入されます。更要学习下nginx经典模块epoll。
上記は、nginx ソース コード学習ノート (21) - イベント モジュール 2 - イベント駆動型コア ngx_process_events_and_timers をキューの内容も含めて紹介しています。PHP チュートリアルに興味のある友人に役立つことを願っています。