readv(2)

NAZWA
readv, writev, preadv, pwritev, preadv2, pwritev2 - czyta lub zapisuje dane do wielu buforów

BIBLIOTEKA
Standardowa biblioteka C (libc, -lc)

SKŁADNIA
#include <sys/uio.h>

ssize_t readv(int fd, const struct iovec *iov, int iovcnt);
ssize_t writev(int fd, const struct iovec *iov, int iovcnt);

ssize_t preadv(int fd, const struct iovec *iov, int iovcnt,
                off_t offset);
ssize_t pwritev(int fd, const struct iovec *iov, int iovcnt,
                off_t offset);

ssize_t preadv2(int fd, const struct iovec *iov, int iovcnt,
                off_t offset, int flags);
ssize_t pwritev2(int fd, const struct iovec *iov, int iovcnt,
                off_t offset, int flags);

    Wymagane ustawienia makr biblioteki glibc (patrz feature_test_macros(7)):

preadv(), pwritev():
    Od glibc 2.19:
        _DEFAULT_SOURCE
    glibc 2.19 i wcześniejsze:
        _BSD_SOURCE

OPIS
Wywołanie systemowe readv() czyta liczbę iovcnt bloków z pliku skojarzonego z deskryptorem pliku fd do wielu buforów opisanych przez iov („rozrzucone wejście”).

Funkcja writev() zapisuje co najwyżej iovcnt bloków opisanych przez iov do pliku skojarzonego z deskryptorem pliku fd („zgromadzone wyjście”).

Wskaźnik iov prowadzi do struktury iovec, opisanej w iovec(3type).

Wywołanie systemowe readv() działa tak samo jak read(2), z tą różnicą że wypełnianych jest wiele buforów.

Wywołanie systemowe writev() działa tak samo jak write(2), z tą różnicą że zapisywane dane pochodzą z wielu buforów.

Bufory są przetwarzane w porządku, w którym zostały wymienione w tablicy. Oznacza to, że readv() całkowicie zapełni iov[0] zanim przejdzie do iov[1] itd. (jeśli jest za mało danych, to nie wszystkie bufory w iov zostaną wypełnione). Podobnie writev zapisuje całkowicie zawartość iov[0], zanim przejdzie do iov[1], itd.

Transfery danych przeprowadzane przez readv() i writev() są atomowe: dane zapisywane przez writev() są zapisywane jako pojedynczy blok danych, niekolidujący z danymi zapisywanymi przez inne procesy. Analogicznie readv() gwarantuje przeczytanie sąsiadujących bloków danych, niezależnie od operacji odczytu przeprowadzanych przez inne wątki lub procesy mające deskryptory plików odnoszące się do tego samego otwartego pliku (patrz open(2)).

  preadv() i pwritev()
Wywołanie systemowe preadv() łączy w sobie funkcjonalności dostarczane przez readv() i przez pread(2). Wykonuje to samo zadanie, co readv(), ale dodaje czwarty argument, offset, określający miejsce w pliku, w którym zostanie przeprowadzona operacja wejściowa.

Wywołanie systemowe pwritev() łączy w sobie funkcjonalności dostarczane przez writev() i przez pwrite(2). Wykonuje to samo zadanie, co writev, ale dodaje czwarty argument, offset, określający miejsce w pliku, w którym zostanie przeprowadzona operacja wyjściowa.

Opisywane wywołania systemowe nie zmieniają pozycji przesunięcia w pliku. Pliki wskazywane przez fd muszą pozwalać na swobodny dostęp (przeszukiwanie).

  preadv2() i pwritev2()
Te wywołania systemowe są podobne do wywołań preadv() i pwritev(), lecz dodają piąty argument flags, modyfikujący zachowanie w zależności od wywołania.

W przeciwieństwie do preadv() i pwritev(), jeśli argument offset wynosi -1, to używane i aktualizowane jest przesunięcie bieżącego pliku.

Argument flags zawiera sumę bitową (OR) z jednego lub więcej z następujących znaczników:

RWF_DSYNC (od Linuksa 4.7)
    Udostępnia ekwiwalent znacznika O_DSYNC open(2), tyle że do zapisu. Znacznik ten ma znaczenie jedynie dla pwritev2(), a jego efekty stosują się tylko w zakresie danych zapisanych przez wywołanie systemowe.

RWF_HIPRI (od Linuksa 4.6)
    Odczyt/zapis o wysokim priorytecie. Pozwala blokowym systemom plików na odpytywanie urządzenia, co zapewnia niższe opóźnienia, lecz może wymagać dodatkowych zasobów (obecnie ta funkcja nadaje się do użycia wyłącznie, jeśli deskryptor pliku otwarto ze znacznikiem O_DIRECT).

RWF_SYNC (od Linuksa 4.7)
    Udostępnia ekwiwalent znacznika O_SYNC open(2), tyle że do zapisu. Znacznik ten ma znaczenie jedynie dla pwritev2(), a jego efekty stosują się tylko w zakresie danych zapisanych przez wywołanie systemowe.

