[dpdk-dev] [PATCH 07/10] tailq: introduce dynamic register system

David Marchand david.marchand at 6wind.com
Wed Mar 4 22:50:07 CET 2015


This register system makes it possible to reserve a tailq for the dpdk
libraries.
The "dynamic" tailqs are right after the "static" tailqs in shared mem.
Primary process is responsible for writing the tailq names, so that secondary
processes can find them.

This is a temp commit, "static" tailqs are removed after conversion of all
users in next commits.

Signed-off-by: David Marchand <david.marchand at 6wind.com>
---
 app/test/test_tailq.c                           |   82 +++++++++-----
 lib/librte_eal/bsdapp/eal/rte_eal_version.map   |    1 +
 lib/librte_eal/common/eal_common_tailqs.c       |  130 +++++++++++++++++++++--
 lib/librte_eal/common/include/rte_tailq.h       |   38 +++++++
 lib/librte_eal/linuxapp/eal/rte_eal_version.map |    1 +
 5 files changed, 219 insertions(+), 33 deletions(-)

diff --git a/app/test/test_tailq.c b/app/test/test_tailq.c
index 56656f0..c046a8a 100644
--- a/app/test/test_tailq.c
+++ b/app/test/test_tailq.c
@@ -34,6 +34,7 @@
 #include <stdio.h>
 #include <stdint.h>
 #include <stdarg.h>
+#include <string.h>
 #include <errno.h>
 #include <sys/queue.h>
 
@@ -49,40 +50,59 @@
 	return 1; \
 } while (0)
 
-#define DEFAULT_TAILQ (RTE_TAILQ_NUM)
+static struct rte_tailq_elem rte_dummy_tailq = {
+	.name = "dummy",
+};
+EAL_REGISTER_TAILQ(rte_dummy_tailq)
+
+static struct rte_tailq_elem rte_dummy_dyn_tailq = {
+	.name = "dummy_dyn",
+};
+static struct rte_tailq_elem rte_dummy_dyn2_tailq = {
+	.name = "dummy_dyn",
+};
 
 static struct rte_tailq_entry d_elem;
+static struct rte_tailq_entry d_dyn_elem;
 
 static int
-test_tailq_create(void)
+test_tailq_early(void)
 {
 	struct rte_tailq_entry_head *d_head;
-	unsigned i;
 
-	/* create a first tailq and check its non-null */
-	d_head = RTE_TAILQ_LOOKUP_BY_IDX(DEFAULT_TAILQ, rte_tailq_entry_head);
+	d_head = RTE_TAILQ_CAST(rte_dummy_tailq.head, rte_tailq_entry_head);
 	if (d_head == NULL)
-		do_return("Error allocating dummy_q0\n");
+		do_return("Error %s has not been initialised\n",
+			  rte_dummy_tailq.name);
 
-	/* check we can add an item to it
-	 */
+	/* check we can add an item to it */
 	TAILQ_INSERT_TAIL(d_head, &d_elem, next);
 
-	/* try allocating dummy_q0 again, and check for failure */
-	if (RTE_TAILQ_LOOKUP_BY_IDX(DEFAULT_TAILQ, rte_tailq_entry_head) == NULL)
-		do_return("Error, non-null result returned when attemption to "
-				"re-allocate a tailq\n");
+	return 0;
+}
+
+static int
+test_tailq_create(void)
+{
+	struct rte_tailq_entry_head *d_head;
+
+	/* create a tailq and check its non-null (since we are post-eal init) */
+	if ((rte_eal_tailq_register(&rte_dummy_dyn_tailq) < 0) ||
+	    (rte_dummy_dyn_tailq.head == NULL))
+		do_return("Error allocating %s\n", rte_dummy_dyn_tailq.name);
+
+	d_head = RTE_TAILQ_CAST(rte_dummy_dyn_tailq.head, rte_tailq_entry_head);
 
-	/* now fill up the tailq slots available and check we get an error */
-	for (i = RTE_TAILQ_NUM; i < RTE_MAX_TAILQ; i++){
-		if ((d_head = RTE_TAILQ_LOOKUP_BY_IDX(i,
-				rte_tailq_entry_head)) == NULL)
-			break;
-	}
+	/* check we can add an item to it */
+	TAILQ_INSERT_TAIL(d_head, &d_dyn_elem, next);
 
-	/* check that we had an error return before RTE_MAX_TAILQ */
-	if (i != RTE_MAX_TAILQ)
-		do_return("Error, we did not have a reservation as expected\n");
+	if (strcmp(rte_dummy_dyn2_tailq.name, rte_dummy_dyn_tailq.name))
+		do_return("Error, something is wrong in the tailq test\n");
+
+	/* try allocating again, and check for failure */
+	if (!rte_eal_tailq_register(&rte_dummy_dyn2_tailq))
+		do_return("Error, registering the same tailq %s did not fail\n",
+			  rte_dummy_dyn2_tailq.name);
 
 	return 0;
 }
