Linux aio что это

Linux aio что это

Интерфейс POSIX AIO состоит из следующих функций:

aio_read(3) Ставит запрос на чтение в очередь. Это асинхронный аналог read(2). aio_write(3) Ставит запрос на запись в очередь. Это асинхронный аналог write(2). aio_fsync(3) Ставит запрос синхронизации операций ввода-вывода над файловым дескриптором. Это асинхронный аналог fsync(2) и fdatasync(2). aio_error(3) Возвращает информацию о состоянии поставленного в очередь запроса ввода-вывода. aio_return(3) Возвращает информацию о выполненном запросе ввода-вывода. aio_suspend(3) Приостанавливает вызывающего до тех пор, пока не выполнится один или более указанных запросов ввода-вывода. aio_cancel(3) Пытается отменить ожидающие выполнения запросы ввода-вывода над заданным файловым дескриптором. lio_listio(3) Ставит в очередь сразу несколько запросов ввода-вывода за один вызов функции.

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

Поля этой структуры имеют следующее назначение: aio_filedes Файловый дескриптор, над которым будут выполняться операции ввода-вывода. aio_offset Файловое смещение, начиная с которого будут выполняться операции ввода-вывода. aio_buf Буфер, используемый для пересылки данных при операции чтения или записи. aio_nbytes Размер буфера, на который указывает aio_buf. aio_reqprio В этом поле задаётся значение, которое вычитается из приоритета реального времени вызывающей нити, чтобы определить приоритет выполнения данного запроса ввода-вывода (смотрите pthread_setschedparam(3)). Указываемое значение должно быть в диапазоне от 0 и до значения, возвращаемого sysconf(_SC_AIO_PRIO_DELTA_MAX). Данное поле игнорируется при операциях синхронизации файла. aio_sigevent В этом поле задаётся структура, которая указывает как вызывающему должно быть сообщено о завершении анонимной операции ввода-вывода. Возможные значения для aio_sigevent.sigev_notify: SIGEV_NONE, SIGEV_SIGNAL и SIGEV_THREAD. Подробности смотрите в sigevent(7). aio_lio_opcode Задаёт тип операции, которая будет выполнена; используется только в lio_listio(3).

В дополнении к стандартным функциям, перечисленным ранее, в библиотеке GNU C есть следующее расширение программного интерфейса POSIX AIO:

aio_init(3) Позволяет изменить настройки поведения реализации glibc для POSIX AIO.

ОШИБКИ

ВЕРСИИ

СООТВЕТСТВИЕ СТАНДАРТАМ

ЗАМЕЧАНИЯ

Одновременное выполнение операций чтения или записи через совместно используемую структуру aiocb приводит к непредсказуемым результатам.

Имеющаяся реализация Linux POSIX AIO предоставляется glibc в пользовательском пространстве. Она имеет ряд ограничений, наиболее существенные из которых — затраты на сопровождение нескольких нитей при операциях ввода-вывода и плохое масштабирование. Некогда для реализации асинхронного ввода-вывода велась работа над ядерной реализацией на основе машины состояний (смотрите io_submit(2), io_setup(2), io_cancel(2), io_destroy(2), io_getevents(2)), но эта реализация ещё недостаточно стабильна в тех местах, где POSIX AIO можно было бы полностью реализовать на системных вызовах ядра.

ПРИМЕР

Сигнал SIGQUIT (генерируемый нажатием control-\) заставляет программу отменить все невыполненные запросы с помощью aio_cancel(3).

Вот результат работы программы. В этом примере программа ставит в очередь два запроса для стандартного ввода, и они отрабатываются двумя введёнными строками «abc» и «x».

Источник

Vsevolod Stakhov

Страницы

Thursday, May 3, 2012

AIO в Linux.

Введение.

Не так давно я реализовывал систему асинхронного io для эффективной работы в Linux. Данный пост является компиляцией моего опыта в данной теме и описывает, в основном, ядерный io (который осуществляется через io_submit). Желающих ознакомиться с данным опытом прошу под кат.

Читайте также:  Dns changer для windows

Принципы asynchronous io.

Асинхронный ввод/вывод — это неблокирующее выполнение файловых операций с уведомлением об их завершении. При традиционном, блокирующем, IO операция с файлом выглядит так:
запрос операции -> блокирование вызывающего потока -> выполнение операции -> разблокирование вызывающего потока -> возврат результата.

При неблокирующем io блокировки не происходит, но способа понять, когда именно данные записались или прочитались фактически не существует — приложение, фактически, рассчитывает на возврат EAGAIN в качестве сигнала о том, что данные в таком количестве на данном дескрипторе в настоящее время недоступны. Это делает процесс организации ввода/вывода довольно затруднительным, так как каждый раз можно ожидать неполного завершения операции и организовывать его обработку.

