Re: [PATCH v4] tools: usb: aio example applications

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



On Mon, Feb 10 2014, Robert Baldyga wrote:
> This patch adds two example applications showing usage of Asynchronous I/O API
> of FunctionFS. First one (aio_simple) is simple example of bidirectional data
> transfer. Second one (aio_multibuff) shows multi-buffer data transfer, which
> may to be used in high performance applications.
>
> Both examples contains userspace applications for device and for host.
> It needs libaio library on the device, and libusb library on host.
>
> Signed-off-by: Robert Baldyga <r.baldyga@xxxxxxxxxxx>
> ---
>
> Hello,
>
> This is fourth version of patch adding examples of use AIO API of FunctionFS.
>
> In this version I have solved active polling problem replaceing it with select
> function. It's possible because AIO API supports eventfd notification when
> events are available to read. Using selecti() on ep0 file need wait_queue
> support in its poll funcion. It's done in v5 of my patchset adding AIO support
> to FunctionFS.

Thanks, this looks much better!

> I have also fixed error handling in host application, and add some
> modifications to get rid of duplicated code.
>
>  tools/usb/aio_multibuff/device_app/aio_multibuff.c |  335 ++++++++++++++++++++
>  tools/usb/aio_multibuff/host_app/Makefile          |   13 +
>  tools/usb/aio_multibuff/host_app/test.c            |  146 +++++++++
>  tools/usb/aio_simple/device_app/aio_simple.c       |  325 +++++++++++++++++++
>  tools/usb/aio_simple/host_app/Makefile             |   13 +
>  tools/usb/aio_simple/host_app/test.c               |  148 +++++++++

Perhaps a single
  tools/usb/ffs-aio-example
directory would be better?  It's not really clear what “aio_simple”
means and that it relates to FFS.

> diff --git a/tools/usb/aio_multibuff/device_app/aio_multibuff.c b/tools/usb/aio_multibuff/device_app/aio_multibuff.c

