.\" -*- coding: UTF-8 -*- .\" Copyright (c) 2010 by Michael Kerrisk .\" .\" SPDX-License-Identifier: Linux-man-pages-copyleft .\" .\"******************************************************************* .\" .\" This file was generated with po4a. Translate the source file. .\" .\"******************************************************************* .TH AIO 7 "3 мая 2023 г." "Linux man\-pages 6.05.01" .SH ИМЯ aio \- введение в асинхронный ввод\-вывод POSIX .SH ОПИСАНИЕ Интерфейс асинхронного ввода\-вывода POSIX (AIO) позволяет приложениям запускать одну или несколько операций ввода\-вывода, которые выполняются асинхронно (т. е., в фоновом режиме). Приложение может выбрать каким образом оно будет уведомлено о завершении операции ввода\-вывода: с помощью сигнала, созданием новой нити или вообще не получать уведомления. .PP Интерфейс POSIX AIO состоит из следующих функций: .TP \fBaio_read\fP(3) Ставит запрос на чтение в очередь. Это асинхронный аналог \fBread\fP(2). .TP \fBaio_write\fP(3) Ставит запрос на запись в очередь. Это асинхронный аналог \fBwrite\fP(2). .TP \fBaio_fsync\fP(3) Ставит запрос синхронизации операций ввода\-вывода над файловым дескриптором. Это асинхронный аналог \fBfsync\fP(2) и \fBfdatasync\fP(2). .TP \fBaio_error\fP(3) Возвращает информацию о состоянии поставленного в очередь запроса ввода\-вывода. .TP \fBaio_return\fP(3) Возвращает информацию о выполненном запросе ввода\-вывода. .TP \fBaio_suspend\fP(3) Приостанавливает вызывающего до тех пор, пока не выполнится один или более указанных запросов ввода\-вывода. .TP \fBaio_cancel\fP(3) Пытается отменить ожидающие выполнения запросы ввода\-вывода над заданным файловым дескриптором. .TP \fBlio_listio\fP(3) Ставит в очередь сразу несколько запросов ввода\-вывода за один вызов функции. .PP В структуре \fIaiocb\fP («блок управления асинхронным вводом\-выводом») задаются параметры, которые управляют операцией ввода\-вывода. Аргумент данного типа передаётся во все функции, перечисленные ранее. Данная структура имеет следующий вид: .PP .in +4n .EX #include \& struct aiocb { /* The order of these fields is implementation\-dependent */ \& int aio_fildes; /* File descriptor */ off_t aio_offset; /* File offset */ volatile void *aio_buf; /* Location of buffer */ size_t aio_nbytes; /* Length of transfer */ int aio_reqprio; /* Request priority */ struct sigevent aio_sigevent; /* Notification method */ int aio_lio_opcode; /* Operation to be performed; lio_listio() only */ \& /* Various implementation\-internal fields not shown */ }; \& /* Operation codes for \[aq]aio_lio_opcode\[aq]: */ \& enum { LIO_READ, LIO_WRITE, LIO_NOP }; .EE .in .PP Поля этой структуры имеют следующее назначение: .TP \fIaio_fildes\fP Файловый дескриптор, над которым будут выполняться операции ввода\-вывода. .TP \fIaio_offset\fP Файловое смещение, начиная с которого будут выполняться операции ввода\-вывода. .TP \fIaio_buf\fP Буфер, используемый для пересылки данных при операции чтения или записи. .TP \fIaio_nbytes\fP Размер буфера, на который указывает \fIaio_buf\fP. .TP \fIaio_reqprio\fP В этом поле задаётся значение, которое вычитается из приоритета реального времени вызывающей нити, чтобы определить приоритет выполнения данного запроса ввода\-вывода (смотрите \fBpthread_setschedparam\fP(3)). Указываемое значение должно быть в диапазоне от 0 и до значения, возвращаемого \fIsysconf(_SC_AIO_PRIO_DELTA_MAX)\fP. Данное поле игнорируется при операциях синхронизации файла. .TP \fIaio_sigevent\fP В этом поле задаётся структура, которая указывает как вызывающему должно быть сообщено о завершении анонимной операции ввода\-вывода. Возможные значения для \fIaio_sigevent.sigev_notify\fP: \fBSIGEV_NONE\fP, \fBSIGEV_SIGNAL\fP и \fBSIGEV_THREAD\fP. Подробности смотрите в \fBsigevent\fP(7). .TP \fIaio_lio_opcode\fP Задаёт тип операции, которая будет выполнена; используется только в \fBlio_listio\fP(3). .PP В дополнении к стандартным функциям, перечисленным ранее, в библиотеке GNU C есть следующее расширение программного интерфейса POSIX AIO: .TP \fBaio_init\fP(3) Позволяет изменить настройки поведения реализации glibc для POSIX AIO. .SH ОШИБКИ .TP \fBEINVAL\fP Значение поля \fIaio_reqprio\fP структуры \fIaiocb\fP меньше 0 или больше, чем значение ограничения, возвращаемое вызовом \fIsysconf(_SC_AIO_PRIO_DELTA_MAX)\fP. .SH СТАНДАРТЫ POSIX.1\-2008. .SH ИСТОРИЯ POSIX.1\-2001. glibc 2.1. .SH ЗАМЕЧАНИЯ Желательно обнулять буфер блока управления перед использованием (смотрите \fBmemset\fP(3)). Буфер блока управления и буфер, который задаётся в \fIaio_buf\fP, не должны изменяться во время выполнения операции ввода\-вывода. Данные буферы должны оставаться рабочими до завершения операции ввода\-вывода. .PP Одновременное выполнение операций чтения или записи через совместно используемую структуру \fIaiocb\fP приводит к непредсказуемым результатам. .PP .\" http://lse.sourceforge.net/io/aio.html .\" http://lse.sourceforge.net/io/aionotes.txt .\" http://lwn.net/Articles/148755/ Имеющаяся реализация Linux POSIX AIO предоставляется glibc в пользовательском пространстве. Она имеет ряд ограничений, наиболее существенные из которых — затраты на сопровождение нескольких нитей при операциях ввода\-вывода и плохое масштабирование. Некогда для реализации асинхронного ввода\-вывода велась работа над ядерной реализацией на основе машины состояний (смотрите \fBio_submit\fP(2), \fBio_setup\fP(2), \fBio_cancel\fP(2), \fBio_destroy\fP(2), \fBio_getevents\fP(2)), но эта реализация ещё недостаточно стабильна в тех местах, где POSIX AIO можно было бы полностью реализовать на системных вызовах ядра. .SH ПРИМЕРЫ Представленная далее программа открывает все файлы, указанные в параметрах командной строки и ставит в очередь запрос на полученные файловые дескрипторы с помощью \fBaio_read\fP(3). Затем программа входит в цикл, в котором периодически следит за всеми выполняемыми операциями ввода\-вывода с помощью \fBaio_error\fP(3). Для каждого запроса ввода\-вывода настроено получение уведомления посредством сигнала. После завершения всех запросов ввода\-вывода, программа возвращает их состояние с помощью \fBaio_return\fP(3). .PP The \fBSIGQUIT\fP signal (generated by typing control\-\e) causes the program to request cancelation of each of the outstanding requests using \fBaio_cancel\fP(3). .PP Вот результат работы программы. В этом примере программа ставит в очередь два запроса для стандартного ввода, и они отрабатываются двумя введёнными строками «abc» и «x». .PP .in +4n .EX $ \fB./a.out /dev/stdin /dev/stdin\fP открыт /dev/stdin в дескрипторе 3 открыт /dev/stdin в дескрипторе 4 aio_error(): запрос 0 (дескриптор 3): выполняется запрос 1 (дескриптор 4): выполняется \fBabc\fP Получен сигнал завершения ввода\-вывода aio_error(): запрос 0 (дескриптор 3): ввод\-вывод завершён запрос 1 (дескриптор 4): выполняется aio_error(): запрос 1 (дескриптор 4): выполняется \fBx\fP Получен сигнал завершения ввода\-вывода aio_error(): запрос 1 (дескриптор 4): ввод\-вывод завершён Завершены все запросы ввода\-вывода aio_return(): запрос 0 (дескриптор 3): 4 запрос 1 (дескриптор 4): 2 .EE .in .SS "Исходный код программы" \& .EX #include #include #include #include #include #include #include \& #define BUF_SIZE 20 /* Size of buffers for read operations */ \& #define errExit(msg) do { perror(msg); exit(EXIT_FAILURE); } while (0) \& struct ioRequest { /* Application\-defined structure for tracking I/O requests */ int reqNum; int status; struct aiocb *aiocbp; }; \& static volatile sig_atomic_t gotSIGQUIT = 0; /* On delivery of SIGQUIT, we attempt to cancel all outstanding I/O requests */ \& static void /* Handler for SIGQUIT */ quitHandler(int sig) { gotSIGQUIT = 1; } \& #define IO_SIGNAL SIGUSR1 /* Signal used to notify I/O completion */ \& static void /* Handler for I/O completion signal */ aioSigHandler(int sig, siginfo_t *si, void *ucontext) { if (si\->si_code == SI_ASYNCIO) { write(STDOUT_FILENO, "I/O completion signal received\en", 31); \& /* The corresponding ioRequest structure would be available as struct ioRequest *ioReq = si\->si_value.sival_ptr; and the file descriptor would then be available via ioReq\->aiocbp\->aio_fildes */ } } \& int main(int argc, char *argv[]) { struct sigaction sa; int s; int numReqs; /* Total number of queued I/O requests */ int openReqs; /* Number of I/O requests still in progress */ \& if (argc < 2) { fprintf(stderr, "Usage: %s ...\en", argv[0]); exit(EXIT_FAILURE); } \& numReqs = argc \- 1; \& /* Allocate our arrays. */ \& struct ioRequest *ioList = calloc(numReqs, sizeof(*ioList)); if (ioList == NULL) errExit("calloc"); \& struct aiocb *aiocbList = calloc(numReqs, sizeof(*aiocbList)); if (aiocbList == NULL) errExit("calloc"); \& /* Establish handlers for SIGQUIT and the I/O completion signal. */ \& sa.sa_flags = SA_RESTART; sigemptyset(&sa.sa_mask); \& sa.sa_handler = quitHandler; if (sigaction(SIGQUIT, &sa, NULL) == \-1) errExit("sigaction"); \& sa.sa_flags = SA_RESTART | SA_SIGINFO; sa.sa_sigaction = aioSigHandler; if (sigaction(IO_SIGNAL, &sa, NULL) == \-1) errExit("sigaction"); \& /* Open each file specified on the command line, and queue a read request on the resulting file descriptor. */ \& for (size_t j = 0; j < numReqs; j++) { ioList[j].reqNum = j; ioList[j].status = EINPROGRESS; ioList[j].aiocbp = &aiocbList[j]; \& ioList[j].aiocbp\->aio_fildes = open(argv[j + 1], O_RDONLY); if (ioList[j].aiocbp\->aio_fildes == \-1) errExit("open"); printf("opened %s on descriptor %d\en", argv[j + 1], ioList[j].aiocbp\->aio_fildes); \& ioList[j].aiocbp\->aio_buf = malloc(BUF_SIZE); if (ioList[j].aiocbp\->aio_buf == NULL) errExit("malloc"); \& ioList[j].aiocbp\->aio_nbytes = BUF_SIZE; ioList[j].aiocbp\->aio_reqprio = 0; ioList[j].aiocbp\->aio_offset = 0; ioList[j].aiocbp\->aio_sigevent.sigev_notify = SIGEV_SIGNAL; ioList[j].aiocbp\->aio_sigevent.sigev_signo = IO_SIGNAL; ioList[j].aiocbp\->aio_sigevent.sigev_value.sival_ptr = &ioList[j]; \& s = aio_read(ioList[j].aiocbp); if (s == \-1) errExit("aio_read"); } \& openReqs = numReqs; \& /* Loop, monitoring status of I/O requests. */ \& while (openReqs > 0) { sleep(3); /* Delay between each monitoring step */ \& if (gotSIGQUIT) { \& /* On receipt of SIGQUIT, attempt to cancel each of the outstanding I/O requests, and display status returned from the cancelation requests. */ \& printf("got SIGQUIT; canceling I/O requests: \en"); \& for (size_t j = 0; j < numReqs; j++) { if (ioList[j].status == EINPROGRESS) { printf(" Request %zu on descriptor %d:", j, ioList[j].aiocbp\->aio_fildes); s = aio_cancel(ioList[j].aiocbp\->aio_fildes, ioList[j].aiocbp); if (s == AIO_CANCELED) printf("I/O canceled\en"); else if (s == AIO_NOTCANCELED) printf("I/O not canceled\en"); else if (s == AIO_ALLDONE) printf("I/O all done\en"); else perror("aio_cancel"); } } \& gotSIGQUIT = 0; } \& /* Check the status of each I/O request that is still in progress. */ \& printf("aio_error():\en"); for (size_t j = 0; j < numReqs; j++) { if (ioList[j].status == EINPROGRESS) { printf(" for request %zu (descriptor %d): ", j, ioList[j].aiocbp\->aio_fildes); ioList[j].status = aio_error(ioList[j].aiocbp); \& switch (ioList[j].status) { case 0: printf("I/O succeeded\en"); break; case EINPROGRESS: printf("In progress\en"); break; case ECANCELED: printf("Canceled\en"); break; default: perror("aio_error"); break; } \& if (ioList[j].status != EINPROGRESS) openReqs\-\-; } } } \& printf("All I/O requests completed\en"); \& /* Check status return of all I/O requests. */ \& printf("aio_return():\en"); for (size_t j = 0; j < numReqs; j++) { ssize_t s; \& s = aio_return(ioList[j].aiocbp); printf(" for request %zu (descriptor %d): %zd\en", j, ioList[j].aiocbp\->aio_fildes, s); } \& exit(EXIT_SUCCESS); } .EE .SH "СМ. ТАКЖЕ" .ad l .nh \fBio_cancel\fP(2), \fBio_destroy\fP(2), \fBio_getevents\fP(2), \fBio_setup\fP(2), \fBio_submit\fP(2), \fBaio_cancel\fP(3), \fBaio_error\fP(3), \fBaio_init\fP(3), \fBaio_read\fP(3), \fBaio_return\fP(3), \fBaio_write\fP(3), \fBlio_listio\fP(3) .PP «Asynchronous I/O Support in Linux 2.5», Bhattacharya, Pratt, Pulavarty, and Morgan, Proceedings of the Linux Symposium, 2003, .UR https://www.kernel.org/doc/ols/2003/ols2003\-pages\-351\-366.pdf .UE .PP .SH ПЕРЕВОД Русский перевод этой страницы руководства был сделан Dmitry Bolkhovskikh и Yuri Kozlov . .PP Этот перевод является бесплатной документацией; прочитайте .UR https://www.gnu.org/licenses/gpl-3.0.html Стандартную общественную лицензию GNU версии 3 .UE или более позднюю, чтобы узнать об условиях авторского права. Мы не несем НИКАКОЙ ОТВЕТСТВЕННОСТИ. .PP Если вы обнаружите ошибки в переводе этой страницы руководства, пожалуйста, отправьте электронное письмо на .MT man-pages-ru-talks@lists.sourceforge.net .ME .