splice(2)

НАИМЕНОВАНИЕ
splice - подключает данные к каналу/выбирает данные из канала

БИБЛИОТЕКА
Стандартная библиотека языка C (libc, -lc)

ОБЗОР
#define _GNU_SOURCE         /* см. feature_test_macros(7) */
#define _FILE_OFFSET_BITS 64
#include <fcntl.h>

ssize_t splice(int fd_in, off_t *_Nullable off_in,
               int fd_out, off_t *_Nullable off_out,
               size_t size, unsigned int flags);

ОПИСАНИЕ
splice() moves data between two file descriptors without copying between kernel address space and user address space. It transfers up to size bytes of data from the file descriptor fd_in to the file descriptor fd_out, where one of the file descriptors must refer to a pipe.

К fd_in и off_in применяются следующие правила:

•   Если fd_in указывает на канал, то значение off_in должно быть NULL.

•   Если fd_in не указывает на канал и off_in равно NULL, то из fd_in читаются байты начиная с смещения файла и это смещение соответственно изменяется.

•   If fd_in does not refer to a pipe and off_in is not NULL, then off_in must point to a buffer which specifies the starting offset from which bytes will be read from fd_in; in this case, the file offset of fd_in is not changed, and the offset pointed to by off_in is adjusted appropriately instead.

Аналогичные правила относятся и к fd_out и off_out.

Аргумент flags представляет собой битовую маску, которая составляется логическим сложением (OR) следующих значений:

SPLICE_F_MOVE
    Пытаться переместить страницы, а не копировать их. Используется только как подсказка ядру: страницы всё равно будут копироваться, если ядро не сможет переместить страницы из канала, или если буферы канала не ссылаются на полные страницы. Первая реализация этого флага была с дефектами: поэтому начиная с Linux 2.6.21 этот флаг ни на что не влияет (но по прежнему разрешён в вызове splice()); в будущем, возможно появится корректная реализация.

SPLICE_F_NONBLOCK
    Не блокировать при вводе-выводе. Это делает операции соединения с каналом неблокируемыми, но splice(), тем не менее, может заблокироваться, так как файловые дескрипторы, с которыми ведётся работа, могут блокироваться (если у них не установлен флаг O_NONBLOCK).

SPLICE_F_MORE
    В следующем подключении будут дополнительные данные. Полезно указывать, когда fd_out ссылается на сокет (смотрите также описание MSG_MORE в send(2) и описание TCP_CORK в tcp(7)).

SPLICE_F_GIFT
    Не используется в splice(); смотрите vmsplice(2).

ВОЗВРАЩАЕМОЕ ЗНАЧЕНИЕ
При успешном выполнении splice() возвращает количество байт, которые были записаны или получены из канала.

Возвращаемое значение 0 означает конец ввода. Если fd_in указывает на канал, то это означает, что нет данных для передачи и и блокировка не имела бы смысла, так как нет писателей, подключённых к пишущему концу канала.

В случае ошибки splice() возвращает -1, а errno устанавливается в соответствующее значение.

ОШИБКИ

EAGAIN
    В flags указан SPLICE_F_NONBLOCK или один из файловых дескрипторов был помечен как неблокирующий (O_NONBLOCK), и операция вызвала бы блокировку.

EBADF
    Один или оба файловых дескриптора недействительны или в неправильном режиме чтения-записи.

EINVAL
    Целевая файловая система не поддерживает подключение данных (splicing).

EINVAL
    Файл назначения открыт в режиме добавления.

EINVAL
    Ни один из файловых дескрипторов не ссылается на канал.

EINVAL
    Указано смещение для устройства этого не поддерживающего (например, канала).

EINVAL
    Значение fd_in и fd_out указывают на один и тот же канал.

ENOMEM
    Не хватает памяти.

ESPIPE
    Значение off_in или off_out не равно NULL, но соответствующий файловый дескриптор ссылается на канал.

СТАНДАРТЫ
Linux.

ИСТОРИЯ
Linux 2.6.17, glibc 2.5.

