lkml.org 
[lkml]   [2009]   [Apr]   [29]   [last100]   RSS Feed
Views: [wrap][no wrap]   [headers]  [forward] 
 
Messages in this thread
    /
    Date
    From
    Subjectsplice() on two pipes
    Hi,

    when I read about the splice() system call, I thought it was obvious
    that it could copy data between two pipes. I was surprised that this
    assumption is wrong, it's not possible on 2.6.29, I get EINVAL. Can
    anybody please explain this limitation?

    Background: I want to forward data between two subprocesses, which are
    connected to me with a pipe().

    I have attached a small test program which prints a table of supported
    splice operations. Here's the output on 2.6.29.1:

    in\out pipe sock reg chr
    pipe no yes yes yes
    sock no no no no
    reg yes no no no
    chr no no no no

    Max
    /*
    * Copyright (C) 2009 Max Kellermann <max@duempel.org>
    *
    * Redistribution and use in source and binary forms, with or without
    * modification, are permitted provided that the following conditions
    * are met:
    *
    * - Redistributions of source code must retain the above copyright
    * notice, this list of conditions and the following disclaimer.
    *
    * - Redistributions in binary form must reproduce the above copyright
    * notice, this list of conditions and the following disclaimer in the
    * documentation and/or other materials provided with the
    * distribution.
    */

    /*
    * This tiny program prints a matrix: which file descriptor
    * combinations are supported by splice()?
    */

    #define _GNU_SOURCE
    #include <fcntl.h>
    #include <errno.h>
    #include <unistd.h>
    #include <stdio.h>
    #include <stdlib.h>
    #include <sys/socket.h>

    static struct {
    const char *const name;
    int in, out;
    } fds[] = {
    { .name = "pipe", },
    { .name = "sock", },
    { .name = "reg", },
    { .name = "chr", },
    };

    enum {
    NUM_FDS = sizeof(fds) / sizeof(fds[0]),
    };

    int main(int argc, char **argv)
    {
    int f[2], ret;
    unsigned x, y;
    char template1[] = "/tmp/test_splice.XXXXXX";
    char template2[] = "/tmp/test_splice.XXXXXX";

    (void)argc;
    (void)argv;

    /* open two file descriptors of each kind */

    fds[0].in = pipe(f) >= 0 ? f[0] : -1;
    fds[0].out = pipe(f) >= 0 ? f[1] : -1;
    fds[1].in = socketpair(AF_UNIX, SOCK_STREAM, 0, f) >= 0 ? f[0] : -1;
    fds[1].out = socketpair(AF_UNIX, SOCK_STREAM, 0, f) >= 0 ? f[0] : -1;
    fds[2].in = mkstemp(template1);
    fds[2].out = mkstemp(template2);
    fds[3].in = open("/dev/zero", O_RDONLY);
    fds[3].out = open("/dev/null", O_WRONLY);

    /* print table header */

    printf("in\\out");
    for (x = 0; x < NUM_FDS; ++x)
    printf("\t%s", fds[x].name);
    putchar('\n');

    for (y = 0; y < NUM_FDS; ++y) {
    fputs(fds[y].name, stdout);

    for (x = 0; x < NUM_FDS; ++x) {
    putchar('\t');

    if (fds[x].out < 0 || fds[y].in < 0) {
    fputs("n/a", stdout);
    continue;
    }

    ret = splice(fds[y].in, NULL, fds[x].out, NULL, 1,
    SPLICE_F_NONBLOCK);
    if (ret >= 0 || errno == EAGAIN || errno == EWOULDBLOCK)
    /* EAGAIN or EWOULDBLOCK means that the kernel has
    accepted this combination, but can't move pages
    right now */
    fputs("yes", stdout);
    else if (errno == EINVAL)
    /* the kernel doesn't support this combination */
    fputs("no", stdout);
    else if (errno == ENOSYS)
    /* splice() isn't supported at all */
    fputs("ENOSYS", stdout);
    else
    /* an unexpected error code */
    fputs("err", stdout);
    }

    putchar('\n');
    }

    unlink(template1);
    unlink(template2);
    }
    \
     
     \ /
      Last update: 2009-04-29 13:05    [W:0.024 / U:0.208 seconds]
    ©2003-2016 Jasper Spaans. hosted at Digital OceanAdvertise on this site