@@ -94,8 +114,10 @@ test_tailq_lookup(void)
 	struct rte_tailq_entry_head *d_head;
 	struct rte_tailq_entry *d_ptr;
 
-	d_head = RTE_TAILQ_LOOKUP_BY_IDX(DEFAULT_TAILQ, rte_tailq_entry_head);
-	if (d_head == NULL)
+	d_head = RTE_TAILQ_LOOKUP(rte_dummy_tailq.name, rte_tailq_entry_head);
+	/* rte_dummy_tailq has been registered by EAL_REGISTER_TAILQ */
+	if (d_head == NULL ||
+	    d_head != RTE_TAILQ_CAST(rte_dummy_tailq.head, rte_tailq_entry_head))
 		do_return("Error with tailq lookup\n");
 
 	TAILQ_FOREACH(d_ptr, d_head, next)
@@ -103,8 +125,19 @@ test_tailq_lookup(void)
 			do_return("Error with tailq returned from lookup - "
 					"expected element not found\n");
 
+	d_head = RTE_TAILQ_LOOKUP(rte_dummy_dyn_tailq.name, rte_tailq_entry_head);
+	/* rte_dummy_dyn_tailq has been registered by test_tailq_create */
+	if (d_head == NULL ||
+	    d_head != RTE_TAILQ_CAST(rte_dummy_dyn_tailq.head, rte_tailq_entry_head))
+		do_return("Error with tailq lookup\n");
+
+	TAILQ_FOREACH(d_ptr, d_head, next)
+		if (d_ptr != &d_dyn_elem)
+			do_return("Error with tailq returned from lookup - "
+					"expected element not found\n");
+
 	/* now try a bad/error lookup */
-	d_head = RTE_TAILQ_LOOKUP_BY_IDX(RTE_MAX_TAILQ, rte_tailq_entry_head);
+	d_head = RTE_TAILQ_LOOKUP("coucou", rte_tailq_entry_head);
 	if (d_head != NULL)
 		do_return("Error, lookup does not return NULL for bad tailq name\n");
 
