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.
This commit is contained in:
parent
9614d51135
commit
92a19a19dd
@ -158,6 +158,7 @@ int uv__work_cancel(uv_loop_t* loop, uv_req_t* req, struct uv__work* w) {
|
|||||||
w->work = uv__cancelled;
|
w->work = uv__cancelled;
|
||||||
uv_mutex_lock(&loop->wq_mutex);
|
uv_mutex_lock(&loop->wq_mutex);
|
||||||
ngx_queue_insert_tail(&loop->wq, &w->wq);
|
ngx_queue_insert_tail(&loop->wq, &w->wq);
|
||||||
|
uv_async_send(&loop->wq_async);
|
||||||
uv_mutex_unlock(&loop->wq_mutex);
|
uv_mutex_unlock(&loop->wq_mutex);
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
|
|||||||
@ -193,6 +193,7 @@ TEST_DECLARE (threadpool_multiple_event_loops)
|
|||||||
TEST_DECLARE (threadpool_cancel_getaddrinfo)
|
TEST_DECLARE (threadpool_cancel_getaddrinfo)
|
||||||
TEST_DECLARE (threadpool_cancel_work)
|
TEST_DECLARE (threadpool_cancel_work)
|
||||||
TEST_DECLARE (threadpool_cancel_fs)
|
TEST_DECLARE (threadpool_cancel_fs)
|
||||||
|
TEST_DECLARE (threadpool_cancel_single)
|
||||||
TEST_DECLARE (thread_mutex)
|
TEST_DECLARE (thread_mutex)
|
||||||
TEST_DECLARE (thread_rwlock)
|
TEST_DECLARE (thread_rwlock)
|
||||||
TEST_DECLARE (thread_create)
|
TEST_DECLARE (thread_create)
|
||||||
@ -468,6 +469,7 @@ TASK_LIST_START
|
|||||||
TEST_ENTRY (threadpool_cancel_getaddrinfo)
|
TEST_ENTRY (threadpool_cancel_getaddrinfo)
|
||||||
TEST_ENTRY (threadpool_cancel_work)
|
TEST_ENTRY (threadpool_cancel_work)
|
||||||
TEST_ENTRY (threadpool_cancel_fs)
|
TEST_ENTRY (threadpool_cancel_fs)
|
||||||
|
TEST_ENTRY (threadpool_cancel_single)
|
||||||
TEST_ENTRY (thread_mutex)
|
TEST_ENTRY (thread_mutex)
|
||||||
TEST_ENTRY (thread_rwlock)
|
TEST_ENTRY (thread_rwlock)
|
||||||
TEST_ENTRY (thread_create)
|
TEST_ENTRY (thread_create)
|
||||||
|
|||||||
@ -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) {
|
TEST_IMPL(threadpool_cancel_getaddrinfo) {
|
||||||
uv_getaddrinfo_t reqs[4];
|
uv_getaddrinfo_t reqs[4];
|
||||||
struct cancel_info ci;
|
struct cancel_info ci;
|
||||||
@ -264,3 +273,35 @@ TEST_IMPL(threadpool_cancel_fs) {
|
|||||||
|
|
||||||
return 0;
|
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;
|
||||||
|
}
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user