From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: Received: from mail-we0-f174.google.com (mail-we0-f174.google.com [74.125.82.174]) by dpdk.org (Postfix) with ESMTP id 9F6839A88 for ; Wed, 4 Mar 2015 22:50:26 +0100 (CET) Received: by wesk11 with SMTP id k11so49128480wes.11 for ; Wed, 04 Mar 2015 13:50:26 -0800 (PST) X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20130820; h=x-gm-message-state:from:to:subject:date:message-id:in-reply-to :references; bh=RhfzNAT+PB/nkvZU44eBEvekyUaQkR9UGLrDLcvxoYE=; b=kRakYhGeqc60i0pMiGxVxL1D1k9+/UMMzDg/IcEh0xDqptQSFA/erh+s+eXLqtNZX0 SZpg0pPCNR8wfAVlVYAgjw0OT1OJ30yRazXRwAcsARlQ14O6IrLxIlCuhIV6zNoCZcnq 6II2cPR8rjlRoJIQrF4wbsDH/5BhmU+na/0iwE+X11AyAnShO+EwLDjgH0KWJGCc2mqT T8CfZAfMbUu9CWj8yllLxpCPJEOM5Djggm+xa86lJnYFBZkXt55X82e/L0+glxqvPNyt qsU6rVEEt9++UHqylOEP40n8gLkEo/hfvlfM8K2+MQj3sIsEY0Y4kS1KWB4d0MPN0Wiu W+Kg== X-Gm-Message-State: ALoCoQmecwDESh15WoonnlvMDyqEZQMUZxjUoph5G++l3wOS8N51mGFY0yhv7ElNfgk7u1vq5zje X-Received: by 10.181.27.201 with SMTP id ji9mr29817528wid.20.1425505826542; Wed, 04 Mar 2015 13:50:26 -0800 (PST) Received: from alcyon.dev.6wind.com (6wind.net2.nerim.net. [213.41.180.237]) by mx.google.com with ESMTPSA id bf8sm6037947wjb.37.2015.03.04.13.50.25 for (version=TLSv1.2 cipher=ECDHE-RSA-AES128-GCM-SHA256 bits=128/128); Wed, 04 Mar 2015 13:50:25 -0800 (PST) From: David Marchand To: dev@dpdk.org Date: Wed, 4 Mar 2015 22:50:07 +0100 Message-Id: <1425505810-9269-8-git-send-email-david.marchand@6wind.com> X-Mailer: git-send-email 1.7.10.4 In-Reply-To: <1425505810-9269-1-git-send-email-david.marchand@6wind.com> References: <1425505810-9269-1-git-send-email-david.marchand@6wind.com> Subject: [dpdk-dev] [PATCH 07/10] tailq: introduce dynamic register system X-BeenThere: dev@dpdk.org X-Mailman-Version: 2.1.15 Precedence: list List-Id: patches and discussions about DPDK List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , X-List-Received-Date: Wed, 04 Mar 2015 21:50:26 -0000 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 --- 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 #include #include +#include #include #include @@ -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 #include #include +#include #include "eal_private.h" @@ -62,6 +63,14 @@ const char* rte_tailq_names[RTE_MAX_TAILQ] = { #include }; +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 #include +#include /** 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