ACK: [PATCH 5/6] pipeio: Add fwts_pipe_readwrite

Alex Hung alex.hung at canonical.com
Wed Apr 27 04:31:50 UTC 2016


On 2016-04-22 01:41 PM, Jeremy Kerr wrote:
> This change adds a function to process input & output data of a process
> opened by fwts_pipe_open_rw(). We add support for the input file
> descriptor, and add poll() to allow reads & writes to the child process
> (and use non-blocking IO on the file descriptors to make this possible).
>
> We then implement the existing fwts_pipe_read() as a base-case of this
> new function, by not providing input data to write.
>
> Signed-off-by: Jeremy Kerr <jk at ozlabs.org>
> ---
>   src/lib/include/fwts_pipeio.h |   3 ++
>   src/lib/src/fwts_pipeio.c     | 107 ++++++++++++++++++++++++++++++++++--------
>   2 files changed, 90 insertions(+), 20 deletions(-)
>
> diff --git a/src/lib/include/fwts_pipeio.h b/src/lib/include/fwts_pipeio.h
> index e2d498a..7f9aaf4 100644
> --- a/src/lib/include/fwts_pipeio.h
> +++ b/src/lib/include/fwts_pipeio.h
> @@ -34,6 +34,9 @@ int   fwts_pipe_open_ro(const char *command, pid_t *childpid, int *fd);
>   int   fwts_pipe_open_rw(const char *command, pid_t *childpid, int *in_fd,
>   		int *out_fd);
>   int   fwts_pipe_read(const int fd, char **out_buf, ssize_t *out_len);
> +int   fwts_pipe_readwrite(
> +		const int in_fd, const char *in_buf, const size_t in_len,
> +		const int out_fd, char **out_buf, ssize_t *out_len);
>   int   fwts_pipe_close(const int fd, const pid_t pid);
>   int   fwts_pipe_exec(const char *command, fwts_list **list, int *status);
>   int   fwts_exec(const char *command, int *status);
> diff --git a/src/lib/src/fwts_pipeio.c b/src/lib/src/fwts_pipeio.c
> index bb51515..a741477 100644
> --- a/src/lib/src/fwts_pipeio.c
> +++ b/src/lib/src/fwts_pipeio.c
> @@ -32,6 +32,7 @@
>   #include <paths.h>
>
>   #include <sys/param.h>
> +#include <sys/poll.h>
>   #include <sys/types.h>
>   #include <sys/wait.h>
>   #include <errno.h>
> @@ -128,51 +129,117 @@ int fwts_pipe_open_ro(const char *command, pid_t *childpid, int *fd)
>   	return fwts_pipe_open_rw(command, childpid, NULL, fd);
>   }
>
> +static int fwts_pipeio_set_nonblock(const int fd)
> +{
> +	int flags;
> +	if (fd < 0)
> +		return 0;
> +	flags = fcntl(fd, F_GETFL, 0);
> +	flags |= O_NONBLOCK;
> +	return !!fcntl(fd, F_SETFL, flags);
> +}
> +
>   /*
> - *  fwts_pipe_read()
> - *	read output from fwts_pipe_open_ro(), *out_buf is populated with
> - *	returned data (allocated, must be free()-ed after use), and length in
> - *	*out_len.
> + *  fwts_pipe_readwrite()
> + *	send input to and read output from fwts_pipe_open_rw(), in_len bytes
> + *	of in_buf are written to the pipe, and data is read into *out_buf,
> + *	*out_len indicating output length. *out_buf is allocated, and
> + *	must be free()-ed after use.
>    *	Returns non-zero on failure.
>    */
> -int fwts_pipe_read(const int fd, char **out_buf, ssize_t *out_len)
> +int fwts_pipe_readwrite(
> +		const int in_fd, const char *in_buf, const size_t in_len,
> +		const int out_fd, char **out_buf, ssize_t *out_len)
>   {
> +	struct pollfd pollfds[2];
> +	size_t in_size = in_len;
> +	ssize_t out_size = 0;
>   	char *ptr = NULL;
>   	char buffer[8192];
> -	ssize_t size = 0;
> +
>   	*out_len = 0;
>
> -	ptr = NULL;
> +	pollfds[0].fd = out_fd;
> +	pollfds[0].events = POLLIN;
> +	pollfds[1].fd = in_fd;
> +	pollfds[1].events = POLLOUT;
> +
> +	/* we need non-blocking IO */
> +	if (fwts_pipeio_set_nonblock(in_fd))
> +		return -1;
> +
> +	if (fwts_pipeio_set_nonblock(out_fd))
> +		return -1;
>
>   	for (;;) {
> -		ssize_t n = read(fd, buffer, sizeof(buffer));
> +		ssize_t n;
>   		char *tmp;
> +		int rc;
> +
> +		if (in_size == 0 || in_fd < 0 || in_buf == NULL)
> +			pollfds[1].events = 0;
>
> -		if (n == 0)
> +		rc = poll(pollfds, 2, -1);
> +		if (rc < 0)
>   			break;
> -		if (n < 0) {
> -			if (errno != EINTR && errno != EAGAIN) {
> +
> +		if (pollfds[0].revents) {
> +			n = read(out_fd, buffer, sizeof(buffer));
> +
> +			if (n == 0)
> +				break;
> +			if (n < 0) {
> +				if (errno != EINTR && errno != EAGAIN) {
> +					free(ptr);
> +					return -1;
> +				}
> +				continue;
> +			}
> +
> +			if ((tmp = realloc(ptr, out_size + n + 1)) == NULL) {
>   				free(ptr);
>   				return -1;
>   			}
> -			continue;
> +			ptr = tmp;
> +			memcpy(ptr + out_size, buffer, n);
> +			out_size += n;
> +			*(ptr+out_size) = 0;
>   		}
>
> -		if ((tmp = realloc(ptr, size + n + 1)) == NULL) {
> -			free(ptr);
> -			return -1;
> +		if (pollfds[1].revents) {
> +			n = write(in_fd, in_buf, in_size);
> +
> +			if (n < 0) {
> +				if (errno != EINTR && errno != EAGAIN) {
> +					free(ptr);
> +					return -1;
> +				}
> +				continue;
> +			}
> +
> +			in_buf += n;
> +			in_size -= n;
>   		}
> -		ptr = tmp;
> -		memcpy(ptr + size, buffer, n);
> -		size += n;
> -		*(ptr+size) = 0;
> +
>   	}
> -	*out_len = size;
> +
> +	*out_len = out_size;
>   	*out_buf = ptr;
>   	return 0;
>   }
>
>   /*
> + *  fwts_pipe_read()
> + *	read output from fwts_pipe_open_ro(), *length is
> + *	set to the number of chars read and we return
> + *	a buffer of read data.
> + */
> +int fwts_pipe_read(const int fd, char **out_buf, ssize_t *out_len)
> +{
> +	return fwts_pipe_readwrite(-1, NULL, 0, fd, out_buf, out_len);
> +}
> +
> +/*
>    *  fwts_pipe_close()
>    *	close fd, wait for child of given pid to exit
>    */
>

Acked-by: Alex Hung <alex.hung at canonical.com>



More information about the fwts-devel mailing list