Messages in this thread | | | Date | Fri, 07 Jul 2006 09:07:03 +0200 | From | "Michael Kerrisk" <> | Subject | splice/tee bugs? |
| |
Hello Jens,
While editing and extending your draft man pages for tee(), splice(), vmsplice() I've been testing out the splice()/tee() calls using a modified version of the program you provided in the tee.2 manual page.
The most notable differences between my program and yours are:
* I print some debugging info to stderr.
* I don't pass SPLICE_F_NONBLOCK to tee().
I'm running this on kernel 2.6.17, using the following command line:
$ ls *.c | ktee r | wc
On different runs I see:
a) No output from ls through the pipeline:
tee returned 0 0 0 0
b) Very many instances of EAGAIN followed by expected results:
... EAGAIN EAGAIN EAGAIN EAGAIN EAGAIN EAGAIN tee returned 19 splice returned 19 tee returned 0 2 2 19
In some of these cases the elapsed time to run the command-line is 1 or 2 seconds in this case (instead of the more typical 0.05 seconds).
c) Occasionally the command line just hangs, producing no output. In this case I can't kill it with ^C or ^\. This is a hard-to-reproduce behaviour on my (x86) system, but I have seen it several times by now.
Assuming I'm not messing up with my test method, some observations:
Result a) seems to be occurring because tee() returns 0 if its in_fd is not yet "ready" to deliver data. Shouldn't tee() be blocking in this case? And should not 0 only be returned for EOF? on the input file descriptor?
If I uncomment the usleep() line in the program, this behavior does not occur--the program always just produces the expected output:
tee returned 19 splice returned 19 tee returned 0 2 2 19
For behaviour b) -- why does tee() give EAGAIN when I haven't specified SPLICE_F_NONBLOCK? (This is a philosophical question; I can see that there are code paths that lead to EAGAIN without SPLICE_F_NONBLOCK, but that seems confusing behaviour for userland.)
Behaviour c) hints of a bug in tee().
Your thoughts?
Cheers,
Michael
====
/* ktee.c */
#define _GNU_SOURCE #include <stdio.h> #include <stdlib.h> #include <unistd.h> #include <fcntl.h> #include <assert.h> #include <errno.h> #include <limits.h>
#if defined(__i386__) #define __NR_splice 313 #define __NR_tee 315 #else #error unsupported arch #endif
#define SPLICE_F_MOVE (0x01) /* move pages instead of copying */ #define SPLICE_F_NONBLOCK (0x02) /* don't block on the pipe splicing (but */ /* we may still block on the fd we splice */ /* from/to, of course */ #define SPLICE_F_MORE (0x04) /* expect more data */ #define SPLICE_F_GIFT (0x08) /* pages passed in are a gift */
static inline int splice(int fdin, loff_t *off_in, int fdout, loff_t *off_out, size_t len, unsigned int flags) { return syscall(__NR_splice, fdin, off_in, fdout, off_out, len, flags); }
static inline int tee(int fdin, int fdout, size_t len, unsigned int flags) { return syscall(__NR_tee, fdin, fdout, len, flags); }
int main(int argc, char *argv[]) { int fd; int len, slen;
assert(argc == 2);
fd = open(argv[1], O_WRONLY | O_CREAT | O_TRUNC, 0644); if (fd == -1) { perror("open"); exit(EXIT_FAILURE); }
//usleep(100000); do { /* * tee stdin to stdout. */ len = tee(STDIN_FILENO, STDOUT_FILENO, INT_MAX, 0);
if (len < 0) { if (errno == EAGAIN) { fprintf(stderr, "EAGAIN\n"); continue; } perror("tee"); exit(EXIT_FAILURE); } fprintf(stderr, "tee returned %ld\n", (long) len); if (len == 0) break;
/* * Consume stdin by splicing it to a file. */ while (len > 0) { slen = splice(STDIN_FILENO, NULL, fd, NULL, len, SPLICE_F_MOVE); if (slen < 0) { perror("splice"); break; } fprintf(stderr, "splice returned %ld\n", (long) slen); len -= slen; } } while (1);
close(fd); exit(EXIT_SUCCESS); }
-- Michael Kerrisk maintainer of Linux man pages Sections 2, 3, 4, 5, and 7
Want to help with man page maintenance? Grab the latest tarball at ftp://ftp.win.tue.nl/pub/linux-local/manpages/, read the HOWTOHELP file and grep the source files for 'FIXME'. - To unsubscribe from this list: send the line "unsubscribe linux-kernel" in the body of a message to majordomo@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html Please read the FAQ at http://www.tux.org/lkml/
| |