All of lore.kernel.org
 help / color / mirror / Atom feed
From: "Michael Kerrisk" <mtk-manpages@gmx.net>
To: axboe@suse.de
Cc: linux-kernel@vger.kernel.org, michael.kerrisk@gmx.net
Subject: splice/tee bugs?
Date: Fri, 07 Jul 2006 09:07:03 +0200	[thread overview]
Message-ID: <20060707070703.165520@gmx.net> (raw)

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'.

             reply	other threads:[~2006-07-07  7:07 UTC|newest]

Thread overview: 34+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2006-07-07  7:07 Michael Kerrisk [this message]
2006-07-07 11:07 ` splice/tee bugs? Andrew Morton
2006-07-07 11:42   ` Michael Kerrisk
2006-07-07 12:03     ` Jens Axboe
2006-07-07 12:28       ` Jens Axboe
2006-07-07 12:31         ` Michael Kerrisk
2006-07-07 12:41           ` Jens Axboe
2006-07-07 13:12             ` Jens Axboe
2006-07-07 13:14               ` Jens Axboe
2006-07-07 13:21                 ` Arjan van de Ven
2006-07-07 13:26                   ` Jens Axboe
2006-07-07 13:54                     ` Paulo Marques
2006-07-07 14:02                       ` Jens Axboe
2006-07-07 14:05               ` Michael Kerrisk
2006-07-07 14:08                 ` Jens Axboe
2006-07-07 16:13   ` Luiz Fernando N. Capitulino
2006-07-07 21:43     ` Luiz Fernando N. Capitulino
2006-07-08  6:41     ` Jens Axboe
2006-07-08 21:09       ` Luiz Fernando N. Capitulino
2006-07-09 10:36         ` Jens Axboe
2006-07-09 11:16           ` Jens Axboe
2006-07-09 16:47             ` Luiz Fernando N. Capitulino
2006-07-09 17:57               ` Jens Axboe
2006-07-10  6:25                 ` Michael Kerrisk
2006-07-10  6:43                   ` Jens Axboe
2006-07-10  8:09                     ` Michael Kerrisk
2006-07-10  8:24                       ` Jens Axboe
2006-07-10  8:40                         ` Michael Kerrisk
2006-07-10  8:46                           ` Jens Axboe
2006-07-10  8:50                             ` Michael Kerrisk
2006-07-10  9:06                               ` Jens Axboe
2006-07-10  9:08                                 ` Michael Kerrisk
2006-07-10  8:50                             ` Jens Axboe
  -- strict thread matches above, loose matches on Subject: below --
2006-07-08  5:33 Chuck Ebbert

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=20060707070703.165520@gmx.net \
    --to=mtk-manpages@gmx.net \
    --cc=axboe@suse.de \
    --cc=linux-kernel@vger.kernel.org \
    --cc=michael.kerrisk@gmx.net \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.