@@ -115,6 +148,7 @@ static int
 test_tailq(void)
 {
 	int ret = 0;
+	ret |= test_tailq_early();
 	ret |= test_tailq_create();
 	ret |= test_tailq_lookup();
 	return ret;
diff --git a/lib/librte_eal/bsdapp/eal/rte_eal_version.map b/lib/librte_eal/bsdapp/eal/rte_eal_version.map
index c94fe8e..e42ea74 100644
--- a/lib/librte_eal/bsdapp/eal/rte_eal_version.map
+++ b/lib/librte_eal/bsdapp/eal/rte_eal_version.map
@@ -45,6 +45,7 @@ DPDK_2.0 {
 	rte_eal_remote_launch;
 	rte_eal_tailq_lookup;
 	rte_eal_tailq_lookup_by_idx;
+	rte_eal_tailq_register;
 	rte_eal_wait_lcore;
 	rte_exit;
 	rte_get_hpet_cycles;
diff --git a/lib/librte_eal/common/eal_common_tailqs.c b/lib/librte_eal/common/eal_common_tailqs.c
index 975ee74..3c4e70d 100644
--- a/lib/librte_eal/common/eal_common_tailqs.c
+++ b/lib/librte_eal/common/eal_common_tailqs.c
@@ -51,6 +51,7 @@
 #include <rte_branch_prediction.h>
 #include <rte_log.h>
 #include <rte_string_fns.h>
+#include <rte_debug.h>
 
 #include "eal_private.h"
 
@@ -62,6 +63,14 @@ const char* rte_tailq_names[RTE_MAX_TAILQ] = {
 #include <rte_tailq_elem.h>
 };
 
+TAILQ_HEAD(rte_tailq_elem_head, rte_tailq_elem);
+/* local tailq list */
+static struct rte_tailq_elem_head rte_tailq_elem_head =
+	TAILQ_HEAD_INITIALIZER(rte_tailq_elem_head);
+
+/* number of tailqs registered, -1 before call to rte_eal_tailqs_init */
+static int rte_tailqs_count = -1;
+
 struct rte_tailq_head *
 rte_eal_tailq_lookup(const char *name)
 {
@@ -72,9 +81,13 @@ rte_eal_tailq_lookup(const char *name)
 		return NULL;
 
 	for (i = 0; i < RTE_MAX_TAILQ; i++) {
-		if (rte_tailq_names[i] == NULL)
-			continue;
-		if (!strncmp(name, rte_tailq_names[i], RTE_TAILQ_NAMESIZE-1))
+		if (i < RTE_TAILQ_NUM &&
+		    !strncmp(name, rte_tailq_names[i], RTE_TAILQ_NAMESIZE-1))
+			return &mcfg->tailq_head[i];
+
+		/* if past static entries, look at shared mem for names */
+		if (!strncmp(name, mcfg->tailq_head[i].name,
+			     RTE_TAILQ_NAMESIZE-1))
 			return &mcfg->tailq_head[i];
 	}
 
@@ -103,31 +116,130 @@ rte_dump_tailq(FILE *f)
 	mcfg = rte_eal_get_configuration()->mem_config;
 
 	rte_rwlock_read_lock(&mcfg->qlock);
-	for (i=0; i < RTE_MAX_TAILQ; i++) {
+	for (i = 0; i < RTE_MAX_TAILQ; i++) {
 		const struct rte_tailq_head *tailq = &mcfg->tailq_head[i];
 		const struct rte_tailq_entry_head *head = &tailq->tailq_head;
+		const char *name = "nil";
 
-		fprintf(f, "Tailq %u: qname:<%s>, tqh_first:%p, tqh_last:%p\n", i,
-		       (rte_tailq_names[i] != NULL ? rte_tailq_names[i]:"nil"),
-		       head->tqh_first, head->tqh_last);
+		if (rte_tailq_names[i])
+			name = rte_tailq_names[i];
+		else if (tailq->name)
+			name = tailq->name;
+
+		fprintf(f, "Tailq %u: qname:<%s>, tqh_first:%p, tqh_last:%p\n",
+			i, name, head->tqh_first, head->tqh_last);
 	}
 	rte_rwlock_read_unlock(&mcfg->qlock);
 }
 
+static struct rte_tailq_head *
+rte_eal_tailq_create(const char *name)
+{
+	struct rte_tailq_head *head = NULL;
+
+	if (!rte_eal_tailq_lookup(name) &&
+	    (rte_tailqs_count + 1 < RTE_MAX_TAILQ)) {
+		struct rte_mem_config *mcfg;
+
+		mcfg = rte_eal_get_configuration()->mem_config;
+		head = &mcfg->tailq_head[rte_tailqs_count];
+		snprintf(head->name, sizeof(head->name) - 1, "%s", name);
+		TAILQ_INIT(&head->tailq_head);
+		rte_tailqs_count++;
+	}
+
+	return head;
+}
+
+/* local register, used to store "early" tailqs before rte_eal_init() and to
+ * ensure secondary process only registers tailqs once. */
+static int
+rte_eal_tailq_local_register(struct rte_tailq_elem *t)
+{
+	struct rte_tailq_elem *temp;
+
+	TAILQ_FOREACH(temp, &rte_tailq_elem_head, next) {
+		if (!strncmp(t->name, temp->name, sizeof(temp->name)))
+			return -1;
+	}
+
+	TAILQ_INSERT_TAIL(&rte_tailq_elem_head, t, next);
+	return 0;
+}
+
+static void
+rte_eal_tailq_update(struct rte_tailq_elem *t)
+{
+	if (rte_eal_process_type() == RTE_PROC_PRIMARY) {
+		/* primary process is the only one that creates */
+		t->head = rte_eal_tailq_create(t->name);
+	} else {
+		t->head = rte_eal_tailq_lookup(t->name);
+	}
+}
+
+int
+rte_eal_tailq_register(struct rte_tailq_elem *t)
+{
+	if (rte_eal_tailq_local_register(t) < 0) {
+		rte_log(RTE_LOG_ERR, RTE_LOGTYPE_EAL,
+			"%s tailq is already registered\n", t->name);
+		goto error;
+	}
+
+	/* if a register happens after rte_eal_tailqs_init(), then we can update
+	 * tailq head */
+	if (rte_tailqs_count >= 0) {
+		rte_eal_tailq_update(t);
+		if (t->head == NULL) {
+			rte_log(RTE_LOG_ERR, RTE_LOGTYPE_EAL,
+				"Cannot initialize tailq: %s\n", t->name);
+			TAILQ_REMOVE(&rte_tailq_elem_head, t, next);
+			goto error;
+		}
+	}
+
+	return 0;
+
+error:
+	t->head = NULL;
+	return -1;
+}
+
 int
 rte_eal_tailqs_init(void)
 {
 	unsigned i;
 	struct rte_mem_config *mcfg = NULL;
+	struct rte_tailq_elem *t;
 
 	RTE_BUILD_BUG_ON(RTE_MAX_TAILQ < RTE_TAILQ_NUM);
 
 	if (rte_eal_process_type() == RTE_PROC_PRIMARY) {
 		mcfg = rte_eal_get_configuration()->mem_config;
-		for (i = 0; i < RTE_MAX_TAILQ; i++)
+		for (i = 0; i < RTE_TAILQ_NUM; i++)
 			TAILQ_INIT(&mcfg->tailq_head[i].tailq_head);
 	}
 
+	/* mark those static entries as already taken */
+	rte_tailqs_count = RTE_TAILQ_NUM;
+
+	TAILQ_FOREACH(t, &rte_tailq_elem_head, next) {
+		/* second part of register job for "early" tailqs, see
+		 * rte_eal_tailq_register and EAL_REGISTER_TAILQ */
+		rte_eal_tailq_update(t);
+		if (t->head == NULL) {
+			rte_log(RTE_LOG_ERR, RTE_LOGTYPE_EAL,
+				"Cannot initialize tailq: %s\n", t->name);
+			/* no need to TAILQ_REMOVE, we are going to panic in
+			 * rte_eal_init() */
+			goto fail;
+		}
+	}
+
 	return 0;
-}
 
+fail:
+	rte_dump_tailq(stderr);
+	return -1;
+}
diff --git a/lib/librte_eal/common/include/rte_tailq.h b/lib/librte_eal/common/include/rte_tailq.h
index 6b7278c..df11183 100644
--- a/lib/librte_eal/common/include/rte_tailq.h
+++ b/lib/librte_eal/common/include/rte_tailq.h
@@ -46,6 +46,7 @@ extern "C" {
 
 #include <sys/queue.h>
 #include <stdio.h>
+#include <rte_debug.h>
 
 /** dummy structure type used by the rte_tailq APIs */
 struct rte_tailq_entry {
@@ -67,6 +68,17 @@ TAILQ_HEAD(rte_tailq_entry_head, rte_tailq_entry);
  */
 struct rte_tailq_head {
 	struct rte_tailq_entry_head tailq_head; /**< NOTE: must be first element */
+	char name[RTE_TAILQ_NAMESIZE];
+};
+
+struct rte_tailq_elem {
+	/**
+	 * Reference to head in shared mem, updated at init time by
+	 * rte_eal_tailqs_init()
+	 */
+	struct rte_tailq_head *head;
+	TAILQ_ENTRY(rte_tailq_elem) next;
+	const char name[RTE_TAILQ_NAMESIZE];
 };
 
 /**
@@ -151,6 +163,32 @@ struct rte_tailq_head *rte_eal_tailq_lookup(const char *name);
  */
 struct rte_tailq_head *rte_eal_tailq_lookup_by_idx(const unsigned idx);
 
+/**
+ * Register a tail queue.
+ *
+ * Register a tail queue from shared memory.
+ * This function is mainly used by EAL_REGISTER_TAILQ macro which is used to
+ * register tailq from the different dpdk libraries. Since this macro is a
+ * constructor, the function has no access to dpdk shared memory, so the
+ * registered tailq can not be used before call to rte_eal_init() which calls
+ * rte_eal_tailqs_init().
+ *
+ * @param t
+ *   The tailq element which contains the name of the tailq you want to
+ *   create (/retrieve when in secondary process).
+ * @return
+ *   0 on success or -1 in case of an error.
+ */
+int rte_eal_tailq_register(struct rte_tailq_elem *t);
+
+#define EAL_REGISTER_TAILQ(t) \
+void tailqinitfn_ ##t(void); \
+void __attribute__((constructor, used)) tailqinitfn_ ##t(void) \
+{ \
+	if (rte_eal_tailq_register(&t) < 0) \
+		rte_panic("Cannot initialize tailq: %s\n", t.name); \
+}
+
 #ifdef __cplusplus
 }
 #endif
diff --git a/lib/librte_eal/linuxapp/eal/rte_eal_version.map b/lib/librte_eal/linuxapp/eal/rte_eal_version.map
index a1ba203..3db5856 100644
--- a/lib/librte_eal/linuxapp/eal/rte_eal_version.map
+++ b/lib/librte_eal/linuxapp/eal/rte_eal_version.map
@@ -49,6 +49,7 @@ DPDK_2.0 {
 	rte_eal_remote_launch;
 	rte_eal_tailq_lookup;
 	rte_eal_tailq_lookup_by_idx;
+	rte_eal_tailq_register;
 	rte_eal_vdev_init;
 	rte_eal_vdev_uninit;
 	rte_eal_wait_lcore;
-- 
1.7.10.4



More information about the dev mailing list