RWF_NOWAIT (od Linuksa 4.14)
    Nie oczekuje na dane, które nie są natychmiast dostępne. Jeśli poda się ten znacznik, to wywołanie systemowe preadv2() powróci natychmiast, jeśli miałoby musieć odczytywać dane z nośnika nieulotnego lub czekać na blokadę. Jeśli jakieś dane zostały pomyślnie odczytane, zwróci liczbę odczytanych bajtów. Jeśli nie odczytano żadnych danych, zwróci -1 i ustawi errno na EAGAIN (lecz zobacz USTERKI). Obecnie, znacznik ten ma znaczenie jedynie dla preadv2().

RWF_APPEND (od Linuksa 4.16)
    Udostępnia ekwiwalent znacznika O_APPEND open(2), tyle że do zapisu. Znacznik ten ma znaczenie jedynie dla pwritev2(), a jego efekty stosują się tylko w zakresie danych zapisanych przez wywołanie systemowe. Argument offset nie wpływa na operację zapisu; dane są zawsze dopisywane do końca pliku. Jednakże, jeśli argument offset wynosi -1, bieżące przesunięcie pliku jest uaktualniane.

RWF_NOAPPEND (od Linuksa 6.9)
    Nie honoruje znacznika O_APPEND open(2). Znacznik ten jest istotny tylko dla pwritev2(). Historycznie, Linux uwzględniał znacznik O_APPEND, jeśli był ustawiony, i ignorował argument przesunięcia, co jest błędem. W przypadku pwritev2(), jeśli znacznik RWF_NOAPPEND jest ustawiony, argument offset jest honorowany zgodnie z przewidywaniami, czyli tak samo, jak gdyby znacznik O_APPEND nie był ustawiony.

RWF_ATOMIC (od Linuksa 6.11)
    Wymaga, aby zapisy do zwykłych plików w systemie plików korzystającym z bloków, były wydawane z zabezpieczeniem przed rozdartym zapisem (ang. torn-write). Zabezpieczenie przed rozdartym zapisem oznacza, że w przypadku usterki zasilania lub dowolnej innej usterki sprzętowej zostaną zapisane albo wszystkie, albo żadne dane z zapisu, jednak nigdy nie będzie do mieszanina starych i nowych danych. Znacznik ten jest istotny tylko dla pwritev2(), a jego skutki dotyczą tylko danych zapisywanych przez to wywołanie systemowe. Całkowita długość zapisu musi być potęgą dwójki i musi mieścić się w przedziale [stx_atomic_write_unit_min, stx_atomic_write_unit_max]. Zapis musi być w naturalnie dopasowanym przesunięciu w pliku, z uwzględnieniem całkowitej długości zapisu. Na przykład zapis o długości 32KiB na przesunięciu 32KiB w pliku jest dozwolony, natomiast zapis o długości 32KiB na przesunięciu 48KiB już nie. Górną granicę iovcnt dla pwritev2() określa wartość w stx_atomic_write_segments_max. Zabezpieczenie przed rozdartym zapisem działa tylko ze znacznikiem O_DIRECT, tj. zapisy buforowane nie są obsługiwane. Aby zagwarantować spójność zapisu pomiędzy wewnętrznym stanem pliku a tym na urządzeniu dyskowym, konieczne jest podanie O_SYNC lub O_DSYNC przy open(2). Taka sama gwarancja zsynchronizowanego wejścia/wyjście jak opisana w open(2) jest zapewniana, gdy używane są te znaczniki, albo ich odpowiedniki, oraz wywołania systemowe (np. gdy podano RWF_SYNC dla pwritev2()).

RWF_DONTCACHE (od Linuksa 6.14)
    Odczyty lub zapisy do zwykłego pliku wyczyszczą zawartość utworzonego bufora strony po zakończeniu operacji. Różni się to od zwykłego buforowanego wejścia/wyjścia, gdzie dane zwykle pozostają w buforze do momentu, gdy zostanie on odzyskany ze względu na potrzebną pamięć. Jeśli dane zakresy odczytywanego lub zapisywanego wejścia/wyjścia już znajdowały się w buforze przed tym odczytem lub zapisem, to nie zostaną one wyczyszczone po zakończeniu operacji wejścia/wyjścia.

    Dodatkowo, wszelkie zakresy zmodyfikowane (dirty) przez operację zapisu z ustawionym RWF_DONTCACHE zostaną przeznaczone do zapisu zwrotnego. Jest to podobne do wywołania sync_file_range(2) z SYNC_FILE_RANGE_WRITE w celu rozpoczęcia zapisu zwrotnego zadanego zakresu. RWF_DONTCACHE jest wskazówką, wobec której, pomimo próby jej spełnienia, nie istnieje gwarancja co do stanu bufora strony po zakończeniu operacji.

    Przy użyciu w systemie plików lub na urządzeniu blokowym, który go nie obsługuje, zwróci -1 i spowoduje ustawienie errno na EOPNOTSUPP.

WARTOŚĆ ZWRACANA
Gdy się powiodą, funkcje readv(), preadv() i preadv2() zwracają liczbę przeczytanych bajtów, a funkcje writev(), pwritev() i pwritev2() zwracają liczbę bajtów zapisanych.