> +int main(int argc, char *argv[])
> +{
> +	int ret;
> +	unsigned i, j;
> +	char *ep_path;
> +
> +	int ep0, ep1;
> +
> +	io_context_t ctx;
> +
> +	int evfd;
> +	fd_set rfds;
> +
> +	struct io_buffer iobuf[2];
> +	int actual;
> +	bool ready;
> +
> +	if (argc != 2) {
> +		printf("ffs directory not specified!\n");
> +		return 1;
> +	}
> +
> +	ep_path = malloc(strlen(argv[1]) + 4 /* "/ep#" */ + 1 /* '\0' */);
> +	if (!ep_path) {
> +		perror("malloc");
> +		return 1;
> +	}
> +
> +	/* open endpoint files */
> +	sprintf(ep_path, "%s/ep0", argv[1]);
> +	ep0 = open(ep_path, O_RDWR);
> +	if (ep0 < 0) {
> +		perror("unable to open ep0");
> +		return 1;
> +	}
> +	if (write(ep0, &descriptors, sizeof(descriptors)) < 0) {
> +		perror("unable do write descriptors");
> +		return 1;
> +	}
> +	if (write(ep0, &strings, sizeof(strings)) < 0) {
> +		perror("unable to write strings");
> +		return 1;
> +	}
> +	sprintf(ep_path, "%s/ep1", argv[1]);
> +	ep1 = open(ep_path, O_RDWR);
> +	if (ep1 < 0) {
> +		perror("unable to open ep1");
> +		return 1;
> +	}
> +
> +	free(ep_path);
> +
> +	memset(&ctx, 0, sizeof(ctx));
> +	/* setup aio context to handle up to AIO_MAX requests */
> +	if (io_setup(AIO_MAX, &ctx) < 0) {
> +		perror("unable to setup aio");
> +		return 1;
> +	}
> +
> +	evfd = eventfd(0, 0);
> +	if (evfd < 0) {
> +		perror("unable to open eventfd");
> +		return 1;
> +	}
> +
> +	for (i = 0; i < sizeof(iobuf)/sizeof(*iobuf); ++i)
> +		init_bufs(&iobuf[i], BUFS_MAX, BUF_LEN);
> +
> +	while (1) {
> +		FD_ZERO(&rfds);
> +		FD_SET(ep0, &rfds);
> +		FD_SET(evfd, &rfds);
> +
> +		ret = select(((ep0 > evfd) ? ep0 : evfd)+1,
> +			     &rfds, NULL, NULL, NULL);
> +		if (ret < 0)
> +			continue;

Perhaps 

+		if (ret < 0) {
+			if (errno == EINTR)
+				continue;
+			perror("select");
+			return 1;
+		}

or something similar.

> +
> +		if (FD_ISSET(ep0, &rfds))
> +			handle_ep0(ep0, &ready);
> +
> +		/* we are waiting for function ENABLE */
> +		if (!ready)
> +			continue;
> +
> +		/*
> +		 * when we're preparing new data to submit,
> +		 * second buffer being transmitted
> +		 */
> +		for (i = 0; i < sizeof(iobuf)/sizeof(*iobuf); ++i) {
> +			if (iobuf[i].requested)
> +				continue;
> +			 /* if all req's from iocb1 completed */

“1” in the comment is not needed now, i.e. it should be:

+			 /* if all reqs from iocb completed */

> +			actual = (i+1)%(sizeof(iobuf)/sizeof(*iobuf));

I'm confused.  Why is actual set here?  I think it should be set to 0 at
the beginning and changed when events are consumed.  Is there anything
I'm missing?

> +			/* prepare requests */
> +			for (j = 0; j < iobuf[i].cnt; ++j) {
> +				io_prep_pwrite(iobuf[i].iocb[j], ep1,
> +					       iobuf[i].buf[j],
> +					       iobuf[i].len, 0);
> +				/* enable eventfd notification */
> +				iobuf[i].iocb[j]->u.c.flags |= IOCB_FLAG_RESFD;
> +				iobuf[i].iocb[j]->u.c.resfd = evfd;
> +			}
> +			/* submit table of requests */
> +			ret = io_submit(ctx, iobuf[i].cnt, iobuf[i].iocb);
> +			if (ret >= 0) {
> +				iobuf[i].requested = ret;
> +				printf("submit: %d requests buf: %d\n", ret, i);
> +			} else
> +				perror("unable to submit reqests");

I would put body of the for loop in a separate function, but that's up
to you.

> +		}
> +		/* if something was submitted we wait for event */
> +
> +		if (FD_ISSET(evfd, &rfds)) {

Perhaps

+		if (!FD_ISSET(evfd, &rfds))
+			continue;

to save indention level later on:

> +			struct io_event e;
> +			/* we wait for one event */
> +			ret = io_getevents(ctx, 1, 1, &e, NULL);
> +			if (ret > 0) /* if we got event */
> +				iobuf[actual].requested--;

Again, I'm a bit confused here.  Don't you have to read() from evfd?
Otherwise the next select() will return immediately.  I think the whole
thing should be something like:

+			struct io_event e;
+			struct timespec timeout = { 0, 0 };
+			char buffer[8];
+			/* consume eventfd notification */
+			if (read(evfd, buffer, 8) < 2) {
+				perror("eventfd: read");
+				return -1;
+			}
+			/* consume IO events */
+			for (;;) {
+				ret = io_getevents(ctx, 1, 1, &e, &timeout);
+				if (ret <= 0)
+					break;
+				if (!iobuf[actual].requested)
+					actual = (actual + 1) %
+						(sizeof(iobuf)/sizeof(*iobuf));
+				iobuf[actual].requested--;
+			}

> +		}
> +	}
> +
> +	/* free resources */
> +
> +	for (i = 0; i < sizeof(iobuf)/sizeof(*iobuf); ++i)
> +		delete_bufs(&iobuf[i]);
> +	io_destroy(ctx);
> +
> +	close(ep1);
> +	close(ep0);
> +
> +	return 0;
> +}

-- 
Best regards,                                         _     _
.o. | Liege of Serenely Enlightened Majesty of      o' \,=./ `o
..o | Computer Science,  Michał “mina86” Nazarewicz    (o o)
ooo +--<mpn@xxxxxxxxxx>--<xmpp:mina86@xxxxxxxxxx>--ooO--(_)--Ooo--

Attachment: signature.asc
Description: PGP signature


[Index of Archives]     [Linux Media]     [Linux Input]     [Linux Audio Users]     [Yosemite News]     [Linux Kernel]     [Linux SCSI]     [Old Linux USB Devel Archive]

  Powered by Linux