Erinnern wir uns zunächst weiterhin daran, dass es im vorherigen Sub-Thread-Ausführungsvorgang einen unbeteiligten Inhalt ngx_process_events_and_timers gab. Heute werden wir diese Funktion untersuchen.
Dieser Artikel stammt von: http://blog.csdn.net/lengzijian/article/details/7601730
Schauen wir uns einige Screenshots von Abschnitt 19 an:
Heute erklären wir hauptsächlich die ereignisgesteuerte Funktion, den roten Teil im Bild:
[cpp]-Ansicht
Klartext?
- src/event/ngx_event.c
-
- void
- ngx_process_events_and_timers(ngx_cycle_t *cycle)
- {
- ngx_uint_t flags;
- ngx_msec_t timer, delta;
-
- if (ngx_timer_resolution) {
- timer = NGX_TIMER_INFINITE;
- flags = 0;
-
- } else {
- timer = ngx_event_find_timer();
- flags = NGX_UPDATE_TIME;
- }
-
- /*
- ngx_use_accept_mutex变量代表是否使用accept互斥体
- 默认是使用,可以通过accept_mutex off;指令关闭;
- akzeptieren 🎜> */
- if
(ngx_use_accept_mutex) { -
- /*
-
ngx_accept_disabled变量在ngx_event_accept函数中计算。
-
如果ngx_accept_disabled大于0,就表示该进程接受的链接过多,
-
因此放弃一次争抢Akzeptieren mutex的机会,同时将自己减一.
-
然后,继续处理已有连接上的事件。
-
nginx就利用这一点实现了继承关于连接的基本负载均衡.
- */
- if
(ngx_accept_disabled > 0) { - ngx_accept_disabled--;
-
- } else
{ -
/*
-
listen套接字放到epoll中.
-
塞在epoll_wait时,
-
才不会惊群现象。
- */
-
🎜 > (ngx_trylock_accept_mutex(cycle) == NGX_ERROR) { ><.> 🎜>
- /*
-
Wenn der Prozess die Sperre erhält, wird ein NGX_POST_EVENTS-Flag hinzugefügt.
Die Funktion dieses Flags besteht darin, alle generierten Ereignisse in eine - Warteschlange zu stellen und die Ereignisse nach ihrer Freigabe langsam zu verarbeiten. .
Da die Verarbeitungszeit sehr zeitaufwändig sein kann, wird die Sperre nicht zuerst freigegeben und dann verarbeitet , - Dadurch können andere Prozesse keine Sperren erhalten, sodass die Effizienz von ACCEPT gering ist.
-
_POST_EVENTS;
-
/* Es gibt keinen erworbenen Prozess und natürlich keine Notwendigkeit für das NGX_POST_EVENTS-Flag. -
Aber Sie müssen die Verzögerungszeit einstellen, bevor Sie um die Sperre kämpfen. - X_TIMER_INFINITE
ngx_accept_mutex_delay ) - _mutex_delay;
} } >- }
-
- delta = ngx_current_msec;
-
- /*Als nächstes startet Epoll das Warteereignis,
Die spezifische Implementierung von ngx_process_events entspricht der Funktion ngx_epoll_process_events in Das Epoll-Modul -
-
wird später ausführlich erklärt
* /-
- (void) ngx_process_events(cycle, timer, flags);
- //Statistiken zum Zeitverbrauch dieses Warteereignisses
-
delta = ngx_current_msec - delta; >
-
ngx_log_debug1(NGX_LOG_DEBUG_EVENT, Cycle->log, 0,
" Timer-Delta: %M"-
, Delta);
-
>
-
ngx_posted_accept_events ist eine Ereignis-- Warteschlange, die vorübergehend das Akzeptanzereignis speichert, auf das Epoll vom Listening-Socket wartet.
-
Nachdem das oben erwähnte NGX_POST_EVENTS-Flag verwendet wurde, werden alle Akzeptanzereignisse vorübergehend in dieser Warteschlange
-
*/
-
-
ngx_event_process_posted (cycle, &ngx_posted_accept_events); 🎜> // Nachdem alle Akzeptanzereignisse verarbeitet wurden, wird die Sperre aufgehoben, wenn sie gehalten wird.
- if (ngx_accept_mutex_held) { ngx_shmtx_unlock(&ngx_accept_mutex_); 🎜>
-
Delta ist der zuvor berechnete Zeitverbrauch. Wenn ein Zeitverbrauch im Millisekundenbereich vorliegt, überprüfen Sie die Timer aller Zeiten Timeout verwendet wird, löschen Sie den abgelaufenen Timer aus dem Time-RBTree und rufen Sie die Handlerfunktion des entsprechenden Ereignisses auf, um
*/-
-
if (Delta) {
-
ngx_event_expire_timers( );
- }
, -
- /* Normale Ereignisse verarbeiten (auf der Verbindung erhaltene Ereignisse lesen und schreiben),
- Da jedes Ereignis seine eigene Handler-Methode hat,
-
*/
-
- if (ngx_posted_events) {
-
if
- (ngx_threaded) {
ngx _wakeup_worker_thread(cycle); -
- } else {
- ngx_event_process_posted(cycle, &ngx_posted_events);
} - }
} -
Vorher gesagt: Das Accept-Ereignis lauscht tatsächlich auf neue Ereignisse am Socket Die Methode der Akzeptanzzeit wird unten vorgestellt:
-
ngx_event_accept:
[cpp] view
Klartext?
- src/event/ngx_event_accept.c
-
- void
- ngx_event_accept(ngx_event_t *ev)
- {
- socklen_t socklen;
- ngx_err_t err;
- ngx_log_t *log;
- 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->listening;
- ev->ready = 0;
-
- ngx_log_debug2(NGX_LOG_DEBUG_EVENT, ev->log, 0,
- "accept on %V, ready: %d", &ls->addr_text, ev->available);
-
- tun {
- socklen = NGX_SOCKADDRLEN;
- //accept一个新的连接
- s = accept(lc-> ;fd, (struct sockaddr *) sa, &socklen);
- //省略部分代码
-
- /*
-
accept到一个新的连接后,就重新计算ngx_accept_disabled的值,
- 它主要是用来做负载均衡,之前有提过.
-
- 这里,我们可以看到他的就只方式
- “总连接数的八分之一- 剩余的连接数“
- 总连接指每个进程设定的最大连接数,这个数字可以再配置文件中指定.
- ngx_accept_disabled ist größer als Null und die Verbindung ist überlastet
- 🎜>
-
ngx_accept_disabled = ngx_cycle->connection_n / 8 - - ngx_cycle- >free_connection_n;
>-
c = ngx_get_connection(s, ev->log); >
-
//Speicherpool für den neuen Link erstellen-
-
>
-
c->pool = ngx_create_pool(ls->pool_size, ev->log); 🎜>- 🎜>
- c->sockaddr = ngx_palloc(c->pool, socklen); >
- if (c->sockaddr == NULL) {
ngx_close_accepted_connection(c); - return; c->sockaddr, sa, socklen); 🎜>(ngx_log_t));
- > ngx_close_accepted_connection(c);
-
🎜>
}
-
- /* einen Blockierungsmodus für AIO und einen nicht blockierenden Modus für andere festlegen.*/
-
- 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 " fehlgeschlagen");
- ngx_close_accepted_connection(c);
- Rückgabe;
- }
- }
-
- } else {
- //我们使用epoll模型,这里我们设置连接为nonblocking
- > if
(ngx_nonblocking(s) == -1) { - ngx_log_error(NG X_LOG_ALERT, ev->log , ngx_socket_errno,
- ngx_nonblocking_n " fehlgeschlagen"
); - ngx_close_accepted_connection(c);
- Rückgabe
; - }
- }
- }
-
- *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- & gt; sockaddr- & gt; sa_family == af_unix) {
- c- & gt; tcp_nopush = ngx_tcp_nopush_disabled ;
- c->tcp_nodelay = NGX_TCP_NODELAY_DISABLED;
- #if (NGX_SOLARIS)
- /* Solaris's sendfilev() unterstützt AF_NCA, AF_INET und 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()
- * oder Schutz durch kritischen Abschnitt oder leichten Mutex
- *
- * - ngx_atomic_fetch_add()
- * oder Schutz durch kritischen Abschnitt oder leichten Mutex
-
* /
-
c->number = ngx_atomic_fetch_add(ngx_connection_counter, 1); - if (ngx_add_conn && (ngx_event_flags & NGX_USE_EPOL_EVENT) == 0 ) {
-
if (ngx_add_conn(c) == NGX_ERROR) {
- ngx _close_accepted_connection(c );
- Rückgabe;
- }
} -
log->data = NULL; log->handler = NULL; -
>
很重要,它将完成新连接的最后初始化工作,-
-
同时将accept到的新的连接放入epoll中;挂在这个handler上的函数,
- 🎜>
*/ -
- ls->handler(c);
- if
(ngx_event_flags & NGX_USE_KQUEUE_EVENT) { - ev->verfügbar--;
- }
-
- } während (ev ->verfügbar);
- }
acpt事件的handler方法也就是如此了.之后就是每个连接的读写事件handler方法,这一部分会直接将我们引入http模块,我们还不急,还要学习下nginx经典模块epoll。
Das Obige stellt die Nginx-Quellcode-Studiennotizen (21) vor – Ereignismodul 2 – den ereignisgesteuerten Kern ngx_process_events_and_timers, einschließlich Warteschlangeninhalten. Ich hoffe, dass es für Freunde hilfreich sein wird, die an PHP-Tutorials interessiert sind.