bind9/lib/isc/include/isc/queue.h
Ondřej Surý c602d76c1f
Reduce false sharing in dns_qpcache
Instead of having many node_lock_count * sizeof(<member>) arrays, pack
all the members into a qpcache_bucket_t struct that is cacheline aligned
and have a single array of those.

Additionaly, make both the head and the tail of isc_queue_t padded, not
just the head, to prevent false sharing of the lock-free structure with
the lock that follows it.
2025-02-04 21:37:46 +01:00

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_head)];
} 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))