DPDK patches and discussions
 help / color / mirror / Atom feed
From: David Marchand <david.marchand@6wind.com>
To: dev@dpdk.org
Subject: [dpdk-dev] [PATCH 07/10] tailq: introduce dynamic register system
Date: Wed,  4 Mar 2015 22:50:07 +0100	[thread overview]
Message-ID: <1425505810-9269-8-git-send-email-david.marchand@6wind.com> (raw)
In-Reply-To: <1425505810-9269-1-git-send-email-david.marchand@6wind.com>

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@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

  parent reply	other threads:[~2015-03-04 21:50 UTC|newest]

Thread overview: 24+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2015-03-04 21:50 [dpdk-dev] [PATCH 00/10] eal: rte_tailq api cleanup David Marchand
2015-03-04 21:50 ` [dpdk-dev] [PATCH 01/10] eal: remove yet another remaining reference to pm David Marchand
2015-03-04 21:50 ` [dpdk-dev] [PATCH 02/10] pci: use lookup tailq api David Marchand
2015-03-04 21:50 ` [dpdk-dev] [PATCH 03/10] tailq: remove unneeded inclusion of rte_tailq.h David Marchand
2015-03-04 21:50 ` [dpdk-dev] [PATCH 04/10] tailq: use a single cast macro David Marchand
2015-03-04 21:50 ` [dpdk-dev] [PATCH 05/10] tailq: get rid of broken "reserve" api David Marchand
2015-03-04 21:50 ` [dpdk-dev] [PATCH 06/10] tailq: remove unused RTE_EAL_TAILQ_* macros David Marchand
2015-03-04 21:50 ` David Marchand [this message]
2015-03-04 21:50 ` [dpdk-dev] [PATCH 08/10] tailq: move to dynamic tailq David Marchand
2015-03-04 21:50 ` [dpdk-dev] [PATCH 09/10] tailq: remove static slots David Marchand
2015-03-04 21:50 ` [dpdk-dev] [PATCH 10/10] eal: no need for E_RTE_NO_TAILQ anymore David Marchand
2015-03-04 22:55 ` [dpdk-dev] [PATCH 00/10] eal: rte_tailq api cleanup Thomas Monjalon
2015-03-06  0:26 ` Neil Horman
2015-03-10 11:20   ` Thomas Monjalon
2015-03-11  7:44     ` Tetsuya Mukawa
2015-03-11  8:47       ` David Marchand
2015-03-11 17:28         ` David Marchand
2015-03-11 20:24           ` Mcnamara, John
2015-03-11 21:29             ` David Marchand
2015-03-11 22:25               ` Mcnamara, John
2015-03-12  2:05                 ` Tetsuya Mukawa
2015-03-12  2:12                   ` Tetsuya Mukawa
2015-03-12  5:44                   ` David Marchand
2015-03-12  8:38                     ` Liu, Yong

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=1425505810-9269-8-git-send-email-david.marchand@6wind.com \
    --to=david.marchand@6wind.com \
    --cc=dev@dpdk.org \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).