При асинхронном io блокировки запроса также не происходит, но при завершении запроса приложение получает нотификацию. Таким образом, можно предположить, что при получении нотификации наша операция либо полностью завершена, либо произошла ошибка. И нам нет нужды вначале проверять готовность дескриптора к операции, вместо этого мы можем послать запросы в любой момент.

AIO в Linux.

В Linux существует два типа aio — posix aio, который эмулируется в glibc созданием потоков (pthreads), и ядерный aio, который работает внутри ядра и не является портабельным на другие ОС (в том числе и на старые ядра Linux). Первый способ работает через сигналы и не слишком производителен из-за накладных расходов по переключению контекста и обработке этих самых сигналов. Зато второй способ хорошо укладывался в модель обработки событий через libevent.

Необходимо отметить, что есть целый ряд ограничений на работу ядерного aio. Во-первых, ядерный aio не имеет интерфейса в libc, поэтому надо либо использовать libaio, либо писать собственнные обертки вокруг системных вызовов, что усложняется тем, что номера системных вызовов отличаются от архитектуры к архитектуре. Обертки могут выглядеть таким образом:

Следующее ограничение — дескрипторы для ядерного aio должны быть открыты с флагом O_DIRECT, что накладывает ограничения на операции с дескриптором (без этого флага aio работать будет, но может быть блокирующим):

  • Буфер в памяти должен быть выровнен по границе 512 байт (например, при помощи posix_memalign)
  • При невыполнении этих условий aio операции будут выдавать EINVAL, что, конечно, было бы крайне информативно, если бы этот самый EINVAL не возвращался в куче других случаев. Поэтому эти три пункта должны выполняться неукоснительно.

    Получение нотификаций.

    Нотификации можно получать двумя способами: через сигналы (дорого) и через eventfd (правильно). Eventfd — это такой дескриптор, через который ядро уведомляет приложение о событиях, которые случились внутри ядра. Завершение AIO является характерным примером такого события. Сам по себе eventfd выплевывает 8-ми байтные целые числа. Такое число значит, сколько событий произошло с последнего вызова eventfd. Eventfd может обрабатываться обычными операциями поллинга, например, через libevent. Далее, получив число таких событий, можно звать io_getevents. Данный вызов заполняет массив структур io_cbdata, выглядящих следующим образом:

    Основная ценность данной структуры в поле data, позволяющем передать произвольный указатель при aio запросе, а вторая — поле res, означающее результат. Этот результат — это либо число байт, обработанных в ходе запроса, либо код ошибки (при отрицательном res).

    Отправка запросов.

    Отправка aio запроса — отдельная тема для разговора, так как опять же структура для этого не описана в libc. Поэтому я использовал фрагмент кода из libaio для описания этой структуры:

    Использовать эту структуру для aio запроса следует так:

    Таким образом, можно отправлять не единичные, а множественные запросы aio, которые потом обрабатывать.

    Читайте также:  Максимальное количество активаций windows 10

    Заключение.

    AIO в Linux использовать можно и нужно тогда, когда необходимо обеспечить два требования: нотификация о завершении операции и неблокирующий ввод/вывод. Это полезно тогда, когда событийно ориентированной программе необходимо интенсивно выполнять IO с файлам, при этом не блокируясь на read и write, но при этом получая информации о завершении таких операций. Кроме этого, использование O_DIRECT, дает возможность получать нотификацию ровно тогда, когда данные уже либо записались на диск, либо находятся в буфере диска (если таковой есть). Это позволяет избежать использование буферов системы и обеспечить равномерное использование диска (то есть, исключается поведение, когда вначале запись проходит мгновенно, а потом, при переполнении системных буферов, внезапно начинает тормозить, так как эти буферы начинают интенсивно сбрасываться на диск). Полную версию API для использования aio в Linux я включил в rspamd:
    aio_event.c
    aio_event.h

    Надеюсь, кому-то это поможет не наступить на те грабли, по которым я изрядно понаступал сам. Кроме того, можно ознакомиться с кодом libaio или же использовать ее интерфейсы (весьма спорные и мало облегчающие разработку, к сожалению).

    Источник

    Linux Asynchronous I/O

    Introduction

    Asynchronous I/O (AIO) is a method for performing I/O operations so that the process that issued an I/O request is not blocked till the operation is complished. Instead, after an I/O request is submitted, the process continues to execute its code and can later check the status of the submitted request.

    There are several means to accomplish asynchronous I/O in Linux:

    • kernel syscalls
    • user space library implementation and use system calls internally (libaio)
    • emulated AIO entirely in the user space without any kernel support (librt for now, part of libc)

    Table of Contents

    I/O Models

    Mode Blocking Non-blocking
    Synchronous read/write read/write
    (O_NONBLOCK)
    Asynchronous I/O multiplexing
    (select/poll/epoll)
    AIO

    AIO System Calls

    ABI Interface

    AIO system call entry points are located in fs/aio.c file in the kernel’s source code. Types and constants exported to the user space reside in /usr/include/linux/aio_abi.h header file.

    Linux kernel provides only 5 system calls for performing asynchronoes I/O.

    main 2 io_submit

    Every I/O request that is submitted to an AIO context is represented by an I/O control block structure — struct iocb

    io_submit() takes AIO context ID, size of the array and the array itself as the arguments. Notice, that array should contain pointers to the iocb structures, not the structures themself.

    io_submit() ’s return code can be one of the following values:

    ret = (number of iocbs sumbmitted)

    Ideal case, all iocbs were accepted for processing.

    0 io_getevent() system call should be used. When calling io_getevents() , one needs to specify:

    1. which AIO context to get events from (ctx variable)
    2. a buffer where the kernel should load events to (events varaiable)

    minimal number of events one wants to get.

    If less then this number of iocbs are currently completed, io_getevents() will block till enough events appear. See point e) for more details on how to control blocking time.

    maximum number of events one wants to get. This usually is the size of the events buffer (second 1 in our program)

  • If not enough events are available, we don’t want to wait forever. One can specify a relative deadline as the last argument. NULL in this case means to wait infinitely. If one wants io_getevents() not to block at all then timespec timeout structure need to be initialzed to zero seconds and zero nanoseconds.
  • The return code of io_getevents can be:

    ret = (max number of events)

    All events that fit in the user provided buffer were obtained from the kernel. There might be more pending events in the kernel.

    (min number of events) struct io_event

    struct iocb

    AIO Command

    • IOCB_CMD_PREAD positioned read; corresponds to pread() system call.
    • IOCB_CMD_PWRITE positioned write; corresponds to pwrite() system call.
    • IOCB_CMD_FSYNC sync file’s data and metadata with disk; corresponds to fsync() system call.
    • IOCB_CMD_FDSYNC sync file’s data and metadata with disk, but only metadata needed to access modified file data is written; corresponds to fdatasync() system call.
    • IOCB_CMD_PREADV vectored positioned read, sometimes called “scattered input”; corresponds to preadv() system call.
    • IOCB_CMD_PWRITEV vectored positioned write, sometimes called “gathered output”; corresponds to pwritev() system call.
    • IOCB_CMD_NOOP defined in the header file, but is not used anywhere else in the kernel.

    The semantics of other fields in the iocb structure depends on the command specified.

    AIO Context

    AIO context is a set of data structures that the kernel supports to perform AIO.

    Every process can have multiple AIO contextes and as such one needs an identificator for every AIO context in a process.

    A pointer to ctx variable is passed to io_setup() as a second argument and kernel fills this variable with a context identifier. Interestingly, aio_context_t is actually just an unsigned long defined in the kernel ( linux/aio_abi.h ) like that:

    The first argument of io_setup() function is the maximum number of requests that can simultaneously reside in the context.

    syscall()

    syscall() is a small library function that invokes the system call whose assembly language interface has the specified number with the specified arguments. Employing syscall() is useful, for example, when invoking a system call that has no wrapper function in the C library.

    syscall() saves CPU registers before making the system call, restores the registers upon return from the system call, and stores any error code returned by the system call in errno(3) if an error occurs.

    Symbolic constants for system call numbers can be found in the header file .

    Example

    System Tuning

    libaio

    Install

    Syscall Wrappers

    Helper Functions

    struct iocb

    Example

    POSIX asynchronous I/O

    Library

    Interfaces

    The POSIX AIO interface consists of the following functions:

    • aio_read(3) Enqueue a read request. This is the asynchronous analog of read(2).
    • aio_write(3) Enqueue a write request. This is the asynchronous analog of write(2).
    • aio_fsync(3) Enqueue a sync request for the I/O operations on a file descriptor. This is the asynchronous analog of fsync(2) and fdatasync(2).
    • aio_error(3) Obtain the error status of an enqueued I/O request.
    • aio_return(3) Obtain the return status of a completed I/O request.
    • aio_suspend(3) Suspend the caller until one or more of a specified set of I/O requests completes.
    • aio_cancel(3) Attempt to cancel outstanding I/O requests on a specified file descriptor.
    • lio_listio(3) Enqueue multiple I/O requests using a single function call.

    The current Linux POSIX AIO implementation is provided in user space by glibc. This has a number of limitations, most notably that maintaining multiple threads to perform I/O operations is expensive and scales poorly. Work has been in progress for some time on a kernel state-machine-based implementation of asynchronous I/O (see io_submit(2), io_setup(2), io_cancel(2), io_destroy(2), io_getevents(2)), but this implementation hasn’t yet matured to the point where the POSIX AIO implementation can be completely reimplemented using the kernel system calls.

    Источник

    Читайте также:  Dell драйвера для установки windows
    Оцените статью