Proszę zauważyć, że nie jest błędem przesłanie mniejszej liczby bajtów niż żądano przez poprawne wywołanie (zob. read(2) i write(2)).

W razie wystąpienia błędu zwracane jest -1 i ustawiane errno wskazując błąd.

BŁĘDY
Zwracane błędy są takie same, jak w przypadku funkcji read(2) i write(2). Ponadto preadv(), preadv2(), pwritev() i pwritev2() mogą także zwrócić błędy takie jak w przypadku lseek(2). Dodatkowo zdefiniowane są następujące błędy:

EINVAL
    Suma wartości iov_len przekracza rozmiar ssize_t.

EINVAL
    Jeśli podano RWF_ATOMIC, połączenie sumy wartości iov_len i wartości offset nie jest zgodne z regułami określonymi dla długości i przesunięcia, przy stosowaniu zabezpieczenia przed rozdartym zapisem (ang. torn-write).

EINVAL
    Liczba iovcnt wektorów wynosi mniej niż zero lub jest większa od dozwolonego maksimum. Jeśli podano RWF_ATOMIC, maksimum wynika z wartości stx_atomic_write_segments_max ze statx.

EOPNOTSUPP
    We flags ustawiono RWF_DONTCACHE, a plik tego nie obsługiwał.

EOPNOTSUPP
    Jako flags podano nieznaną flagę.

WERSJE

  Różnice biblioteki C/jądra
Surowe wywołania systemowe preadv() i pwritev() mają sygnatury wywołań różniące się subtelnie od odpowiadających im w funkcji opakowującej biblioteki GNU C pokazanych w SKŁADNI. Ostatni argument offset, jest rozpakowany przez funkcję opakowującą na dwa argumenty wywołania systemowego:

unsigned long pos_l, unsigned long pos

Argumenty te zawierają 32 bitowy offset w kolejności odpowiednio, od najmniej i od najbardziej znaczącego bitu.

STANDARDY

readv()
writev()
    POSIX.1-2024.

preadv()
pwritev()
    BSD.

preadv2()
pwritev2()
    Linux.

HISTORIA

readv()
writev()
    POSIX.1-2001, 4.4BSD (pojawiło się pierwotnie w 4.2BSD).

preadv(), pwritev(): Linux 2.6.30, glibc 2.10.

preadv2(), pwritev2(): Linux 4.6, glibc 2.26.

  Historyczne różnice biblioteki C/jądra
Aby rozwiązać sytuację, gdy IOV_MAX było tak niskie we wczesnych wersjach Linuksa, funkcje opakowujące readv() i writev() wykonywały pewne dodatkowe działania po wykryciu, że odpowiednie wywołanie systemowe zakończyło się błędem z powodu przekroczenia limitu. W takim wypadku funkcja readv() biblioteki glibc przydzielała tymczasowy bufor, wystarczająco duży, by pomieścić wszystkie elementy określone przez iov, przekazywała ten bufor wywołaniu systemowemu read(2), kopiowała dane z bufora tymczasowego do lokalizacji określonych przez iov, a następnie zwalniała pamięć bufora. Funkcja glibc dla writev() wykonywała analogiczne zadanie, używając bufora tymczasowego i wywołania funkcji write(2).

Potrzeba tych dodatkowych działań funkcji opakowujących glibc przestała istnieć od Linuksa 2.2. Jednak glibc wciąż udostępniał to zachowanie do glibc 2.10. Poczynając od wersji glibc 2.9, funkcje opakowujące wykonywały to działanie tylko jeśli biblioteka wykryła, że system działa pod kontrolą jądra Linux starszego niż Linux 2.6.18 (wybór tej wersji jądra nie ma głębszej przyczyny). Od glibc 2.10 (wymagającej co najmniej Linuksa 2.6.32) funkcje opakowujące glibc bezpośrednio przywołują wywołania systemowe.

UWAGI
POSIX.1 pozwala w implementacji umieścić ograniczenie liczby argumentów, które mogą być przekazane w iov. Implementacja może rozgłosić ten limit definiując IOV_MAX w <limits.h> lub w czasie uruchomienia, zwracaną wartością z sysconf(_SC_IOV_MAX). Na współczesnych systemach Linux limit ten wynosi 1024. W czasach Linuksa 2.0 wynosił 16.

USTERKI
Linux 5.9 i Linux 5.10 są obarczone błędem: preadv2() ze znacznikiem RWF_NOWAIT może zwrócić 0 nawet, gdy nie jest to koniec pliku.

PRZYKŁADY
Następujący przykładowy kod pokazuje użycie funkcji writev():

    char          *str0 = "witaj ";
    char          *str1 = "świecie\n";
    ssize_t       nwritten;
    struct iovec  iov[2];

    iov[0].iov_base = str0;
    iov[0].iov_len = strlen(str0);
    iov[1].iov_base = str1;
    iov[1].iov_len = strlen(str1);

    nwritten = writev(STDOUT_FILENO, iov, 2);

ZOBACZ TAKŻE
pread(2), read(2), write(2)

TŁUMACZENIE
Tłumaczenie niniejszej strony podręcznika: Robert Luberda <robert@debian.org> i 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.