From 92a19a19dd87f7dfeaf7aaf893099d0afd4a182f Mon Sep 17 00:00:00 2001 From: Ben Noordhuis Date: Fri, 28 Dec 2012 15:10:04 +0100 Subject: [PATCH] unix: ensure done_cb gets called after uv_cancel() Wake up the event loop with uv_async_send() when a request is cancelled. Ensures the done_cb is run on the next tick of the event loop. Not sending a wakeup signal results in the done_cb not getting called until another request completes, which may be a long time coming when it's the only request in the queue or when other requests are executing long-running jobs. Fixes #669. --- src/unix/threadpool.c | 1 + test/test-list.h | 2 ++ test/test-threadpool-cancel.c | 41 +++++++++++++++++++++++++++++++++++ 3 files changed, 44 insertions(+) diff --git a/src/unix/threadpool.c b/src/unix/threadpool.c index ee428201..6139549a 100644 --- a/src/unix/threadpool.c +++ b/src/unix/threadpool.c @@ -158,6 +158,7 @@ int uv__work_cancel(uv_loop_t* loop, uv_req_t* req, struct uv__work* w) { w->work = uv__cancelled; uv_mutex_lock(&loop->wq_mutex); ngx_queue_insert_tail(&loop->wq, &w->wq); + uv_async_send(&loop->wq_async); uv_mutex_unlock(&loop->wq_mutex); return 0; diff --git a/test/test-list.h b/test/test-list.h index 45c4b6c7..ab9ce7dd 100644 --- a/test/test-list.h +++ b/test/test-list.h @@ -193,6 +193,7 @@ TEST_DECLARE (threadpool_multiple_event_loops) TEST_DECLARE (threadpool_cancel_getaddrinfo) TEST_DECLARE (threadpool_cancel_work) TEST_DECLARE (threadpool_cancel_fs) +TEST_DECLARE (threadpool_cancel_single) TEST_DECLARE (thread_mutex) TEST_DECLARE (thread_rwlock) TEST_DECLARE (thread_create) @@ -468,6 +469,7 @@ TASK_LIST_START TEST_ENTRY (threadpool_cancel_getaddrinfo) TEST_ENTRY (threadpool_cancel_work) TEST_ENTRY (threadpool_cancel_fs) + TEST_ENTRY (threadpool_cancel_single) TEST_ENTRY (thread_mutex) TEST_ENTRY (thread_rwlock) TEST_ENTRY (thread_create) diff --git a/test/test-threadpool-cancel.c b/test/test-threadpool-cancel.c index db0397af..970e9fee 100644 --- a/test/test-threadpool-cancel.c +++ b/test/test-threadpool-cancel.c @@ -156,6 +156,15 @@ static void timer_cb(uv_timer_t* handle, int status) { } +static void nop_work_cb(uv_work_t* req) { +} + + +static void nop_done_cb(uv_work_t* req, int status) { + req->data = "OK"; +} + + TEST_IMPL(threadpool_cancel_getaddrinfo) { uv_getaddrinfo_t reqs[4]; struct cancel_info ci; @@ -264,3 +273,35 @@ TEST_IMPL(threadpool_cancel_fs) { return 0; } + + +TEST_IMPL(threadpool_cancel_single) { + uv_loop_t* loop; + uv_work_t req; + int cancelled; + int i; + + loop = uv_default_loop(); + for (i = 0; i < 5000; i++) { + req.data = NULL; + ASSERT(0 == uv_queue_work(loop, &req, nop_work_cb, nop_done_cb)); + + cancelled = uv_cancel((uv_req_t*) &req); + if (cancelled == 0) + break; + + ASSERT(0 == uv_run(loop)); + } + + if (cancelled != 0) { + fputs("Failed to cancel a work req in 5,000 iterations, giving up.\n", + stderr); + return 1; + } + + ASSERT(req.data == NULL); + ASSERT(0 == uv_run(loop)); + ASSERT(req.data != NULL); /* Should have been updated by nop_done_cb(). */ + + return 0; +}