В Linux, когда Вы делаете блокирование i/o вызовом как чтение или принимаете, что на самом деле происходит?
Мои мысли: процесс вынут из очереди выполнения, поместите в ожидание, или блокирующее состояние на некоторых ожидают очередь. Затем, когда соединение TCP сделано (для, принимают), или жесткий диск готов, или что-то для чтения файла, аппаратное прерывание повышено, который позволяет тем процессам, ожидающим, чтобы проснуться и работать (в случае чтения файла, как Linux знает, какие процессы пробудить, как могло быть много процессов, ожидающих на различных файлах?). Или возможно вместо аппаратных прерываний, сам отдельный процесс опрашивает для проверения наличия. Не уверенный, справка?
Фактически метод вернется только тогда, когда файл будет готов к чтению, когда данные находятся в сокете, когда установлено соединение ...
Чтобы убедиться, что он может вернуться немедленно, вы, вероятно, захотите использовать системный вызов Select , чтобы найти готовый дескриптор файла.
Прочтите это: http://www.minix3.org/doc/
Это очень, ясное и очень легкое для понимания объяснение. Обычно это также относится и к Linux.
Каждое устройство Linux, похоже, реализовано немного по-разному, и предпочтительный способ, похоже, меняется каждые несколько релизов Linux по мере добавления более безопасных/быстрых функций ядра, но в целом:
Типичный пример (немного упрощенный):
В драйвере при инициализации:
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
в данном случае - и повторно добавляет в очередь ожидания, если разбужен, когда условие не истинно.
Как уже упоминалось, существует ряд вариаций - главная из них заключается в том, что если обработчик прерывания потенциально должен выполнить много работы, то он сам делает самый минимум, а остальное откладывает на рабочую очередь или tasklet (обычно известный как "нижняя половина"), и именно он будит ожидающие потоки.
См. книгу Linux Device Driver для более подробной информации - pdf доступен здесь: http://lwn.net/Kernel/LDD3