diff --git a/src/lib/core/coio_task.c b/src/lib/core/coio_task.c index d8095eef3eabf8ec5d36b0eb753171725c3721f1..908b336ed15e1430570308853769dfc3d8f27b65 100644 --- a/src/lib/core/coio_task.c +++ b/src/lib/core/coio_task.c @@ -227,22 +227,22 @@ coio_task_destroy(struct coio_task *task) diag_destroy(&task->diag); } +void +coio_task_post(struct coio_task *task) +{ + assert(task->base.type == EIO_CUSTOM); + assert(task->fiber == fiber()); + eio_submit(&task->base); + task->fiber = NULL; +} + int -coio_task_post(struct coio_task *task, double timeout) +coio_task_execute(struct coio_task *task, double timeout) { assert(task->base.type == EIO_CUSTOM); assert(task->fiber == fiber()); eio_submit(&task->base); - if (timeout == 0) { - /* - * This is a special case: - * we don't wait any response from the task - * and just perform just asynchronous post. - */ - task->fiber = NULL; - return 0; - } fiber_yield_timeout(timeout); if (!task->complete) { /* timed out or cancelled. */ @@ -409,7 +409,7 @@ coio_getaddrinfo(const char *host, const char *port, } /* Post coio task */ - if (coio_task_post(&task->base, timeout) != 0) + if (coio_task_execute(&task->base, timeout) != 0) return -1; /* timed out or cancelled */ /* Task finished */ diff --git a/src/lib/core/coio_task.h b/src/lib/core/coio_task.h index bb981f0b0998d0975fe1bc6f8e42efc9ce6f2d79..e81e10ccafaf5d8e754a788648a475d11d930600 100644 --- a/src/lib/core/coio_task.h +++ b/src/lib/core/coio_task.h @@ -63,7 +63,11 @@ typedef int (*coio_task_cb)(struct coio_task *task); /* like eio_req */ */ struct coio_task { struct eio_req base; /* eio_task - must be first */ - /** The calling fiber. */ + /** + * The calling fiber. When set to NULL, the task is + * detached - its resources are freed eventually, and such + * a task should not be accessed after detachment. + */ struct fiber *fiber; /** Callbacks. */ union { @@ -102,7 +106,7 @@ void coio_task_destroy(struct coio_task *task); /** - * Post coio task to EIO thread pool. + * Execute a coio task in a worker thread. * * @param task coio task. * @param timeout timeout in seconds. @@ -114,7 +118,14 @@ coio_task_destroy(struct coio_task *task); * callback. */ int -coio_task_post(struct coio_task *task, double timeout); +coio_task_execute(struct coio_task *task, double timeout); + +/** + * Post a task in detached state. Its result can't be obtained, + * and destructor is called after completion. + */ +void +coio_task_post(struct coio_task *task); /** \cond public */ diff --git a/src/lib/core/say.c b/src/lib/core/say.c index 24963cf82cb695e09b3da6b6371146288dab24a8..0b2cf2c34b322a9c0a915f7b0e27570ef7506bc3 100644 --- a/src/lib/core/say.c +++ b/src/lib/core/say.c @@ -343,7 +343,7 @@ say_logrotate(struct ev_loop *loop, struct ev_signal *w, int revents) coio_task_create(&task->base, logrotate_cb, logrotate_cleanup_cb); task->log = log; task->loop = loop(); - coio_task_post(&task->base, 0); + coio_task_post(&task->base); } errno = saved_errno; } diff --git a/test/unit/coio.cc b/test/unit/coio.cc index 5fb5a26d51c334e56261b009fb1e323c4c9e5110..bb8bd713120041475755b6e30e5a1701b8ed83a0 100644 --- a/test/unit/coio.cc +++ b/test/unit/coio.cc @@ -80,6 +80,24 @@ test_getaddrinfo(void) int rc = coio_getaddrinfo(host, port, NULL, &i, 1); is(rc, 0, "getaddrinfo"); freeaddrinfo(i); + + /* + * gh-4209: 0 timeout should not be a special value and + * detach a task. Before a fix it led to segfault + * sometimes. The cycle below runs getaddrinfo multiple + * times to increase segfault probability. + */ + for (int j = 0; j < 5; ++j) { + if (coio_getaddrinfo(host, port, NULL, &i, 0) == 0 && i != NULL) + freeaddrinfo(i); + /* + * Skip one event loop to check, that the coio + * task destructor will not free the memory second + * time. + */ + fiber_sleep(0); + } + check_plan(); footer(); }