}
}
-static void
+static isc_result_t
readline_next_command(void *arg) {
char *ptr = NULL;
ptr = readline("> ");
isc_loopmgr_nonblocking();
if (ptr == NULL) {
- return;
+ return ISC_R_SUCCESS;
}
if (*ptr != 0) {
cmdline = cmdlinebuf;
}
free(ptr);
+
+ return ISC_R_SUCCESS;
}
-static void
+static isc_result_t
fgets_next_command(void *arg) {
UNUSED(arg);
cmdline = fgets(cmdlinebuf, COMMSIZE, stdin);
+
+ return ISC_R_SUCCESS;
}
ISC_NORETURN static void
bool updatepending; /* there is an update pending */
bool updaterunning; /* there is an update running */
- isc_result_t updateresult; /* result from the offloaded work */
dns_db_t *db; /* zones database */
dns_dbversion_t *dbversion; /* version we will be updating to */
dns_db_t *updb; /* zones database we're working on */
static void
dns__catz_timer_stop(void *arg);
-static void
+static isc_result_t
dns__catz_update_cb(void *data);
static void
dns__catz_done_cb(void *data, isc_result_t result);
catz->updatepending = false;
catz->updaterunning = true;
- catz->updateresult = ISC_R_UNSET;
dns_name_format(&catz->name, domain, DNS_NAME_FORMATSIZE);
"catz: %s: no longer active, reload is canceled",
domain);
catz->updaterunning = false;
- catz->updateresult = ISC_R_CANCELED;
goto exit;
}
* It creates a new catz, iterates over database to fill it with content, and
* then merges new catz into old catz.
*/
-static void
+static isc_result_t
dns__catz_update_cb(void *data) {
dns_catz_zone_t *catz = (dns_catz_zone_t *)data;
dns_db_t *updb = NULL;
catzs = catz->catzs;
if (atomic_load(&catzs->shuttingdown)) {
- result = ISC_R_SHUTTINGDOWN;
- goto exit;
+ return ISC_R_SHUTTINGDOWN;
}
dns_name_format(&updb->origin, bname, DNS_NAME_FORMATSIZE);
LOCK(&catzs->lock);
if (catzs->zones == NULL) {
UNLOCK(&catzs->lock);
- result = ISC_R_SHUTTINGDOWN;
- goto exit;
+ return ISC_R_SHUTTINGDOWN;
}
result = isc_ht_find(catzs->zones, r.base, r.length, (void **)&oldcatz);
is_active = (result == ISC_R_SUCCESS && oldcatz->active);
isc_log_write(DNS_LOGCATEGORY_GENERAL, DNS_LOGMODULE_CATZ,
ISC_LOG_ERROR, "catz: zone '%s' not in config",
bname);
- goto exit;
+ return result;
}
if (!is_active) {
isc_log_write(DNS_LOGCATEGORY_GENERAL, DNS_LOGMODULE_CATZ,
ISC_LOG_INFO,
"catz: zone '%s' is no longer active", bname);
- result = ISC_R_CANCELED;
- goto exit;
+ return ISC_R_CANCELED;
}
result = dns_db_getsoaserial(updb, oldcatz->updbversion, &vers);
ISC_LOG_ERROR,
"catz: zone '%s' has no SOA record (%s)", bname,
isc_result_totext(result));
- goto exit;
+ return result;
}
isc_log_write(DNS_LOGCATEGORY_GENERAL, DNS_LOGMODULE_CATZ, ISC_LOG_INFO,
ISC_LOG_ERROR,
"catz: failed to create DB iterator - %s",
isc_result_totext(result));
- goto exit;
+ return result;
}
name = dns_fixedname_initname(&fixname);
ISC_LOG_ERROR,
"catz: failed to create name from string - %s",
isc_result_totext(result));
- goto exit;
+ return result;
}
result = dns_dbiterator_seek(updbit, name);
"catz: zone '%s' has no 'version' record (%s) "
"and will not be processed",
bname, isc_result_totext(result));
- goto exit;
+
+ return result;
}
newcatz = dns_catz_zone_new(catzs, &updb->origin);
"will not be processed",
bname);
dns_catz_zone_detach(&newcatz);
- result = ISC_R_FAILURE;
- goto exit;
+ return ISC_R_FAILURE;
}
/*
ISC_LOG_ERROR, "catz: failed merging zones: %s",
isc_result_totext(result));
- goto exit;
+ return result;
}
isc_log_write(DNS_LOGCATEGORY_GENERAL, DNS_LOGMODULE_CATZ,
ISC_LOG_DEBUG(3),
"catz: update_from_db: new zone merged");
-exit:
- catz->updateresult = result;
+ return result;
}
static void
-dns__catz_done_cb(void *data, isc_result_t result ISC_ATTR_UNUSED) {
+dns__catz_done_cb(void *data, isc_result_t result) {
dns_catz_zone_t *catz = (dns_catz_zone_t *)data;
char dname[DNS_NAME_FORMATSIZE];
isc_log_write(DNS_LOGCATEGORY_GENERAL, DNS_LOGMODULE_CATZ, ISC_LOG_INFO,
"catz: %s: reload done: %s", dname,
- isc_result_totext(catz->updateresult));
+ isc_result_totext(result));
dns_catz_zone_unref(catz);
}
bool dbregistered; /* db callback notify is registered. */
bool updatepending; /* there is an update pending */
bool updaterunning; /* there is an update running */
- isc_result_t updateresult; /* result from the offloaded work */
dns_db_t *db; /* zones database */
dns_dbversion_t *dbversion; /* version we will be updating to */
dns_db_t *updb; /* zones database we're working on */
}
/*
- * The combination of isc_work_enqueue() on the current loop and callback on
- * lctx->loop ensures the correct ordering:
+ * The load runs on the SLOW work lane of lctx->loop:
*
- * 1. dns_master_loadfileasync() calls isc_work_enqueue() on the current loop.
- * 2. master_load() runs asynchronously and can finish before the entry point
- * returns; master_load_done() is queued on the current loop and cannot run
- * until the entry point returns.
- * 3. The entry point publishes *lctxp.
- * 4. master_load_done() runs on the current loop and hands off to lctx->loop.
- * 5. lctx->done() runs on lctx->loop asynchronously.
+ * 1. dns_master_loadfileasync() publishes *lctxp, then starts
+ * master_load_start() on lctx->loop with isc_async_run(). Publishing
+ * first ensures lctx->done() cannot observe *lctxp unset even when the
+ * caller runs on a different loop.
+ * 2. master_load_start() enqueues the work; isc_work_enqueue() must be
+ * called on the loop the work is bound to, hence the extra hop.
+ * 3. master_load() runs on the worker thread and its result is handed to
+ * master_load_done() on lctx->loop.
+ * 4. master_load_done() calls lctx->done() and drops the loop and lctx
+ * references.
*/
-static void
+static isc_result_t
master_load(void *arg) {
dns_loadctx_t *lctx = arg;
- lctx->result = (lctx->load)(lctx);
+ return (lctx->load)(lctx);
}
static void
-master_load_callback(void *arg) {
+master_load_done(void *arg, isc_result_t result) {
dns_loadctx_t *lctx = arg;
- (lctx->done)(lctx->done_arg, lctx->result);
+ (lctx->done)(lctx->done_arg, result);
isc_loop_detach(&lctx->loop);
dns_loadctx_detach(&lctx);
}
static void
-master_load_done(void *arg, isc_result_t result ISC_ATTR_UNUSED) {
+master_load_start(void *arg) {
dns_loadctx_t *lctx = arg;
- isc_async_run(lctx->loop, master_load_callback, lctx);
+ isc_work_enqueue(lctx->loop, ISC_WORKLANE_SLOW, master_load,
+ master_load_done, lctx);
}
isc_result_t
dns_loadctx_ref(lctx);
isc_loop_attach(loop, &lctx->loop);
- isc_work_enqueue(isc_loop(), ISC_WORKLANE_SLOW, master_load,
- master_load_done, lctx);
+ /* Publish *lctxp before the load can start (see master_load). */
*lctxp = lctx;
+ isc_async_run(loop, master_load_start, lctx);
+
return ISC_R_SUCCESS;
}
dns_dumpdonefunc_t done;
void *done_arg;
/* dns_master_dumpasync() */
- isc_result_t result;
char *file;
char *tmpfile;
dns_masterformat_t format;
}
/*
- * The combination of isc_work_enqueue() on the current loop and callback on
- * dctx->loop ensures the correct ordering:
+ * The dump runs on the SLOW work lane of dctx->loop:
*
- * 1. dns_master_dumptostreamasync() (or dns_master_dumpasync()) calls
- * isc_work_enqueue() on the current loop.
- * 2. master_dump() runs asynchronously and can finish before the entry point
- * returns; master_dump_done() is queued on the current loop and cannot run
- * until the entry point returns.
- * 3. The entry point publishes *dctxp.
- * 4. master_dump_done() runs on the current loop and hands off to dctx->loop.
- * 5. dctx->done() runs on dctx->loop asynchronously.
+ * 1. dns_master_dumptostreamasync() (or dns_master_dumpasync()) publishes
+ * *dctxp, then starts master_dump_start() on dctx->loop with
+ * isc_async_run(). Publishing first ensures dctx->done() cannot observe
+ * *dctxp unset even when the caller runs on a different loop.
+ * 2. master_dump_start() enqueues the work; isc_work_enqueue() must be
+ * called on the loop the work is bound to, hence the extra hop.
+ * 3. master_dump() runs on the worker thread and its result is handed to
+ * master_dump_done() on dctx->loop.
+ * 4. master_dump_done() calls dctx->done() and drops the loop and dctx
+ * references.
*/
-static void
+static isc_result_t
master_dump(void *data) {
isc_result_t result = ISC_R_UNSET;
dns_dumpctx_t *dctx = data;
result = flushandsync(dctx->f, result, NULL);
}
- dctx->result = result;
+ return result;
}
static void
-master_dump_callback(void *data) {
+master_dump_done(void *data, isc_result_t result) {
dns_dumpctx_t *dctx = data;
- (dctx->done)(dctx->done_arg, dctx->result);
+ (dctx->done)(dctx->done_arg, result);
isc_loop_detach(&dctx->loop);
dns_dumpctx_detach(&dctx);
}
static void
-master_dump_done(void *data, isc_result_t result ISC_ATTR_UNUSED) {
+master_dump_start(void *data) {
dns_dumpctx_t *dctx = data;
- isc_async_run(dctx->loop, master_dump_callback, dctx);
+ isc_work_enqueue(dctx->loop, ISC_WORKLANE_SLOW, master_dump,
+ master_dump_done, dctx);
}
static isc_result_t
dns_dumpctx_ref(dctx);
isc_loop_attach(loop, &dctx->loop);
- isc_work_enqueue(isc_loop(), ISC_WORKLANE_SLOW, master_dump,
- master_dump_done, dctx);
+ /* Publish *dctxp before the dump can start (see master_dump). */
*dctxp = dctx;
+ isc_async_run(loop, master_dump_start, dctx);
+
return ISC_R_SUCCESS;
}
dns_dumpctx_ref(dctx);
isc_loop_attach(loop, &dctx->loop);
- isc_work_enqueue(isc_loop(), ISC_WORKLANE_SLOW, master_dump,
- master_dump_done, dctx);
+ /* Publish *dctxp before the dump can start (see master_dump). */
*dctxp = dctx;
+ isc_async_run(loop, master_dump_start, dctx);
+
return ISC_R_SUCCESS;
cleanup_tempname:
dns_view_t *view;
dns_message_cb_t cb;
void *cbarg;
- isc_result_t result;
} checksig_ctx_t;
/*
static void
checksig_done(void *arg, isc_result_t result);
-static void
+static isc_result_t
checksig_run(void *arg) {
checksig_ctx_t *chsigctx = arg;
- chsigctx->result = dns_message_checksig(chsigctx->msg, chsigctx->view);
+ return dns_message_checksig(chsigctx->msg, chsigctx->view);
}
static void
-checksig_done(void *arg, isc_result_t result ISC_ATTR_UNUSED) {
+checksig_done(void *arg, isc_result_t result) {
checksig_ctx_t *chsigctx = arg;
dns_message_t *msg = chsigctx->msg;
- chsigctx->cb(chsigctx->cbarg,
- (result != ISC_R_SUCCESS) ? result : chsigctx->result);
+ chsigctx->cb(chsigctx->cbarg, result);
dns_view_detach(&chsigctx->view);
isc_loop_detach(&chsigctx->loop);
*chsigctx = (checksig_ctx_t){
.cb = cb,
.cbarg = cbarg,
- .result = ISC_R_UNSET,
.loop = isc_loop_ref(loop),
};
dns_message_attach(msg, &chsigctx->msg);
}
static void
-update_rpz_done_cb(void *data, isc_result_t result ISC_ATTR_UNUSED) {
+update_rpz_done_cb(void *data, isc_result_t result) {
dns_rpz_zone_t *rpz = (dns_rpz_zone_t *)data;
char dname[DNS_NAME_FORMATSIZE];
isc_log_write(DNS_LOGCATEGORY_GENERAL, DNS_LOGMODULE_RPZ, ISC_LOG_INFO,
"rpz: %s: reload done: %s", dname,
- isc_result_totext(rpz->updateresult));
+ isc_result_totext(result));
dns_rpz_zones_unref(rpz->rpzs);
}
return ISC_R_SUCCESS;
}
-static void
+static isc_result_t
update_rpz_cb(void *data) {
dns_rpz_zone_t *rpz = (dns_rpz_zone_t *)data;
isc_result_t result = ISC_R_SUCCESS;
REQUIRE(rpz->nodes != NULL);
- result = dns__rpz_shuttingdown(rpz->rpzs);
- if (result != ISC_R_SUCCESS) {
- goto shuttingdown;
- }
+ RETERR(dns__rpz_shuttingdown(rpz->rpzs));
isc_ht_init(&newnodes, rpz->rpzs->mctx, 1, ISC_HT_CASE_SENSITIVE);
cleanup:
isc_ht_destroy(&newnodes);
-shuttingdown:
- rpz->updateresult = result;
+ return result;
}
static void
rpz->updatepending = false;
rpz->updaterunning = true;
- rpz->updateresult = ISC_R_UNSET;
dns_db_attach(rpz->db, &rpz->updb);
INSIST(rpz->dbversion != NULL);
static isc_result_t
validate_async_run(dns_validator_t *val, isc_job_cb cb);
static isc_result_t
-validate_work_enqueue(dns_validator_t *val, isc_job_cb cb);
+validate_work_enqueue(dns_validator_t *val, isc_work_cb cb);
static void
validate_dnskey(void *arg);
static void
consume_validation_fail(dns_validator_t *val);
-static void
+static isc_result_t
resume_answer_with_key(void *arg) {
dns_validator_t *val = arg;
dns_rdataset_t *rdataset = &val->frdataset;
consume_validation_fail(val);
}
- (void)validate_async_run(val, resume_answer_with_key_done);
+ return validate_async_run(val, resume_answer_with_key_done);
}
static void
static void
validate_answer_signing_key_done(void *arg);
-static void
+static isc_result_t
validate_answer_signing_key(void *arg) {
dns_validator_t *val = arg;
isc_result_t result;
break;
}
- (void)validate_async_run(val, validate_answer_signing_key_done);
+ return validate_async_run(val, validate_answer_signing_key_done);
}
static void
}
static isc_result_t
-validate_work_enqueue(dns_validator_t *val, isc_job_cb cb) {
+validate_work_enqueue(dns_validator_t *val, isc_work_cb cb) {
val->attributes |= VALATTR_OFFLOADED;
isc_work_enqueue(val->loop, ISC_WORKLANE_FAST, cb, null_done, val);
return DNS_R_WAIT;
static void
validate_dnskey_dsset_next_done(void *arg);
-static void
+static isc_result_t
validate_dnskey_dsset_next(void *arg) {
dns_validator_t *val = arg;
val->result = validate_dnskey_dsset(val);
}
- validate_async_run(val, validate_dnskey_dsset_next_done);
+ return validate_async_run(val, validate_dnskey_dsset_next_done);
}
static void
#define XFRIN_MAGIC ISC_MAGIC('X', 'f', 'r', 'I')
#define VALID_XFRIN(x) ISC_MAGIC_VALID(x, XFRIN_MAGIC)
-#define XFRIN_WORK_MAGIC ISC_MAGIC('X', 'f', 'r', 'W')
-#define VALID_XFRIN_WORK(x) ISC_MAGIC_VALID(x, XFRIN_WORK_MAGIC)
-
-typedef struct xfrin_work {
- unsigned int magic;
- isc_result_t result;
- dns_xfrin_t *xfr;
-} xfrin_work_t;
-
/**************************************************************************/
/*
* Forward declarations.
return result;
}
-static void
+static isc_result_t
axfr_apply(void *arg);
static isc_result_t
CHECK(dns_zone_checknames(xfr->zone, name, rdata));
if (dns_diff_size(&xfr->diff) > 128) {
- xfrin_work_t work = (xfrin_work_t){
- .magic = XFRIN_WORK_MAGIC,
- .result = ISC_R_UNSET,
- .xfr = xfr,
- };
- axfr_apply((void *)&work);
- CHECK(work.result);
+ CHECK(axfr_apply(xfr));
}
dns_difftuple_create(xfr->diff.mctx, op, name, ttl, rdata, &tuple);
/*
* Store a set of AXFR RRs in the database.
*/
-static void
+static isc_result_t
axfr_apply(void *arg) {
- xfrin_work_t *work = arg;
- REQUIRE(VALID_XFRIN_WORK(work));
-
- dns_xfrin_t *xfr = work->xfr;
+ dns_xfrin_t *xfr = arg;
REQUIRE(VALID_XFRIN(xfr));
isc_result_t result = ISC_R_SUCCESS;
cleanup:
dns_diff_clear(&xfr->diff);
- work->result = result;
+
+ return result;
}
static void
-axfr_apply_done(void *arg, isc_result_t eresult) {
- xfrin_work_t *work = arg;
- dns_xfrin_t *xfr = work->xfr;
- isc_result_t result = (eresult == ISC_R_SUCCESS) ? work->result
- : eresult;
+axfr_apply_done(void *arg, isc_result_t result) {
+ dns_xfrin_t *xfr = arg;
REQUIRE(VALID_XFRIN(xfr));
- REQUIRE(VALID_XFRIN_WORK(work));
if (atomic_load(&xfr->shuttingdown)) {
result = ISC_R_SHUTTINGDOWN;
cleanup:
xfr->diff_running = false;
- isc_mem_put(xfr->mctx, work, sizeof(*work));
-
if (result == ISC_R_SUCCESS) {
if (atomic_load(&xfr->state) == XFRST_AXFR_END) {
xfrin_end(xfr, result);
axfr_commit(dns_xfrin_t *xfr) {
REQUIRE(!xfr->diff_running);
- xfrin_work_t *work = isc_mem_get(xfr->mctx, sizeof(*work));
- *work = (xfrin_work_t){
- .magic = XFRIN_WORK_MAGIC,
- .result = ISC_R_UNSET,
- .xfr = dns_xfrin_ref(xfr),
- };
+ dns_xfrin_ref(xfr);
xfr->diff_running = true;
isc_work_enqueue(xfr->loop, ISC_WORKLANE_SLOW, axfr_apply,
- axfr_apply_done, work);
+ axfr_apply_done, xfr);
}
static isc_result_t
return result;
}
-static void
+static isc_result_t
ixfr_apply(void *arg) {
- xfrin_work_t *work = arg;
- dns_xfrin_t *xfr = work->xfr;
+ dns_xfrin_t *xfr = arg;
isc_result_t result = ISC_R_SUCCESS;
REQUIRE(VALID_XFRIN(xfr));
- REQUIRE(VALID_XFRIN_WORK(work));
struct __cds_wfcq_head diff_head;
struct cds_wfcq_tail diff_tail;
isc_mem_put(xfr->mctx, data, sizeof(*data));
}
- work->result = result;
+ return result;
}
static void
-ixfr_apply_done(void *arg, isc_result_t eresult) {
- xfrin_work_t *work = arg;
- REQUIRE(VALID_XFRIN_WORK(work));
-
- dns_xfrin_t *xfr = work->xfr;
+ixfr_apply_done(void *arg, isc_result_t result) {
+ dns_xfrin_t *xfr = arg;
REQUIRE(VALID_XFRIN(xfr));
- isc_result_t result = (eresult == ISC_R_SUCCESS) ? work->result
- : eresult;
-
if (atomic_load(&xfr->shuttingdown)) {
result = ISC_R_SHUTTINGDOWN;
}
!cds_wfcq_empty(&xfr->diff_head, &xfr->diff_tail))
{
isc_work_enqueue(xfr->loop, ISC_WORKLANE_SLOW, ixfr_apply,
- ixfr_apply_done, work);
+ ixfr_apply_done, xfr);
return;
}
cleanup:
xfr->diff_running = false;
- isc_mem_put(xfr->mctx, work, sizeof(*work));
-
/*
* Don't retry with AXFR (even if it was requested) because there was
* an error or the transfer is shutting down. In case if it _was_ an
&data->wfcq_node);
if (!xfr->diff_running) {
- xfrin_work_t *work = isc_mem_get(xfr->mctx, sizeof(*work));
- *work = (xfrin_work_t){
- .magic = XFRIN_WORK_MAGIC,
- .result = ISC_R_UNSET,
- .xfr = dns_xfrin_ref(xfr),
- };
+ dns_xfrin_ref(xfr);
xfr->diff_running = true;
isc_work_enqueue(xfr->loop, ISC_WORKLANE_SLOW, ixfr_apply,
- ixfr_apply_done, work);
+ ixfr_apply_done, xfr);
}
cleanup:
}
#endif /* ifdef HAVE_ZLIB */
-static void
+static isc_result_t
prepare_response(void *arg) {
isc_httpd_sendreq_t *req = arg;
isc_httpd_t *httpd = req->httpd;
}
httpd->recvlen -= httpd->consume;
httpd->consume = 0;
+
+ return ISC_R_SUCCESS;
}
static void
*
* Each isc event loop has one worker thread per lane (see isc_worklane_t).
* isc_work_enqueue() runs a callback on the worker thread bound to the calling
- * loop's lane and, when it finishes, runs a second callback back on that loop.
- * The handle it returns can be used to cancel a task that has not started
- * running yet.
+ * loop's lane and, when it finishes, runs a second callback back on that loop
+ * with the first callback's result. The handle it returns can be used to
+ * cancel a task that has not started running yet.
*/
#pragma once
* holding up short FAST tasks behind it.
*/
-typedef void (*isc_work_cb)(void *arg);
+typedef isc_result_t (*isc_work_cb)(void *arg);
typedef void (*isc_work_done_cb)(void *arg, isc_result_t result);
typedef struct isc_work isc_work_t;
/*%<
* Schedule 'cb' to run on the worker thread bound to 'loop' and 'lane'. When
* 'cb' returns, 'done_cb' is scheduled back on 'loop' with the result of the
- * work: ISC_R_SUCCESS normally, or ISC_R_CANCELED if the task was canceled
+ * work: the value 'cb' returned, or ISC_R_CANCELED if the task was canceled
* before it started (see isc_work_cancel()).
*
* Returns a handle that may be passed to isc_work_cancel(). The handle is
- * owned by 'loop' and stays valid until 'after_cb' has run; it must not be used
+ * owned by 'loop' and stays valid until 'done_cb' has run; it must not be used
* afterwards.
*
* Requires:
*
*\li 'loop' is a valid isc event loop.
*\li 'cb' is non-NULL.
- *\li 'after_cb' is non-NULL.
+ *\li 'done_cb' is non-NULL.
*\li 'cbarg' is passed to both callbacks, may be NULL.
*/
/*%<
* Try to cancel 'work' before its 'cb' starts running. If the task is still
* queued it is marked canceled and 'cb' will not run; if it is already running
- * or has finished this has no effect. Either way the 'after_cb' passed to
+ * or has finished this has no effect. Either way the 'done_cb' passed to
* isc_work_enqueue() still runs on the origin loop, with ISC_R_CANCELED when
* the cancel succeeded. Nothing is freed here.
*
*
* Requires:
*
- *\li 'work' is a handle from isc_work_enqueue() whose 'after_cb' has not run.
+ *\li 'work' is a handle from isc_work_enqueue() whose 'done_cb' has not run.
*/
/* private */
struct isc_work {
unsigned int magic;
- uint32_t state; /* enum workstate */
+ uint32_t state; /* enum workstate */
+ isc_result_t result;
isc_work_cb cb; /* runs on a worker thread */
isc_work_done_cb done_cb; /* runs on the origin loop */
void *cbarg;
work_done(void *arg) {
isc_work_t *work = arg;
isc_loop_t *loop = work->loop;
- isc_result_t result = (uatomic_load(&work->state, CMM_ACQUIRE) !=
- WORK_CANCELED)
- ? ISC_R_SUCCESS
- : ISC_R_CANCELED;
- work->done_cb(work->cbarg, result);
+ /* work_run() has settled work->result before scheduling us. */
+ INSIST(work->result != ISC_R_UNSET);
+
+ work->done_cb(work->cbarg, work->result);
work->magic = 0;
isc_mem_put(work->loop->mctx, work, sizeof(*work));
WORK_RUNNING);
switch (prev) {
case WORK_QUEUED:
- work->cb(work->cbarg);
+ work->result = work->cb(work->cbarg);
break;
case WORK_CANCELED:
+ work->result = ISC_R_CANCELED;
break;
default:
UNREACHABLE();
isc_work_t *work = isc_mem_get(loop->mctx, sizeof(*work));
*work = (isc_work_t){
.magic = WORK_MAGIC,
+ .result = ISC_R_UNSET,
.cb = cb,
.done_cb = done_cb,
.cbarg = cbarg,
/*
* Tombstone: QUEUED -> CANCELED. The node stays in the queue
* (no interior unlink in a singly-linked lock-free queue) and
- * is discarded by whichever worker dequeues it; after_cb still
+ * is discarded by whichever worker dequeues it; done_cb still
* fires with ISC_R_CANCELED. Nothing is freed here. False
* means the callback is running or done — uv_cancel semantics.
*/
static atomic_uint scheduled = 0;
-static void
+static isc_result_t
work_cb(void *arg ISC_ATTR_UNUSED) {
atomic_fetch_add(&scheduled, 1);
assert_int_equal(isc_tid(), ISC_TID_UNKNOWN);
+
+ return ISC_R_ALREADYRUNNING; /* mock result code */
}
static void
-after_work_cb(void *arg ISC_ATTR_UNUSED, isc_result_t result ISC_ATTR_UNUSED) {
+after_work_cb(void *arg ISC_ATTR_UNUSED, isc_result_t result) {
+ assert_int_equal(result, ISC_R_ALREADYRUNNING);
assert_int_equal(atomic_load(&scheduled), 1);
isc_loopmgr_shutdown();
}