Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with
or
.
Download ZIP
Browse files

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.
  • Loading branch information...
commit 92a19a19dd87f7dfeaf7aaf893099d0afd4a182f 1 parent 9614d51
@bnoordhuis bnoordhuis authored
View
1  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;
View
2  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)
View
41 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;
+}
Please sign in to comment.
Something went wrong with that request. Please try again.