Skip to content

Commit f85f286

Browse files
committed
bugfix: Semaphore not cleaned up on request timeout
After a ngx.semaphore.wait() call, if the current request is terminated by Nginx due to client_header_timeout or client_body_timeout, the corresponding post() is never executed. As a result, all subsequent attempts to wait() on the same semaphore hang until they time out, because the semaphore count was never restored. openresty#2422
1 parent 1f4d846 commit f85f286

File tree

2 files changed

+90
-3
lines changed

2 files changed

+90
-3
lines changed

src/ngx_http_lua_semaphore.c

Lines changed: 85 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,3 @@
1-
21
/*
32
* Copyright (C) Yichun Zhang (agentzh)
43
* Copyright (C) cuiweixie
@@ -26,10 +25,16 @@ static void ngx_http_lua_free_sema(ngx_http_lua_sema_t *sem);
2625
static ngx_int_t ngx_http_lua_sema_resume(ngx_http_request_t *r);
2726
int ngx_http_lua_ffi_sema_new(ngx_http_lua_sema_t **psem,
2827
int n, char **errmsg);
29-
int ngx_http_lua_ffi_sema_post(ngx_http_lua_sema_t *sem, int n);
28+
int ngx_http_lua_ffi_sema_post(ngx_http_request_t *r, ngx_http_lua_sema_t *sem,
29+
int n);
3030
int ngx_http_lua_ffi_sema_wait(ngx_http_request_t *r,
3131
ngx_http_lua_sema_t *sem, int wait_ms, u_char *err, size_t *errlen);
3232
static void ngx_http_lua_sema_cleanup(void *data);
33+
static void ngx_http_lua_sema_abort_cleanup(void *data);
34+
static void ngx_http_lua_sema_add_abort_cleanup(ngx_http_request_t *r,
35+
ngx_http_lua_ctx_t *ctx, ngx_http_lua_sema_t *sem);
36+
static void ngx_http_lua_sema_del_abort_cleanup(ngx_http_request_t *r,
37+
ngx_http_lua_sema_t *sem);
3338
static void ngx_http_lua_sema_handler(ngx_event_t *ev);
3439
static void ngx_http_lua_sema_timeout_handler(ngx_event_t *ev);
3540
void ngx_http_lua_ffi_sema_gc(ngx_http_lua_sema_t *sem);
@@ -334,7 +339,8 @@ ngx_http_lua_ffi_sema_new(ngx_http_lua_sema_t **psem,
334339

335340

336341
int
337-
ngx_http_lua_ffi_sema_post(ngx_http_lua_sema_t *sem, int n)
342+
ngx_http_lua_ffi_sema_post(ngx_http_request_t *r, ngx_http_lua_sema_t *sem,
343+
int n)
338344
{
339345
ngx_log_debug3(NGX_LOG_DEBUG_HTTP, ngx_cycle->log, 0,
340346
"http lua semaphore post: %p, n: %d, resources: %d",
@@ -350,6 +356,8 @@ ngx_http_lua_ffi_sema_post(ngx_http_lua_sema_t *sem, int n)
350356
ngx_post_event((&sem->sem_event), &ngx_posted_events);
351357
}
352358

359+
ngx_http_lua_sema_del_abort_cleanup(r, sem);
360+
353361
return NGX_OK;
354362
}
355363

@@ -392,6 +400,7 @@ ngx_http_lua_ffi_sema_wait(ngx_http_request_t *r,
392400

393401
if (ngx_queue_empty(&sem->wait_queue) && sem->resource_count > 0) {
394402
sem->resource_count--;
403+
ngx_http_lua_sema_add_abort_cleanup(r, ctx, sem);
395404
return NGX_OK;
396405
}
397406

@@ -454,6 +463,78 @@ ngx_http_lua_sema_cleanup(void *data)
454463
}
455464

456465

466+
static void
467+
ngx_http_lua_sema_abort_cleanup(void *data)
468+
{
469+
ngx_http_lua_sema_ctx_t *sema_ctx = data;
470+
ngx_http_lua_sema_t *sem;
471+
472+
sem = sema_ctx->sem;
473+
474+
if (sem) {
475+
sem->resource_count += 1;
476+
477+
if (!ngx_queue_empty(&sem->wait_queue)) {
478+
ngx_post_event((&sem->sem_event), &ngx_posted_events);
479+
}
480+
}
481+
}
482+
483+
484+
static void
485+
ngx_http_lua_sema_add_abort_cleanup(ngx_http_request_t *r,
486+
ngx_http_lua_ctx_t *ctx, ngx_http_lua_sema_t *sem)
487+
{
488+
ngx_http_cleanup_t *cln;
489+
ngx_http_lua_sema_ctx_t *sema_ctx;
490+
491+
cln = ngx_http_lua_cleanup_add(r, sizeof(ngx_http_lua_sema_ctx_t));
492+
if (cln == NULL) {
493+
ngx_log_error(NGX_LOG_ERR, r->connection->log, 0,
494+
"ngx_http_lua_sema_add_abort_cleanup failed to add cleanup");
495+
return;
496+
}
497+
498+
cln->handler = ngx_http_lua_sema_abort_cleanup;
499+
sema_ctx = cln->data;
500+
sema_ctx->sem = sem;
501+
}
502+
503+
504+
static void
505+
ngx_http_lua_sema_del_abort_cleanup(ngx_http_request_t *r,
506+
ngx_http_lua_sema_t *sem)
507+
{
508+
ngx_http_cleanup_t **last, *cln;
509+
ngx_http_lua_ctx_t *ctx;
510+
ngx_http_lua_sema_ctx_t *sema_ctx;
511+
512+
ctx = ngx_http_get_module_ctx(r, ngx_http_lua_module);
513+
if (ctx == NULL) {
514+
return;
515+
}
516+
517+
r = r->main;
518+
519+
last = &r->cleanup;
520+
521+
while (*last) {
522+
if ((*last)->handler == ngx_http_lua_sema_abort_cleanup) {
523+
sema_ctx = (*last)->data;
524+
if (sema_ctx->sem == sem) {
525+
cln = *last;
526+
*last = cln->next;
527+
528+
sema_ctx->sem = NULL;
529+
return;
530+
}
531+
}
532+
533+
last = &(*last)->next;
534+
}
535+
}
536+
537+
457538
static void
458539
ngx_http_lua_sema_handler(ngx_event_t *ev)
459540
{
@@ -492,6 +573,7 @@ ngx_http_lua_sema_handler(ngx_event_t *ev)
492573
sem->resource_count--;
493574

494575
ctx->cur_co_ctx = wait_co_ctx;
576+
ngx_http_lua_sema_add_abort_cleanup(r, ctx, sem);
495577

496578
wait_co_ctx->sem_resume_status = SEMAPHORE_WAIT_SUCC;
497579

src/ngx_http_lua_semaphore.h

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -41,6 +41,11 @@ typedef struct ngx_http_lua_sema_s {
4141
} ngx_http_lua_sema_t;
4242

4343

44+
typedef struct ngx_http_lua_sema_ctx_s {
45+
ngx_http_lua_sema_t *sem;
46+
} ngx_http_lua_sema_ctx_t;
47+
48+
4449
void ngx_http_lua_sema_mm_cleanup(void *data);
4550
ngx_int_t ngx_http_lua_sema_mm_init(ngx_conf_t *cf,
4651
ngx_http_lua_main_conf_t *lmcf);

0 commit comments

Comments
 (0)