1 /* $NetBSD: work.h,v 1.3 2026/08/29 14:55:19 christos Exp $ */ 2 3 /* 4 * Copyright (C) Internet Systems Consortium, Inc. ("ISC") 5 * 6 * SPDX-License-Identifier: MPL-2.0 7 * 8 * This Source Code Form is subject to the terms of the Mozilla Public 9 * License, v. 2.0. If a copy of the MPL was not distributed with this 10 * file, you can obtain one at https://mozilla.org/MPL/2.0/. 11 * 12 * See the COPYRIGHT file distributed with this work for additional 13 * information regarding copyright ownership. 14 */ 15 16 /*! \file isc/work.h 17 * \brief Offload work from an event loop onto a dedicated worker thread. 18 * 19 * Each isc event loop has one worker thread per lane (see isc_worklane_t). 20 * isc_work_enqueue() runs a callback on the worker thread bound to the calling 21 * loop's lane and, when it finishes, runs a second callback back on that loop 22 * with the first callback's result. The handle it returns can be used to 23 * cancel a task that has not started running yet. 24 */ 25 26 #pragma once 27 28 #include <isc/lang.h> 29 #include <isc/mem.h> 30 31 typedef enum isc_worklane { 32 ISC_WORKLANE_FAST = 0, /*%< short, bounded tasks (e.g. crypto) */ 33 ISC_WORKLANE_SLOW, /*%< blocking/long tasks (e.g. zone dump) */ 34 ISC_WORKLANE_COUNT, 35 } isc_worklane_t; 36 /*%< 37 * Selects which per-loop worker thread runs an enqueued task. Keeping long, 38 * blocking SLOW work (disk I/O, zone dump/load) on its own lane stops it from 39 * holding up short FAST tasks behind it. 40 */ 41 42 typedef isc_result_t (*isc_work_cb)(void *arg); 43 typedef void (*isc_work_done_cb)(void *arg, isc_result_t result); 44 typedef struct isc_work isc_work_t; 45 46 ISC_LANG_BEGINDECLS 47 48 isc_work_t * 49 isc_work_enqueue(isc_loop_t *loop, isc_worklane_t lane, isc_work_cb cb, 50 isc_work_done_cb done_cb, void *cbarg); 51 /*%< 52 * Schedule 'cb' to run on the worker thread bound to 'loop' and 'lane'. When 53 * 'cb' returns, 'done_cb' is scheduled back on 'loop' with the result of the 54 * work: the value 'cb' returned, or ISC_R_CANCELED if the task was canceled 55 * before it started (see isc_work_cancel()). 56 * 57 * Returns a handle that may be passed to isc_work_cancel(). The handle is 58 * owned by 'loop' and stays valid until 'done_cb' has run; it must not be used 59 * afterwards. 60 * 61 * Requires: 62 * 63 *\li 'loop' is a valid isc event loop. 64 *\li 'cb' is non-NULL. 65 *\li 'done_cb' is non-NULL. 66 *\li 'cbarg' is passed to both callbacks, may be NULL. 67 */ 68 69 bool 70 isc_work_cancel(isc_work_t *work); 71 /*%< 72 * Try to cancel 'work' before its 'cb' starts running. If the task is still 73 * queued it is marked canceled and 'cb' will not run; if it is already running 74 * or has finished this has no effect. Either way the 'done_cb' passed to 75 * isc_work_enqueue() still runs on the origin loop, with ISC_R_CANCELED when 76 * the cancel succeeded. Nothing is freed here. 77 * 78 * Returns: 79 * 80 *\li true the task was still queued; 'cb' will not run. 81 *\li false the task is already running or done (uv_cancel() semantics). 82 * 83 * Requires: 84 * 85 *\li 'work' is a handle from isc_work_enqueue() whose 'done_cb' has not run. 86 */ 87 88 /* private */ 89 90 typedef struct isc__workthread isc__workthread_t; 91 92 isc__workthread_t * 93 isc__workthread_create(isc_loop_t *loop, isc_worklane_t lane); 94 /*%< 95 * Create one worker thread for 'lane' with its own dispatch queue (the loop 96 * manager creates one per loop). Used by the loop manager; not for general 97 * use. 98 */ 99 100 void 101 isc__workthread_shutdown(isc__workthread_t *thread); 102 /*%< 103 * Begin shutdown of 'thread': set its SHUTDOWN flag (after which new enqueues 104 * run inline on the caller instead of queuing), then, after an RCU grace period 105 * that fences any in-flight enqueue, wake the worker so it drains its queue and 106 * exits. Does not join the worker; see isc__workthread_destroy(). Idempotent. 107 */ 108 109 void 110 isc__workthread_pause(isc__workthread_t *thread); 111 /*%< 112 * Quiesce 'thread' for isc_loopmgr_pause(): mark it paused and block until it 113 * has parked. A no-op if the worker is already shutting down. Must be paired 114 * with isc__workthread_resume() and called from the worker's owning loop. 115 */ 116 117 void 118 isc__workthread_resume(isc__workthread_t *thread); 119 /*%< 120 * Release a worker previously parked by isc__workthread_pause(). 121 */ 122 123 void 124 isc__workthread_destroy(isc__workthread_t **threadp); 125 /*%< 126 * Join the worker thread, then free '*threadp' and set it to NULL. Must be 127 * called after isc__workthread_shutdown(). 128 */ 129 130 ISC_LANG_ENDDECLS 131