ee4347
From 0df59049fe13ef89d362fa7f109f289b297441dc Mon Sep 17 00:00:00 2001
ee4347
From: =?UTF-8?q?Ond=C5=99ej=20Sur=C3=BD?= <ondrej@isc.org>
ee4347
Date: Tue, 22 Feb 2022 23:40:39 +0100
ee4347
Subject: [PATCH] Provide alternative isc_queue implementation based on locked
ee4347
 list
ee4347
ee4347
The current implementation of isc_queue uses Michael-Scott lock-free
ee4347
queue that in turn uses hazard pointers.  It was discovered that the way
ee4347
we use the isc_queue, such complicated mechanism isn't really needed,
ee4347
because most of the time, we either execute the work directly when on
ee4347
nmthread (in case of UDP) or schedule the work from the matching
ee4347
nmthreads.
ee4347
ee4347
Provide alternative implementation for the isc_queue based on locked
ee4347
ISC_LIST.
ee4347
PatchNumber: 11
ee4347
PatchNumber: 11
ee4347
---
ee4347
 bin/named/main.c            |   1 -
ee4347
 configure.ac                |  12 ++++
ee4347
 lib/isc/include/isc/queue.h |   3 +-
ee4347
 lib/isc/queue.c             | 121 ++++++++++++++++++++++++++++++++++++
ee4347
 4 files changed, 134 insertions(+), 3 deletions(-)
ee4347
ee4347
diff --git a/bin/named/main.c b/bin/named/main.c
ee4347
index 9ad2d0e..8870933 100644
ee4347
--- a/bin/named/main.c
ee4347
+++ b/bin/named/main.c
ee4347
@@ -34,7 +34,6 @@
ee4347
 #include <isc/dir.h>
ee4347
 #include <isc/file.h>
ee4347
 #include <isc/hash.h>
ee4347
-#include <isc/hp.h>
ee4347
 #include <isc/httpd.h>
ee4347
 #include <isc/managers.h>
ee4347
 #include <isc/netmgr.h>
