splice(2)

NAZWA
splice - przenosi dane do/z potoku

BIBLIOTEKA
Standardowa biblioteka C (libc, -lc)

SKŁADNIA
#define _GNU_SOURCE         /* Zob. 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);

OPIS
splice() przenosi dane pomiędzy dwoma deskryptorami plików, bez kopiowania pomiędzy przestrzenią adresową jądra i przestrzenią adresową użytkownika. Transferuje maksymalnie size bajtów z deskryptora pliku fd_in do deskryptora pliku fd_out, przy czym jeden z deskryptorów plików musi odnosić się do potoku.

fd_in i off_in są objęte następującą semantyką:

•   Jeśli fd_in odnosi się do potoku, to off_in musi wynosić NULL.

•   Jeśli fd_in nie odnosi się do potoku, a off_in wynosi NULL, to bajty są odczytywane z fd_in począwszy od przesunięcia pliku, a przesunięcie pliku jest odpowiednio dostosowywane.

•   Jeśli fd_in nie odnosi się do pliku, a off_in nie wynosi NULL, to off_in musi wskazywać na bufor, określający początkowe przesunięcie, od którego zostaną odczytane bajty w fd_in; w tym przypadku przesunięcie pliku fd_in pozostaje bez zmian, w zamian odpowiednio dostosowywane jest przesunięcie, na które wskazuje off_in.

Analogiczne stwierdzenia stosują się do fd_out i off_out.

Argument flags jest maską bitową tworzoną jako suma logiczna (OR) zera lub większej liczby następujących wartości:

SPLICE_F_MOVE
    Próbuje przesunąć strony zamiast je kopiować. Jest to tylko wskazówka dla jądra: strony wciąż mogą być skopiowane, jeśli jądro nie może przesunąć stron z potoku lub jeśli bufory potoku nie odnoszą się do pełnych stron. Pierwotna implementacja tego znacznika była nieprawidłowa: z tego względu począwszy od Linuksa 2.6.21 nie odnosi on skutku (jednak wciąż jest dozwolony w wywołaniu do splice()); w przyszłości może być przywrócona poprawna implementacja.

SPLICE_F_NONBLOCK
    Nie blokuje wejścia/wyjścia. Operacje splice na potoku będą nieblokujące, jednak splice() wciąż może zablokować, ponieważ deskryptory plików do/z których następuje splice mogą blokować (chyba, że mają one ustawiony znacznik O_NONBLOCK).

SPLICE_F_MORE
    W kolejnym splice nadejdzie więcej danych. Jest to przydatna wskazówka, gdy fd_out odnosi się do gniazda (zob. też opis MSG_MORE w send(2) oraz opis TCP_CORK w tcp(7)).

SPLICE_F_GIFT
    Nieużywane w splice(); zob. vmsplice(2).

WARTOŚĆ ZWRACANA
Po pomyślnym zakończeniu splice() zwraca liczbę bajtów przeniesionych do lub z potoku.

Zwracana wartość 0 oznacza koniec wejścia. Jeśli fd_in odnosi się do potoku, oznacza to, że nie było danych do transferu, zatem blokowanie nie miało sensu, ponieważ nie było zapisujących do końca do zapisu potoku.

W razie wystąpienia błędu splice zwraca -1 i ustawia errno, wskazując błąd.

BŁĘDY

EAGAIN
    We flags podano SPLICE_F_NONBLOCK lub jeden z deskryptorów plików oznaczono jako nieblokujący (O_NONBLOCK), natomiast operacja spowodowałaby blokowanie.

EBADF
    Jeden lub więcej deskryptorów plików nie jest prawidłowych lub nie mają prawidłowego trybu do odczytu i zapisu.

EINVAL
    Docelowy system plików nie obsługuje operacji splice.

EINVAL
    Docelowy plik jest otwarty w trybie dopisywania.

EINVAL
    Żaden z deskryptorów plików nie odnosi się do potoku.

EINVAL
    Podano przesunięcie dla urządzenia, które nie jest przewijalne (np. potok).

EINVAL
    fd_in i fd_out odnoszą się do tego samego potoku.

ENOMEM
    Brak pamięci.

ESPIPE
    off_in albo off_out nie miały wartości NULL, a odpowiadający deskryptor pliku odnosił się do potoku.

STANDARDY
Linux.

HISTORIA
Linux 2.6.17, glibc 2.5.

W Linuksie 2.6.30 i wcześniejszych, dokładnie jeden z argumentów fd_in i fd_out musiał być potokiem. Od Linuksa 2.6.31 oba argumenty mogą odnosić się do potoków.

UWAGI
Trzy wywołania systemowe: splice(), vmsplice(2) i tee(2) zapewniają programom w przestrzeni użytkownika pełną kontrolę nad pewnym buforem jądra, zaimplementowanym w jądrze używając tego samego typu bufora, jaki jest używany dla potoku. Ogólnie, te wywołania systemowe spełniają następujące role:

splice()
    przenosi dane z bufora do dowolnego deskryptora pliku lub na odwrót, lub z jednego bufora do innego.

tee(2)
    „kopiuje” dane z jednego bufora do drugiego.

vmsplice(2)
    „kopiuje” dane z przestrzeni użytkownika do bufora.

Choć mowa tu o kopiowaniu, generalnie unika się faktycznego kopiowania. Jądro dokonuje tego implementując bufor potoku jako zbiór wskaźników, z licznikami odniesień, do stron pamięci jądra. Jądro tworzy „kopie” stron w buforze, tworząc nowe wskaźniki (dla bufora wyjściowego) odnoszące się do stron oraz zwiększając liczniki odniesień do stron: kopiowane są tylko wskaźniki, a nie strony bufora.

_FILE_OFFSET_BITS powinno być zdefiniowane jako 64 w kodzie, który używa wartości off_in lub off_out innych niż null lub takim, który przyjmuje adres splice, jeśli kod ma być przenośny na tradycyjne, 32-bitowe platformy x86 i ARM, w których szerokość off_t domyślnie wynosi 32 bity.

PRZYKŁADY
Inny przykład opisano w podręczniku tee(2).

    #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[14] = "Witaj swiecie!";

            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("Nowy przesunięcie wynosi %jd\n", (intmax_t) off);

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

ZOBACZ TAKŻE
copy_file_range(2), sendfile(2), tee(2), vmsplice(2), pipe(7)

TŁUMACZENIE
Tłumaczenie niniejszej strony podręcznika: Michał Kułach <michal.kulach@gmail.com>

Niniejsze tłumaczenie jest wolną dokumentacją. Bliższe informacje o warunkach licencji można uzyskać zapoznając się z GNU General Public License w wersji 3 (https://www.gnu.org/licenses/gpl-3.0.html) lub nowszej. Nie przyjmuje się ŻADNEJ ODPOWIEDZIALNOŚCI.

Błędy w tłumaczeniu strony podręcznika prosimy zgłaszać na adres listy dyskusyjnej manpages-pl-list@lists.sourceforge.net.