#include <stdio.h>
#include <stdint.h>
#include <stdarg.h>
+#include <string.h>
#include <errno.h>
#include <sys/queue.h>
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;
}
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)
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");
test_tailq(void)
{
int ret = 0;
+ ret |= test_tailq_early();
ret |= test_tailq_create();
ret |= test_tailq_lookup();
return ret;
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;
#include <rte_branch_prediction.h>
#include <rte_log.h>
#include <rte_string_fns.h>
+#include <rte_debug.h>
#include "eal_private.h"
#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)
{
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];
}
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;
+}
#include <sys/queue.h>
#include <stdio.h>
+#include <rte_debug.h>
/** dummy structure type used by the rte_tailq APIs */
struct 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];
};
/**
*/
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
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;