Fixed crash that occurs when idle connections are closed forcibly.
This commit is contained in:
@@ -24,8 +24,10 @@ static void nxt_conn_listen_handler(nxt_task_t *task, void *obj,
|
||||
void *data);
|
||||
static nxt_conn_t *nxt_conn_accept_next(nxt_task_t *task,
|
||||
nxt_listen_event_t *lev);
|
||||
static nxt_int_t nxt_conn_accept_close_idle(nxt_task_t *task,
|
||||
static void nxt_conn_accept_close_idle(nxt_task_t *task,
|
||||
nxt_listen_event_t *lev);
|
||||
static void nxt_conn_accept_close_idle_handler(nxt_task_t *task, void *obj,
|
||||
void *data);
|
||||
static void nxt_conn_listen_event_error(nxt_task_t *task, void *obj,
|
||||
void *data);
|
||||
static void nxt_conn_listen_timer_handler(nxt_task_t *task, void *obj,
|
||||
@@ -230,60 +232,76 @@ nxt_conn_accept_next(nxt_task_t *task, nxt_listen_event_t *lev)
|
||||
|
||||
lev->next = NULL;
|
||||
|
||||
do {
|
||||
c = nxt_conn_accept_alloc(task, lev);
|
||||
c = nxt_conn_accept_alloc(task, lev);
|
||||
|
||||
if (nxt_fast_path(c != NULL)) {
|
||||
return c;
|
||||
}
|
||||
if (nxt_slow_path(c == NULL)) {
|
||||
nxt_conn_accept_close_idle(task, lev);
|
||||
}
|
||||
|
||||
} while (nxt_conn_accept_close_idle(task, lev) == NXT_OK);
|
||||
|
||||
nxt_alert(task, "no available connections, "
|
||||
"new connections are not accepted within 1s");
|
||||
|
||||
return NULL;
|
||||
return c;
|
||||
}
|
||||
|
||||
|
||||
static nxt_int_t
|
||||
static void
|
||||
nxt_conn_accept_close_idle(nxt_task_t *task, nxt_listen_event_t *lev)
|
||||
{
|
||||
nxt_event_engine_t *engine;
|
||||
|
||||
engine = task->thread->engine;
|
||||
|
||||
nxt_work_queue_add(&engine->close_work_queue,
|
||||
nxt_conn_accept_close_idle_handler, task, NULL, NULL);
|
||||
|
||||
nxt_timer_add(engine, &lev->timer, 100);
|
||||
|
||||
nxt_fd_event_disable_read(engine, &lev->socket);
|
||||
|
||||
nxt_alert(task, "new connections are not accepted within 100ms");
|
||||
}
|
||||
|
||||
|
||||
static void
|
||||
nxt_conn_accept_close_idle_handler(nxt_task_t *task, void *obj, void *data)
|
||||
{
|
||||
nxt_uint_t times;
|
||||
nxt_conn_t *c;
|
||||
nxt_queue_t *idle;
|
||||
nxt_queue_link_t *link;
|
||||
nxt_queue_link_t *link, *next;
|
||||
nxt_event_engine_t *engine;
|
||||
|
||||
static nxt_log_moderation_t nxt_idle_close_log_moderation = {
|
||||
NXT_LOG_INFO, 2, "idle connections closed", NXT_LOG_MODERATION
|
||||
};
|
||||
|
||||
times = 10;
|
||||
engine = task->thread->engine;
|
||||
|
||||
idle = &engine->idle_connections;
|
||||
|
||||
for (link = nxt_queue_last(idle);
|
||||
link != nxt_queue_head(idle);
|
||||
link = nxt_queue_next(link))
|
||||
link = next)
|
||||
{
|
||||
next = nxt_queue_next(link);
|
||||
|
||||
c = nxt_queue_link_data(link, nxt_conn_t, link);
|
||||
|
||||
nxt_debug(c->socket.task, "idle connection: %d rdy:%d",
|
||||
c->socket.fd, c->socket.read_ready);
|
||||
|
||||
if (!c->socket.read_ready) {
|
||||
nxt_log_moderate(&nxt_idle_close_log_moderation, NXT_LOG_INFO,
|
||||
task->log, "no available connections, "
|
||||
"close idle connection");
|
||||
nxt_queue_remove(link);
|
||||
nxt_conn_close(engine, c);
|
||||
|
||||
return NXT_OK;
|
||||
c->read_state->close_handler(c->socket.task, c, c->socket.data);
|
||||
|
||||
times--;
|
||||
|
||||
if (times == 0) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
nxt_timer_add(engine, &lev->timer, 1000);
|
||||
|
||||
nxt_fd_event_disable_read(engine, &lev->socket);
|
||||
|
||||
return NXT_DECLINED;
|
||||
}
|
||||
|
||||
|
||||
@@ -313,12 +331,10 @@ nxt_conn_accept_error(nxt_task_t *task, nxt_listen_event_t *lev,
|
||||
case ENFILE:
|
||||
case ENOBUFS:
|
||||
case ENOMEM:
|
||||
if (nxt_conn_accept_close_idle(task, lev) != NXT_OK) {
|
||||
nxt_alert(task, "%s(%d) failed %E, "
|
||||
"new connections are not accepted within 1s",
|
||||
accept_syscall, lev->socket.fd, err);
|
||||
}
|
||||
nxt_alert(task, "%s(%d) failed %E",
|
||||
accept_syscall, lev->socket.fd, err);
|
||||
|
||||
nxt_conn_accept_close_idle(task, lev);
|
||||
return;
|
||||
|
||||
default:
|
||||
|
||||
Reference in New Issue
Block a user