comparison src/event/ngx_event_accept.c @ 6153:4f6efabcb09b

The "reuseport" option of the "listen" directive. When configured, an individual listen socket on a given address is created for each worker process. This allows to reduce in-kernel lock contention on configurations with high accept rates, resulting in better performance. As of now it works on Linux and DragonFly BSD. Note that on Linux incoming connection requests are currently tied up to a specific listen socket, and if some sockets are closed, connection requests will be reset, see https://lwn.net/Articles/542629/. With nginx, this may happen if the number of worker processes is reduced. There is no such problem on DragonFly BSD. Based on previous work by Sepherosa Ziehau and Yingqi Lu.
author Maxim Dounin <mdounin@mdounin.ru>
date Wed, 20 May 2015 15:51:56 +0300
parents adba26ff70b5
children 8f038068f4bc
comparison
equal deleted inserted replaced
6152:3c344ea7d88b 6153:4f6efabcb09b
9 #include <ngx_core.h> 9 #include <ngx_core.h>
10 #include <ngx_event.h> 10 #include <ngx_event.h>
11 11
12 12
13 static ngx_int_t ngx_enable_accept_events(ngx_cycle_t *cycle); 13 static ngx_int_t ngx_enable_accept_events(ngx_cycle_t *cycle);
14 static ngx_int_t ngx_disable_accept_events(ngx_cycle_t *cycle); 14 static ngx_int_t ngx_disable_accept_events(ngx_cycle_t *cycle, ngx_uint_t all);
15 static void ngx_close_accepted_connection(ngx_connection_t *c); 15 static void ngx_close_accepted_connection(ngx_connection_t *c);
16 16
17 17
18 void 18 void
19 ngx_event_accept(ngx_event_t *ev) 19 ngx_event_accept(ngx_event_t *ev)
107 continue; 107 continue;
108 } 108 }
109 } 109 }
110 110
111 if (err == NGX_EMFILE || err == NGX_ENFILE) { 111 if (err == NGX_EMFILE || err == NGX_ENFILE) {
112 if (ngx_disable_accept_events((ngx_cycle_t *) ngx_cycle) 112 if (ngx_disable_accept_events((ngx_cycle_t *) ngx_cycle, 1)
113 != NGX_OK) 113 != NGX_OK)
114 { 114 {
115 return; 115 return;
116 } 116 }
117 117
388 388
389 ngx_log_debug1(NGX_LOG_DEBUG_EVENT, cycle->log, 0, 389 ngx_log_debug1(NGX_LOG_DEBUG_EVENT, cycle->log, 0,
390 "accept mutex lock failed: %ui", ngx_accept_mutex_held); 390 "accept mutex lock failed: %ui", ngx_accept_mutex_held);
391 391
392 if (ngx_accept_mutex_held) { 392 if (ngx_accept_mutex_held) {
393 if (ngx_disable_accept_events(cycle) == NGX_ERROR) { 393 if (ngx_disable_accept_events(cycle, 0) == NGX_ERROR) {
394 return NGX_ERROR; 394 return NGX_ERROR;
395 } 395 }
396 396
397 ngx_accept_mutex_held = 0; 397 ngx_accept_mutex_held = 0;
398 } 398 }
411 ls = cycle->listening.elts; 411 ls = cycle->listening.elts;
412 for (i = 0; i < cycle->listening.nelts; i++) { 412 for (i = 0; i < cycle->listening.nelts; i++) {
413 413
414 c = ls[i].connection; 414 c = ls[i].connection;
415 415
416 if (c->read->active) { 416 if (c == NULL || c->read->active) {
417 continue; 417 continue;
418 } 418 }
419 419
420 if (ngx_add_event(c->read, NGX_READ_EVENT, 0) == NGX_ERROR) { 420 if (ngx_add_event(c->read, NGX_READ_EVENT, 0) == NGX_ERROR) {
421 return NGX_ERROR; 421 return NGX_ERROR;
425 return NGX_OK; 425 return NGX_OK;
426 } 426 }
427 427
428 428
429 static ngx_int_t 429 static ngx_int_t
430 ngx_disable_accept_events(ngx_cycle_t *cycle) 430 ngx_disable_accept_events(ngx_cycle_t *cycle, ngx_uint_t all)
431 { 431 {
432 ngx_uint_t i; 432 ngx_uint_t i;
433 ngx_listening_t *ls; 433 ngx_listening_t *ls;
434 ngx_connection_t *c; 434 ngx_connection_t *c;
435 435
436 ls = cycle->listening.elts; 436 ls = cycle->listening.elts;
437 for (i = 0; i < cycle->listening.nelts; i++) { 437 for (i = 0; i < cycle->listening.nelts; i++) {
438 438
439 c = ls[i].connection; 439 c = ls[i].connection;
440 440
441 if (!c->read->active) { 441 if (c == NULL || !c->read->active) {
442 continue; 442 continue;
443 } 443 }
444
445 #if (NGX_HAVE_REUSEPORT)
446
447 /*
448 * do not disable accept on worker's own sockets
449 * when disabling accept events due to accept mutex
450 */
451
452 if (ls[i].reuseport && !all) {
453 continue;
454 }
455
456 #endif
444 457
445 if (ngx_del_event(c->read, NGX_READ_EVENT, NGX_DISABLE_EVENT) 458 if (ngx_del_event(c->read, NGX_READ_EVENT, NGX_DISABLE_EVENT)
446 == NGX_ERROR) 459 == NGX_ERROR)
447 { 460 {
448 return NGX_ERROR; 461 return NGX_ERROR;