Как на самом деле работает блокирующий ввод / вывод Linux? - PullRequest
8 голосов
/ 06 мая 2010

В Linux, когда вы делаете блокирующий вызов ввода-вывода, например чтение или принятие, что на самом деле происходит?

Мои мысли: процесс выводится из очереди выполнения, переводится в состояние ожидания или блокировки в какой-либо очереди ожидания. Затем, когда установлено TCP-соединение (для принятия) или жесткий диск готов или что-то для чтения файла, возникает аппаратное прерывание, которое позволяет тем процессам, которые ожидают пробуждения и запуска (в случае чтения файла, как Linux знает, какие процессы нужно разбудить, так как может быть много процессов, ожидающих разных файлов?). Или, возможно, вместо аппаратных прерываний, отдельный процесс сам запрашивает доступность. Не уверены, помогите?

Ответы [ 3 ]

13 голосов
/ 06 мая 2010

Кажется, что каждое устройство Linux реализовано немного по-разному, и предпочтительный способ, по-видимому, меняется каждые несколько выпусков Linux по мере добавления более безопасных / более быстрых функций ядра, но обычно:

  1. Драйвер устройства создает чтение и записывать очереди ожидания для устройства.
  2. Любой поток процесса, желающий ждать для ввода / вывода ставится на соответствующий очередь ожидания Когда происходит прерывание обработчик просыпается один или несколько ожидающие темы. (Очевидно, потоки не запускаются сразу, поскольку мы прерываем контекст, но добавляются к очередь планирования ядра).
  3. Когда запланировано ядром поток проверяет, если условия правы, чтобы продолжить - если нет он возвращается в очередь ожидания.

Типичный пример (слегка упрощенный):

В драйвере при инициализации:

    init_waitqueue_head(&readers_wait_q);

В функции чтения драйвера:

    if (filp->f_flags & O_NONBLOCK)
    {
        return -EAGAIN;
    }
    if (wait_event_interruptible(&readers_wait_q, read_avail != 0))
    {
        /* signal interrupted the wait, return */
        return -ERESTARTSYS;
    }
    to_copy = min(user_max_read, read_avail);
    copy_to_user(user_buf, read_ptr, to_copy);

Тогда обработчик прерываний просто выдает:

    wake_up_interruptible(&readers_wait_q);

Обратите внимание, что wait_event_interruptible () - это макрос, который скрывает цикл, проверяющий условие - в данном случае read_avail != 0, и многократно добавляет его в очередь ожидания, если он проснулся, когда условие не выполнено.

Как уже упоминалось, существует ряд вариаций, основной из которых является то, что если потенциально обработчику прерываний потенциально предстоит проделать большую работу, он сам выполняет минимальный минимум и откладывает остальное в рабочую очередь или тасклет (обычно известная как «нижняя половина»), и именно она разбудит ожидающие потоки.

См. Книгу драйверов устройств Linux для получения дополнительной информации - pdf доступен здесь: http://lwn.net/Kernel/LDD3

0 голосов
/ 06 мая 2010

Эффективно метод будет возвращаться только тогда, когда файл готов к чтению, когда данные находятся в сокете, когда получено соединение ...

Чтобы убедиться, что он может вернуться немедленно, вы, вероятно, захотите использовать системный вызов Select для поиска готового дескриптора файла.

0 голосов
/ 06 мая 2010

Читать это: http://www.minix3.org/doc/

Это очень ясное объяснение. Как правило, это относится и к Linux.

...