diff --git a/lib/isc/Makefile.am b/lib/isc/Makefile.am index f6343136ef..8a84c407e2 100644 --- a/lib/isc/Makefile.am +++ b/lib/isc/Makefile.am @@ -64,6 +64,7 @@ libisc_la_HEADERS = \ include/isc/pause.h \ include/isc/portset.h \ include/isc/proxy2.h \ + include/isc/queue.h \ include/isc/quota.h \ include/isc/radix.h \ include/isc/random.h \ diff --git a/lib/isc/include/isc/queue.h b/lib/isc/include/isc/queue.h new file mode 100644 index 0000000000..743d3c626d --- /dev/null +++ b/lib/isc/include/isc/queue.h @@ -0,0 +1,103 @@ +/* + * 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 +#include + +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[ISC_OS_CACHELINE_SIZE - + sizeof(struct __cds_wfcq_head)]; + struct cds_wfcq_tail 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))