mirror of
https://github.com/isc-projects/bind9.git
synced 2026-07-12 22:15:51 -04:00
Offloaded work used two different mechanisms: a per-loop isc_helper thread for CPU-bound crypto (DNSSEC validation, message signature checks) and the process-global libuv thread pool for blocking I/O (zone load and dump, inbound transfer apply). Neither could cancel a queued task, and the two disagreed about exclusive mode — the helper paused with its loop under isc_loopmgr_pause() but the libuv pool did not, so blocking offloaded work kept running while a loop held the exclusive lock. Unify both behind isc_work: each loop gets its own worker thread per lane — FAST for short, bounded tasks and SLOW for long, blocking ones — fed by a private queue. Separate lanes keep a short crypto task off the path of a multi-second zone dump once both run on per-loop workers; every lane parks with isc_loopmgr_pause() so exclusive mode now quiesces offloaded work too; and a still-queued task can be canceled before it starts (isc_work_cancel). isc_helper is removed and its callers select a lane.
105 lines
3.5 KiB
C
105 lines
3.5 KiB
C
/*
|
|
* Copyright (C) Internet Systems Consortium, Inc. ("ISC")
|
|
*
|
|
* SPDX-License-Identifier: MPL-2.0
|
|
*
|
|
* This Source Code Form is subject to the terms of the Mozilla Public
|
|
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
|
* file, you can obtain one at https://mozilla.org/MPL/2.0/.
|
|
*
|
|
* See the COPYRIGHT file distributed with this work for additional
|
|
* information regarding copyright ownership.
|
|
*/
|
|
|
|
#include <isc/os.h>
|
|
#include <isc/urcu.h>
|
|
|
|
STATIC_ASSERT(sizeof(struct __cds_wfcq_head) <= ISC_OS_CACHELINE_SIZE,
|
|
"size of struct __cds_wfcq_head must be smaller than "
|
|
"ISC_OS_CACHELINE_SIZE");
|
|
|
|
typedef struct isc_queue {
|
|
struct __cds_wfcq_head head;
|
|
uint8_t __padding_head[ISC_OS_CACHELINE_SIZE -
|
|
sizeof(struct __cds_wfcq_head)];
|
|
struct cds_wfcq_tail tail;
|
|
uint8_t __padding_tail[ISC_OS_CACHELINE_SIZE -
|
|
sizeof(struct cds_wfcq_tail)];
|
|
} isc_queue_t;
|
|
|
|
typedef struct cds_wfcq_node isc_queue_node_t;
|
|
|
|
static inline void
|
|
isc_queue_node_init(isc_queue_node_t *node) {
|
|
cds_wfcq_node_init(node);
|
|
}
|
|
|
|
static inline void
|
|
isc_queue_init(isc_queue_t *queue) {
|
|
__cds_wfcq_init(&(queue)->head, &(queue)->tail);
|
|
}
|
|
|
|
static inline void
|
|
isc_queue_destroy(isc_queue_t *queue) {
|
|
UNUSED(queue);
|
|
}
|
|
|
|
static inline bool
|
|
isc_queue_empty(isc_queue_t *queue) {
|
|
return cds_wfcq_empty(&(queue)->head, &(queue)->tail);
|
|
}
|
|
|
|
static inline bool
|
|
isc_queue_enqueue(isc_queue_t *queue, isc_queue_node_t *node) {
|
|
return cds_wfcq_enqueue(&(queue)->head, &(queue)->tail, node);
|
|
}
|
|
|
|
#define isc_queue_enqueue_entry(queue, entry, member) \
|
|
cds_wfcq_enqueue(&(queue)->head, &(queue)->tail, &((entry)->member))
|
|
|
|
static inline isc_queue_node_t *
|
|
isc_queue_dequeue(isc_queue_t *queue) {
|
|
return __cds_wfcq_dequeue_nonblocking(&(queue)->head, &(queue)->tail);
|
|
}
|
|
|
|
#define isc_queue_entry(ptr, type, member) \
|
|
caa_container_of_check_null(ptr, type, member)
|
|
|
|
#define isc_queue_dequeue_entry(queue, type, member) \
|
|
isc_queue_entry(isc_queue_dequeue(queue), type, member)
|
|
|
|
static inline bool
|
|
isc_queue_splice(isc_queue_t *dest, isc_queue_t *src) {
|
|
enum cds_wfcq_ret ret = __cds_wfcq_splice_blocking(
|
|
&dest->head, &dest->tail, &src->head, &src->tail);
|
|
INSIST(ret != CDS_WFCQ_RET_WOULDBLOCK &&
|
|
ret != CDS_WFCQ_RET_DEST_NON_EMPTY);
|
|
|
|
return ret != CDS_WFCQ_RET_SRC_EMPTY;
|
|
}
|
|
|
|
#define isc_queue_first_entry(queue, type, member) \
|
|
isc_queue_entry( \
|
|
__cds_wfcq_first_blocking(&(queue)->head, &(queue)->tail), \
|
|
type, member)
|
|
|
|
#define isc_queue_next_entry(queue, node, type, member) \
|
|
isc_queue_entry(__cds_wfcq_next_blocking(&(queue)->head, \
|
|
&(queue)->tail, node), \
|
|
type, member)
|
|
|
|
#define isc_queue_for_each_entry(queue, pos, member) \
|
|
for (pos = isc_queue_first_entry(queue, __typeof__(*pos), member); \
|
|
pos != NULL; \
|
|
pos = isc_queue_next_entry(queue, &(pos)->member, \
|
|
__typeof__(*pos), member))
|
|
|
|
#define isc_queue_for_each_entry_safe(queue, pos, next, member) \
|
|
for (pos = isc_queue_first_entry(queue, __typeof__(*pos), member), \
|
|
next = (pos ? isc_queue_next_entry(queue, &(pos)->member, \
|
|
__typeof__(*pos), member) \
|
|
: NULL); \
|
|
pos != NULL; pos = next, \
|
|
next = (pos ? isc_queue_next_entry(queue, &(pos)->member, \
|
|
__typeof__(*pos), member) \
|
|
: NULL))
|