|
16 | 16 | // |
17 | 17 | // |
18 | 18 |
|
| 19 | +#include <grpc/support/port_platform.h> |
| 20 | + |
| 21 | +#include <utility> |
| 22 | + |
| 23 | +#include <grpc/support/atm.h> |
| 24 | + |
19 | 25 | // FIXME: "posix" files shouldn't be depending on _GNU_SOURCE |
20 | 26 | #ifndef _GNU_SOURCE |
21 | 27 | #define _GNU_SOURCE |
22 | 28 | #endif |
23 | 29 |
|
24 | | -#include <grpc/support/port_platform.h> |
25 | | - |
26 | 30 | #include "src/core/lib/iomgr/port.h" |
27 | 31 |
|
28 | 32 | #ifdef GRPC_POSIX_SOCKET_TCP_SERVER |
|
45 | 49 |
|
46 | 50 | #include <grpc/byte_buffer.h> |
47 | 51 | #include <grpc/event_engine/endpoint_config.h> |
| 52 | +#include <grpc/event_engine/event_engine.h> |
48 | 53 | #include <grpc/support/alloc.h> |
49 | 54 | #include <grpc/support/log.h> |
50 | 55 | #include <grpc/support/sync.h> |
|
74 | 79 | #include "src/core/lib/transport/error_utils.h" |
75 | 80 |
|
76 | 81 | static std::atomic<int64_t> num_dropped_connections{0}; |
| 82 | +static constexpr grpc_core::Duration kRetryAcceptWaitTime{ |
| 83 | + grpc_core::Duration::Seconds(1)}; |
77 | 84 |
|
78 | 85 | using ::grpc_event_engine::experimental::EndpointConfig; |
79 | 86 | using ::grpc_event_engine::experimental::EventEngine; |
@@ -350,22 +357,38 @@ static void on_read(void* arg, grpc_error_handle err) { |
350 | 357 | if (fd < 0) { |
351 | 358 | if (errno == EINTR) { |
352 | 359 | continue; |
353 | | - } else if (errno == EAGAIN || errno == ECONNABORTED || |
354 | | - errno == EWOULDBLOCK) { |
| 360 | + } |
| 361 | + // When the process runs out of fds, accept4() returns EMFILE. When this |
| 362 | + // happens, the connection is left in the accept queue until either a |
| 363 | + // read event triggers the on_read callback, or time has passed and the |
| 364 | + // accept should be re-tried regardless. This callback is not cancelled, |
| 365 | + // so a spurious wakeup may occur even when there's nothing to accept. |
| 366 | + // This is not a performant code path, but if an fd limit has been |
| 367 | + // reached, the system is likely in an unhappy state regardless. |
| 368 | + if (errno == EMFILE) { |
| 369 | + GRPC_LOG_EVERY_N_SEC(1, "%s", |
| 370 | + "File descriptor limit reached. Retrying."); |
| 371 | + grpc_fd_notify_on_read(sp->emfd, &sp->read_closure); |
| 372 | + if (gpr_atm_full_xchg(&sp->retry_timer_armed, true)) return; |
| 373 | + grpc_timer_init(&sp->retry_timer, |
| 374 | + grpc_core::Timestamp::Now() + kRetryAcceptWaitTime, |
| 375 | + &sp->retry_closure); |
| 376 | + return; |
| 377 | + } |
| 378 | + if (errno == EAGAIN || errno == ECONNABORTED || errno == EWOULDBLOCK) { |
355 | 379 | grpc_fd_notify_on_read(sp->emfd, &sp->read_closure); |
356 | 380 | return; |
| 381 | + } |
| 382 | + gpr_mu_lock(&sp->server->mu); |
| 383 | + if (!sp->server->shutdown_listeners) { |
| 384 | + gpr_log(GPR_ERROR, "Failed accept4: %s", |
| 385 | + grpc_core::StrError(errno).c_str()); |
357 | 386 | } else { |
358 | | - gpr_mu_lock(&sp->server->mu); |
359 | | - if (!sp->server->shutdown_listeners) { |
360 | | - gpr_log(GPR_ERROR, "Failed accept4: %s", |
361 | | - grpc_core::StrError(errno).c_str()); |
362 | | - } else { |
363 | | - // if we have shutdown listeners, accept4 could fail, and we |
364 | | - // needn't notify users |
365 | | - } |
366 | | - gpr_mu_unlock(&sp->server->mu); |
367 | | - goto error; |
| 387 | + // if we have shutdown listeners, accept4 could fail, and we |
| 388 | + // needn't notify users |
368 | 389 | } |
| 390 | + gpr_mu_unlock(&sp->server->mu); |
| 391 | + goto error; |
369 | 392 | } |
370 | 393 |
|
371 | 394 | if (sp->server->memory_quota->IsMemoryPressureHigh()) { |
@@ -558,6 +581,7 @@ static grpc_error_handle clone_port(grpc_tcp_listener* listener, |
558 | 581 | sp->port_index = listener->port_index; |
559 | 582 | sp->fd_index = listener->fd_index + count - i; |
560 | 583 | GPR_ASSERT(sp->emfd); |
| 584 | + grpc_tcp_server_listener_initialize_retry_timer(sp); |
561 | 585 | while (listener->server->tail->next != nullptr) { |
562 | 586 | listener->server->tail = listener->server->tail->next; |
563 | 587 | } |
@@ -791,6 +815,7 @@ static void tcp_server_shutdown_listeners(grpc_tcp_server* s) { |
791 | 815 | if (s->active_ports) { |
792 | 816 | grpc_tcp_listener* sp; |
793 | 817 | for (sp = s->head; sp; sp = sp->next) { |
| 818 | + grpc_timer_cancel(&sp->retry_timer); |
794 | 819 | grpc_fd_shutdown(sp->emfd, GRPC_ERROR_CREATE("Server shutdown")); |
795 | 820 | } |
796 | 821 | } |
|
0 commit comments