[dpdk-dev] [PATCH v11 11/25] eal/dev: implement device iteration

Shreyansh Jain shreyansh.jain at nxp.com
Thu Jul 12 12:58:27 CEST 2018


On Thursday 12 July 2018 03:15 AM, Gaetan Rivet wrote:
> Use the iteration hooks in the abstraction layers to perform the
> requested filtering on the internal device lists.
> 
> Signed-off-by: Gaetan Rivet <gaetan.rivet at 6wind.com>
> ---
>   lib/librte_eal/common/eal_common_dev.c  | 168 ++++++++++++++++++++++++
>   lib/librte_eal/common/include/rte_dev.h |  26 ++++
>   lib/librte_eal/rte_eal_version.map      |   1 +
>   3 files changed, 195 insertions(+)
> 
> diff --git a/lib/librte_eal/common/eal_common_dev.c b/lib/librte_eal/common/eal_common_dev.c
> index 63e329bd8..b78845f02 100644
> --- a/lib/librte_eal/common/eal_common_dev.c
> +++ b/lib/librte_eal/common/eal_common_dev.c
> @@ -45,6 +45,28 @@ static struct dev_event_cb_list dev_event_cbs;
>   /* spinlock for device callbacks */
>   static rte_spinlock_t dev_event_lock = RTE_SPINLOCK_INITIALIZER;
>   
> +struct dev_next_ctx {
> +	struct rte_dev_iterator *it;
> +	const char *bus_str;
> +	const char *cls_str;
> +};
> +
> +#define CTX(it, bus_str, cls_str) \
> +	(&(const struct dev_next_ctx){ \
> +		.it = it, \
> +		.bus_str = bus_str, \
> +		.cls_str = cls_str, \
> +	})
> +
> +#define ITCTX(ptr) \
> +	(((struct dev_next_ctx *)(intptr_t)ptr)->it)
> +
> +#define BUSCTX(ptr) \
> +	(((struct dev_next_ctx *)(intptr_t)ptr)->bus_str)
> +
> +#define CLSCTX(ptr) \
> +	(((struct dev_next_ctx *)(intptr_t)ptr)->cls_str)
> +
>   static int cmp_detached_dev_name(const struct rte_device *dev,
>   	const void *_name)
>   {
> @@ -398,3 +420,149 @@ rte_dev_iterator_init(struct rte_dev_iterator *it,
>   get_out:
>   	return -rte_errno;
>   }
> +
> +static char *
> +dev_str_sane_copy(const char *str)
> +{
> +	size_t end;
> +	char *copy;
> +
> +	end = strcspn(str, ",/");
> +	if (str[end] == ',') {
> +		copy = strdup(&str[end + 1]);
> +	} else {
> +		/* '/' or '\0' */
> +		copy = strdup("");
> +	}

Though it doesn't change anything functionally, if you can separate 
blocks of if-else with new lines, it really makes it easier to read.
Like here...

> +	if (copy == NULL) {
> +		rte_errno = ENOMEM;
> +	} else {
> +		char *slash;
> +
> +		slash = strchr(copy, '/');
> +		if (slash != NULL)
> +			slash[0] = '\0';
> +	}
> +	return copy;
> +}
> +
> +static int
> +class_next_dev_cmp(const struct rte_class *cls,
> +		   const void *ctx)
> +{
> +	struct rte_dev_iterator *it;
> +	const char *cls_str = NULL;
> +	void *dev;
> +
> +	if (cls->dev_iterate == NULL)
> +		return 1;
> +	it = ITCTX(ctx);
> +	cls_str = CLSCTX(ctx);
> +	dev = it->class_device;
> +	/* it->cls_str != NULL means a class
> +	 * was specified in the devstr.
> +	 */
> +	if (it->cls_str != NULL && cls != it->cls)
> +		return 1;
> +	/* If an error occurred previously,
> +	 * no need to test further.
> +	 */
> +	if (rte_errno != 0)
> +		return -1;

I am guessing here by '..error occurred previously..' you mean 
sane_copy. If so, why wait until this point to return? Anyway the caller 
(rte_bus_find, probably) would only look for '0' or non-zero.

> +	dev = cls->dev_iterate(dev, cls_str, it);
> +	it->class_device = dev;
> +	return dev == NULL;
> +}
> +
> +static int
> +bus_next_dev_cmp(const struct rte_bus *bus,
> +		 const void *ctx)
> +{
> +	struct rte_device *dev = NULL;
> +	struct rte_class *cls = NULL;
> +	struct rte_dev_iterator *it;
> +	const char *bus_str = NULL;
> +
> +	if (bus->dev_iterate == NULL)
> +		return 1;
> +	it = ITCTX(ctx);
> +	bus_str = BUSCTX(ctx);
> +	dev = it->device;
> +	/* it->bus_str != NULL means a bus
> +	 * was specified in the devstr.
> +	 */
> +	if (it->bus_str != NULL && bus != it->bus)
> +		return 1;
> +	/* If an error occurred previously,
> +	 * no need to test further.
> +	 */
> +	if (rte_errno != 0)
> +		return -1;
> +	if (it->cls_str == NULL) {
> +		dev = bus->dev_iterate(dev, bus_str, it);
> +		goto end;

This is slightly confusing. If it->cls_str == NULL, you do 
bus->dev_iterate... but

> +	}
> +	/* cls_str != NULL */
> +	if (dev == NULL) {
> +next_dev_on_bus:
> +		dev = bus->dev_iterate(dev, bus_str, it);

When cls_str!=NULL, you still do bus->dev_iterate...
So, maybe they are OR case resulting in check of dev==NULL and return 
(as being done right now by jumping to out)...?

And, how can bus iterate over a 'null' device?

> +		it->device = dev;
> +	}
> +	if (dev == NULL)
> +		return 1;

Maybe, this check should move in the if(dev==NULL) above - that way, it 
can in path of 'next_dev_on_bus' yet do the same as function as its 
current location.

> +	if (it->cls != NULL)

In what case would (it->cls_str == NULL) but (it->cls != NULL)?

> +		cls = TAILQ_PREV(it->cls, rte_class_list, next);
> +	cls = rte_class_find(cls, class_next_dev_cmp, ctx);
> +	if (cls != NULL) {
> +		it->cls = cls;
> +		goto end;
> +	}
> +	goto next_dev_on_bus;

Maybe I have completely mixed your intention of this function. So, if 
you still find the above comments naive - maybe you can tell me what you 
are attempting here?
Is it: find next bus and stop if no class specified. find next class as 
well, iff that too was specified?

Reason I am confused is that bus_next_dev_cmp attempts to compare both - 
bus and class, yet class_next_dev_cmp simply stops by comparing class only.

> +end:
> +	it->device = dev;
> +	return dev == NULL;
> +}

A new line should be added here - start of a new function.

> +__rte_experimental
> +struct rte_device *
> +rte_dev_iterator_next(struct rte_dev_iterator *it)
> +{
> +	struct rte_bus *bus = NULL;
> +	int old_errno = rte_errno;
> +	char *bus_str = NULL;
> +	char *cls_str = NULL;
> +
> +	rte_errno = 0;
> +	if (it->bus_str == NULL && it->cls_str == NULL) {
> +		/* Invalid iterator. */
> +		rte_errno = EINVAL;
> +		return NULL;
> +	}
> +	if (it->bus != NULL)
> +		bus = TAILQ_PREV(it->bus, rte_bus_list, next);
> +	if (it->bus_str != NULL) {
> +		bus_str = dev_str_sane_copy(it->bus_str);
> +		if (bus_str == NULL)
> +			goto out;
> +	}
> +	if (it->cls_str != NULL) {
> +		cls_str = dev_str_sane_copy(it->cls_str);
> +		if (cls_str == NULL)
> +			goto out;
> +	}
> +	while ((bus = rte_bus_find(bus, bus_next_dev_cmp,
> +				   CTX(it, bus_str, cls_str)))) {
> +		if (it->device != NULL) {
> +			it->bus = bus;
> +			goto out;
> +		}
> +		if (it->bus_str != NULL ||
> +		    rte_errno != 0)
> +			break;
> +	}
> +	if (rte_errno == 0)
> +		rte_errno = old_errno;
> +out:
> +	free(bus_str);
> +	free(cls_str);
> +	return it->device;
> +}
> diff --git a/lib/librte_eal/common/include/rte_dev.h b/lib/librte_eal/common/include/rte_dev.h
> index fdc812ff8..8638a2bbd 100644
> --- a/lib/librte_eal/common/include/rte_dev.h
> +++ b/lib/librte_eal/common/include/rte_dev.h
> @@ -355,6 +355,32 @@ __rte_experimental
>   int
>   rte_dev_iterator_init(struct rte_dev_iterator *it, const char *str);
>   
> +/**
> + * Iterates on a device iterator.
> + *
> + * Generates a new rte_device handle corresponding to the next element
> + * in the list described in comprehension by the iterator.
> + *
> + * The next object is returned, and the iterator is updated.
> + *
> + * @param it
> + *   Device iterator handle.
> + *
> + * @return
> + *   An rte_device handle if found.
> + *   NULL if an error occurred (rte_errno is set).
> + *   NULL if no device could be found (rte_errno is not set).
> + */
> +__rte_experimental
> +struct rte_device *
> +rte_dev_iterator_next(struct rte_dev_iterator *it);
> +
> +#define RTE_DEV_FOREACH(dev, devstr, it) \
> +	for (rte_dev_iterator_init(it, devstr), \
> +	     dev = rte_dev_iterator_next(it); \
> +	     dev != NULL; \
> +	     dev = rte_dev_iterator_next(it))
> +
>   #ifdef __cplusplus
>   }
>   #endif
> diff --git a/lib/librte_eal/rte_eal_version.map b/lib/librte_eal/rte_eal_version.map
> index ac04120d6..4cd5ab3df 100644
> --- a/lib/librte_eal/rte_eal_version.map
> +++ b/lib/librte_eal/rte_eal_version.map
> @@ -252,6 +252,7 @@ EXPERIMENTAL {
>   	rte_dev_event_monitor_start;
>   	rte_dev_event_monitor_stop;
>   	rte_dev_iterator_init;
> +	rte_dev_iterator_next;
>   	rte_devargs_add;
>   	rte_devargs_dump;
>   	rte_devargs_insert;
> 



More information about the dev mailing list