В Linux 2.6.30 и старее, только один из fd_in и fd_out должен быть каналом. Начиная с Linux 2.6.31 оба параметра должны быть каналами.

ПРИМЕЧАНИЯ
Три системных вызова — splice(), vmsplice(2), and tee(2), предоставляют пользовательским программам полный контроль над произвольным буфером ядра; они реализованы в ядре на базе того же типа буферов, который используется для канала. Эти системные вызовы выполняют следующие задачи:

splice()
    перемещает данные из буфера в произвольный файловый дескриптор или наоборот, и из одного буфера в другой.

tee(2)
    «копирует» данные из одного буфера в другой.

vmsplice(2)
    «копирует» данные из пользовательского пространства в буфер.

Хотя мы говорим о копировании, на самом деле копирования, обычно, не происходит. Ядро реализует канальный буфер как набор указателей со счётчиком ссылок на страницы памяти ядра. Ядро создаёт «копии» страниц в буфере посредством создания новых указателей (для выходного буфера), указывающих на страницы, и увеличивает счётчики ссылок страниц: копируются только указатели, а не страницы буфера.

_FILE_OFFSET_BITS should be defined to be 64 in code that uses non-null off_in or off_out or that takes the address of splice, if the code is intended to be portable to traditional 32-bit x86 and ARM platforms where off_t's width defaults to 32 bits.

ПРИМЕРЫ
See tee(2) for another example.

    #define _GNU_SOURCE
    #define _FILE_OFFSET_BITS 64
    #include <err.h>
    #include <fcntl.h>
    #include <stdint.h>
    #include <stdio.h>
    #include <stdlib.h>
    #include <sys/types.h>
    #include <unistd.h>

    int
    main(void)
    {
            int         fd;
            int         pfd[2];
            off_t       off;
            [[gnu::nonstring]]
    	const char  s[12] = "Hello, world";

            fd = open("out", O_WRONLY | O_CREAT | O_EXCL, 0666);
            if (fd == -1)
                    err(EXIT_FAILURE, "open");

            if (pipe(pfd) == -1)
                    err(EXIT_FAILURE, "pipe");

            if (write(pfd[1], s, sizeof(s)) != sizeof(s))
                    err(EXIT_FAILURE, "write");
            if (close(pfd[1]) == -1)
                    err(EXIT_FAILURE, "close");

            off = 10;
            if (splice(pfd[0], NULL, fd, &off, sizeof(s), 0) != sizeof(s))
                    err(EXIT_FAILURE, "splice");
            if (close(pfd[0]) == -1)
                    err(EXIT_FAILURE, "close");

            printf("New offset is %jd\n", (intmax_t) off);

            if (close(fd) == -1)
                    err(EXIT_FAILURE, "close");
            exit(EXIT_SUCCESS);
    }

СМОТРИТЕ ТАКЖЕ
copy_file_range(2), sendfile(2), tee(2), vmsplice(2), pipe(7)

ПЕРЕВОД
Русский перевод этой страницы руководства разработал(и) Alexander Golubev <fatzer2@gmail.com>, Azamat Hackimov <azamat.hackimov@gmail.com>, Hotellook, Nikita <zxcvbnm3230@mail.ru>, Spiros Georgaras <sng@hellug.gr>, Vladislav <ivladislavefimov@gmail.com>, Yuri Kozlov <yuray@komyakino.ru> и Иван Павлов <pavia00@gmail.com>

Этот перевод является свободной программной документацией; он распространяется на условиях общедоступной лицензии GNU (GNU General Public License - GPL, https://www.gnu.org/licenses/gpl-3.0.html версии 3 или более поздней) в отношении авторского права, но БЕЗ КАКИХ-ЛИБО ГАРАНТИЙ.

Если вы обнаружите какие-либо ошибки в переводе этой страницы руководства, пожалуйста, сообщите об этом разработчику(ам) по его(их) адресу(ам) электронной почты или по адресу списка рассылки русских переводчиков (<debian-l10n-russian@lists.debian.org>).