From: Max Kellermann <max@duempel.org>
To: linux-kernel@vger.kernel.org
Subject: splice() on two pipes
Date: Wed, 29 Apr 2009 12:33:08 +0200 [thread overview]
Message-ID: <20090429103308.GA23684@squirrel.roonstrasse.net> (raw)
[-- Attachment #1: Type: text/plain, Size: 667 bytes --]
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
[-- Attachment #2: test_splice.c --]
[-- Type: text/x-csrc, Size: 2971 bytes --]
/*
* 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);
}
next reply other threads:[~2009-04-29 11:02 UTC|newest]
Thread overview: 7+ messages / expand[flat|nested] mbox.gz Atom feed top
2009-04-29 10:33 Max Kellermann [this message]
2009-04-29 15:23 ` splice() on two pipes Andi Kleen
2009-04-29 19:42 ` Max Kellermann
2009-04-30 4:56 ` Willy Tarreau
2009-04-30 14:26 ` Mark Hills
2009-04-30 6:21 ` Jens Axboe
2009-04-30 6:42 ` Max Kellermann
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=20090429103308.GA23684@squirrel.roonstrasse.net \
--to=max@duempel.org \
--cc=linux-kernel@vger.kernel.org \
/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 a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox