Re: [PATCH v5] libtracefs: Add APIs for data streaming

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

 



On Mon, 28 Jun 2021 11:58:10 +0300
Yordan Karadzhov <y.karadz@xxxxxxxxx> wrote:
> > +
> > +static ssize_t read_trace_pipe(bool *keep_going, int in_fd, int out_fd)
> > +{
> > +	char buf[BUFSIZ];
> > +	ssize_t bread = 0;
> > +	int ret;
> > +
> > +	do {
> > +		ret = read(in_fd, buf, BUFSIZ);
> > +		if (ret > 0) {
> > +			ret = write(STDOUT_FILENO, buf, ret);  
> 
> this should be

Doh! I know I was hard coding that in some places for debugging, and
that may have been me not cleaning it up. Thanks, will fix.


> 			ret = write(in_fd, buf, ret);
> 
> > +			if (ret > 0)
> > +				bread += ret;
> > +		}
> > +	} while (ret > 0 && *(volatile bool *)keep_going);
> > +  
> 
> Nit: When looping you check the value of 'ret' 3 times.
>       The same can be done with only 2 checks.
> 
> 	while (*(volatile bool *)keep_going) {
> 		ret = read(in_fd, buf, BUFSIZ);
> 		if (ret <= 0)
> 			break;
> 
> 		ret = write(out_fd, buf, ret);
> 		if (ret <= 0)
> 			break;
> 
> 		bread += ret;
> 	}

Nice, I got you thinking about optimizations ;-)

I'll update it.


> 
> > +	if (ret < 0 && (errno == EAGAIN || errno == EINTR))
> > +		ret = 0;
> > +
> > +	return ret < 0 ? ret : bread;
> > +}
> > +
> > +static bool top_pipe_keep_going;
> > +
> > +/**
> > + * tracefs_trace_pipe_stream - redirect the stream of trace data to an output
> > + * file. The "splice" system call is used to moves the data without copying
> > + * between kernel address space and user address space. The user can interrupt
> > + * the streaming of the data by pressing Ctrl-c.
> > + * @fd: The file descriptor of the output file.
> > + * @instance: ftrace instance, can be NULL for top tracing instance.
> > + * @flags: flags to be passed to the "splice" system call.
> > + *
> > + * Returns -1 in case of an error or number of bytes transferred otherwise.
> > + */
> > +ssize_t tracefs_trace_pipe_stream(int fd, struct tracefs_instance *instance,
> > +				 int flags)
> > +{
> > +	bool *keep_going = instance ? &instance->pipe_keep_going :
> > +				      &top_pipe_keep_going;
> > +	const char *file = "trace_pipe";
> > +	int brass[2], in_fd, ret = -1;
> > +	int oflags = flags & SPLICE_F_NONBLOCK ? O_NONBLOCK: 0;
> > +	off_t data_size;
> > +	ssize_t bread = 0;
> > +
> > +	(*(volatile bool *)keep_going) = true;
> > +
> > +	in_fd = tracefs_instance_file_open(instance, file, O_RDONLY | oflags);
> > +	if (in_fd < 0) {
> > +		tracefs_warning("Failed to open 'trace_pipe'.");
> > +		return ret;
> > +	}
> > +
> > +	if(pipe(brass) < 0) {
> > +		tracefs_warning("Failed to open pipe.");
> > +		goto close_file;
> > +	}
> > +
> > +	data_size = fcntl(brass[0], F_GETPIPE_SZ);
> > +	if (data_size <= 0) {
> > +		tracefs_warning("Failed to open pipe (size=0).");
> > +		goto close_all;
> > +	}
> > +
> > +	/* Test if the output is splice safe */
> > +	if (!splice_safe(fd, brass[0])) {
> > +		close(brass[0]);
> > +		close(brass[1]);
> > +		return read_trace_pipe(keep_going, in_fd, fd);  
> 
> we must close 'in_fd' before returning.

Good catch. I was planning on closing it in read_trace_pipe() and
forgot. I'll close it here.

> 
> > +	}
> > +
> > +	errno = 0;
> > +
> > +	while (*(volatile bool *)keep_going) {
> > +		ret = splice(in_fd, NULL,
> > +			     brass[1], NULL,
> > +			     data_size, flags);
> > +		if (ret < 0)
> > +			break;
> > +
> > +		ret = splice(brass[0], NULL,
> > +			     fd, NULL,
> > +			     data_size, flags);
> > +		if (ret < 0)
> > +			break;
> > +		bread += ret;
> > +	}
> > +
> > +	/*
> > +	 * Do not return error in the case when the "splice" system call
> > +	 * was interrupted by the user (pressing Ctrl-c).
> > +	 * Or if NONBLOCK was specified.
> > +	 */
> > +	if (!keep_going || errno == EAGAIN || errno == EINTR)
> > +		ret = 0;
> > +
> > + close_all:
> > +	close(brass[0]);
> > +	close(brass[1]);
> > + close_file:
> > +	close(in_fd);
> > +
> > +	return ret ? ret : bread;
> > +}
> > +
> > +/**
> > + * tracefs_trace_pipe_print - redirect the stream of trace data to "stdout".
> > + * The "splice" system call is used to moves the data without copying
> > + * between kernel address space and user address space.
> > + * @instance: ftrace instance, can be NULL for top tracing instance.
> > + *
> > + * Returns -1 in case of an error or number of bytes transferred otherwise.
> > + */
> > +
> > +ssize_t tracefs_trace_pipe_print(struct tracefs_instance *instance)
> > +{
> > +	return tracefs_trace_pipe_stream(STDOUT_FILENO, instance,
> > +					 SPLICE_F_NONBLOCK);
> > +}
> > +  
> 
> In fact I want to use this function in "blocking" mode. I would like to keep listening for new trace data until the user 
> presses 'Ctrl-c'. Can we make this function to take a second parameter that will be the splice flags?

Yeah, I was going to ask you if you wanted this to have flags too.

I was also thinking that we should use the O_ flags and not the
SPLICE_F_ flags, as splice is more niche, and O_ is POSIX. We can check
the flags and change them for splice inside these functions.

Are you OK with that?

-- Steve


> 
> Thanks a lot!
> Yordan
> 



[Index of Archives]     [Linux USB Development]     [Linux USB Development]     [Linux Audio Users]     [Yosemite Hiking]     [Linux Kernel]     [Linux SCSI]

  Powered by Linux