ee4347
diff --git a/configure.ac b/configure.ac
ee4347
index 79d33d1..26241a0 100644
ee4347
--- a/configure.ac
ee4347
+++ b/configure.ac
ee4347
@@ -2263,8 +2263,20 @@ AS_CASE([$with_cmocka],
ee4347
 AC_SUBST([CMOCKA_CFLAGS])
ee4347
 AC_SUBST([CMOCKA_LIBS])
ee4347
 
ee4347
+#
ee4347
+# Use lock-free Michael-Scott's queue implementation or locked-list queue
ee4347
+#
ee4347
+# [pairwise: --enable-lock-free-queue, --disable-lock-free-queue]
ee4347
+AC_ARG_ENABLE([lock-free-queue],
ee4347
+	    [AS_HELP_STRING([--enable-lock-free-queue],[enable lock-free queue implementation (default is enabled)])],
ee4347
+	    [],[enable_lock_free_queue=yes])
ee4347
+AS_CASE([$enable_lock_free_queue],
ee4347
+	[no],[],
ee4347
+	[yes],[AC_DEFINE([USE_LOCK_FREE_QUEUE],[1],[Define to 1 to enable lock-free queue])])
ee4347
+
ee4347
 AC_DEFINE([SKIPPED_TEST_EXIT_CODE], [0], [Exit code for skipped tests])
ee4347
 
ee4347
+
ee4347
 #
ee4347
 # Check for kyua execution engine if CMocka was requested
ee4347
 # and bail out if execution engine was not found
ee4347
diff --git a/lib/isc/include/isc/queue.h b/lib/isc/include/isc/queue.h
ee4347
index 0927075..568bf18 100644
ee4347
--- a/lib/isc/include/isc/queue.h
ee4347
+++ b/lib/isc/include/isc/queue.h
ee4347
@@ -39,8 +39,7 @@ uintptr_t
ee4347
 isc_queue_dequeue(isc_queue_t *queue);
ee4347
 /*%<
ee4347
  * Remove an object pointer from the head of the queue and return the
ee4347
- * pointer. If the queue is empty, return `nulluintptr` (the uintptr_t
ee4347
- * representation of NULL).
ee4347
+ * pointer. If the queue is empty, return `NULL`.
ee4347
  *
ee4347
  * Requires:
ee4347
  * \li	'queue' is not null.
ee4347
diff --git a/lib/isc/queue.c b/lib/isc/queue.c
ee4347
index d7ea824..c4cb404 100644
ee4347
--- a/lib/isc/queue.c
ee4347
+++ b/lib/isc/queue.c
ee4347
@@ -28,6 +28,10 @@
ee4347
 
ee4347
 static uintptr_t nulluintptr = (uintptr_t)NULL;
ee4347
 
ee4347
+#if USE_LOCK_FREE_QUEUE
ee4347
+
ee4347
+#define BUFFER_SIZE 1024
ee4347
+
ee4347
 typedef struct node {
ee4347
 	atomic_uint_fast32_t deqidx;
ee4347
 	atomic_uintptr_t items[BUFFER_SIZE];
ee4347
@@ -232,3 +236,120 @@ isc_queue_destroy(isc_queue_t *queue) {
ee4347
 	alloced = queue->alloced_ptr;
ee4347
 	isc_mem_putanddetach(&queue->mctx, alloced, sizeof(*queue) + ALIGNMENT);
ee4347
 }
ee4347
+
ee4347
+#else /* USE_LOCK_FREE_QUEUE */
ee4347
+
ee4347
+typedef struct node node_t;
ee4347
+
ee4347
+struct node {
ee4347
+	uintptr_t item;
ee4347
+	ISC_LINK(node_t) link;
ee4347
+};
ee4347
+
ee4347
+struct isc_queue {
ee4347
+	isc_mem_t *mctx;
ee4347
+	isc_mutex_t lock;
ee4347
+	int max_threads;
ee4347
+	ISC_LIST(node_t) nodes;
ee4347
+	void *alloced_ptr;
ee4347
+};
ee4347
+
ee4347
+static node_t *
ee4347
+node_new(isc_mem_t *mctx, uintptr_t item) {
ee4347
+	node_t *node = isc_mem_get(mctx, sizeof(*node));
ee4347
+	*node = (node_t){
ee4347
+		.item = item,
ee4347
+	};
ee4347
+
ee4347
+	ISC_LINK_INIT(node, link);
ee4347
+
ee4347
+	return (node);
ee4347
+}
ee4347
+
ee4347
+static void
ee4347
+node_destroy(isc_mem_t *mctx, node_t *node) {
ee4347
+	isc_mem_put(mctx, node, sizeof(*node));
ee4347
+}
ee4347
+
ee4347
+isc_queue_t *
ee4347
+isc_queue_new(isc_mem_t *mctx, int max_threads) {
ee4347
+	isc_queue_t *queue = NULL;
ee4347
+	void *qbuf = NULL;
ee4347
+	uintptr_t qptr;
ee4347
+
ee4347
+	qbuf = isc_mem_get(mctx, sizeof(*queue) + ALIGNMENT);
ee4347
+	qptr = (uintptr_t)qbuf;
ee4347
+	queue = (isc_queue_t *)(qptr + (ALIGNMENT - (qptr % ALIGNMENT)));
ee4347
+
ee4347
+	if (max_threads == 0) {
ee4347
+		max_threads = MAX_THREADS;
ee4347
+	}
ee4347
+
ee4347
+	*queue = (isc_queue_t){
ee4347
+		.max_threads = max_threads,
ee4347
+		.alloced_ptr = qbuf,
ee4347
+	};
ee4347
+
ee4347
+	ISC_LIST_INIT(queue->nodes);
ee4347
+
ee4347
+	isc_mutex_init(&queue->lock);
ee4347
+	isc_mem_attach(mctx, &queue->mctx);
ee4347
+
ee4347
+	return (queue);
ee4347
+}
ee4347
+
ee4347
+void
ee4347
+isc_queue_enqueue(isc_queue_t *queue, uintptr_t item) {
ee4347
+	node_t *node = node_new(queue->mctx, item);
ee4347
+	REQUIRE(item != nulluintptr);
ee4347
+
ee4347
+	LOCK(&queue->lock);
ee4347
+	ISC_LIST_ENQUEUE(queue->nodes, node, link);
ee4347
+	UNLOCK(&queue->lock);
ee4347
+}
ee4347
+
ee4347
+uintptr_t
ee4347
+isc_queue_dequeue(isc_queue_t *queue) {
ee4347
+	node_t *node = NULL;
ee4347
+	uintptr_t item = nulluintptr;
ee4347
+	REQUIRE(queue != NULL);
ee4347
+
ee4347
+	LOCK(&queue->lock);
ee4347
+	node = ISC_LIST_HEAD(queue->nodes);
ee4347
+	if (node != NULL) {
ee4347
+		ISC_LIST_DEQUEUE(queue->nodes, node, link);
ee4347
+		item = node->item;
ee4347
+	}
ee4347
+	UNLOCK(&queue->lock);
ee4347
+
ee4347
+	if (node != NULL) {
ee4347
+		node_destroy(queue->mctx, node);
ee4347
+	}
ee4347
+
ee4347
+	return (item);
ee4347
+}
ee4347
+
ee4347
+void
ee4347
+isc_queue_destroy(isc_queue_t *queue) {
ee4347
+	node_t *node = NULL;
ee4347
+	void *alloced = NULL;
ee4347
+
ee4347
+	REQUIRE(queue != NULL);
ee4347
+
ee4347
+	LOCK(&queue->lock);
ee4347
+	node = ISC_LIST_HEAD(queue->nodes);
ee4347
+	while (node != NULL) {
ee4347
+		node_t *next = ISC_LIST_NEXT(node, link);
ee4347
+		ISC_LIST_DEQUEUE(queue->nodes, node, link);
ee4347
+		node_destroy(queue->mctx, node);
ee4347
+		node = next;
ee4347
+	}
ee4347
+	UNLOCK(&queue->lock);
ee4347
+
ee4347
+	isc_mutex_destroy(&queue->lock);
ee4347
+
ee4347
+	alloced = queue->alloced_ptr;
ee4347
+	isc_mem_putanddetach(&queue->mctx, alloced, sizeof(*queue) + ALIGNMENT);
ee4347
+}
ee4347
+
ee4347
+#endif /* USE_LOCK_FREE_QUEUE */
ee4347
-- 
ee4347
2.34.1
ee4347