Подтвердить что ты не робот

Что использует ERESTARTSYS во время написания драйвера linux?

Я изучаю функции блокировки ввода-вывода для записи драйвера устройства linux, и мне интересно, что такое использование ERESTARTSYS. Рассмотрим следующее:

Глобальная переменная:

wait_queue_head_t my_wait_q_head;
int read_avail = 0;


device_init():

init_waitqueue_head(&my_wait_q_head);


device_read():

printk("I'm inside driver read!\n");
wait_event_interruptible(&my_wait_q_head, read_avail != 0);
printk("I'm awaken!\n");


device_write():

read_avail = 1;
wake_up_interruptible(&my_wait_q_head);


Когда я вызываю read() из пользовательского пространства, приглашение команды зависает, пока я не вызову write(), как ожидалось. Сообщения printk отображаются также в dmesg. Тем не менее, я вижу некоторые из драйверов, написанных так:

Другая версия device_read():

printk("I'm inside driver read!\n");
if(wait_event_interruptible(&my_wait_q_head, read_avail != 0))    
{return -ERESTARTSYS;}
printk("I'm awaken!\n");

Я тестировал вторую версию device_read(), используя тот же метод в пользовательском пространстве, и результат точно такой же, так что, что такое использование ERESTARTSYS?

p/s: я прочитал книгу "Драйвер устройства Linux", но я не понимаю, может ли кто-нибудь дать пример для того, чтобы сделать несколько?:

Как только мы закончим этот звонок, что-то разбудило нас, но мы не Знаешь что. Одна из возможностей заключается в том, что процесс получил сигнал. if, который содержит проверку wait_event_interruptible call для этого случая. Это утверждение обеспечивает правильную и ожидаемую реакцию к сигналам, которые могли быть ответственны за пробуждение (поскольку мы были в прерывистом сне). Если сигнал имеет прибыл, и он не был заблокирован процессом, надлежащим поведение заключается в том, чтобы позволить верхним уровням ядра обрабатывать событие. к В этом случае драйвер возвращает -ERESTARTSYS вызывающему абоненту; это значение используемый внутренне уровнем виртуальной файловой системы (VFS), который либо перезапускает системный вызов или возвращает -EINTR в пользовательское пространство. Мы используем такой же тип проверки для обработки сигналов для каждого считывания и записать реализацию.

Источник: http://www.makelinux.net/ldd3/chp-6-sect-2

4b9b3361

Ответ 1

-ERESTARTSYS связан с концепцией перезапускаемого системного вызова. Перезапустимый системный вызов - это тот, который ядром может быть прозрачно повторно выполняться при прерывании.

Например, процесс пользовательского пространства, который спит в системном вызове, может получить сигнал, выполнить обработчик, а затем, когда обработчик вернется, он, похоже, возвращается в ядро ​​и продолжает спать при исходном системном вызове.

Используя флаг POSIX sigaction API SA_RESTART, процессы могут упорядочить поведение перезапуска, связанное с сигналами.

В ядре Linux, когда драйвер или другой модуль, блокирующий в контексте системного вызова, обнаруживает, что задача проснулась из-за сигнала, она может вернуть -EINTR. Но -EINTR пузырится до пользовательского пространства и заставляет системный вызов возвращать -1 с errno, установленным в EINTR.

Если вы вернете -ERESTARTSYS вместо этого, это означает, что ваш системный вызов перезапускается. Код ERESTARTSYS не обязательно будет отображаться в пользовательском пространстве. Он либо переводится на -1-й возврат, либо errno, установленный в EINTR (тогда, очевидно, он отображается в пространстве пользователя), или он преобразуется в поведение перезапуска системного вызова, что означает, что ваш syscall вызывается снова с теми же аргументами (по никаких действий в части процесса пользовательского пространства: ядро ​​делает это, помещая информацию в специальный блок перезапуска).

Обратите внимание на очевидную проблему с "теми же аргументами" в предыдущем абзаце: некоторые системные вызовы не могут быть перезапущены с теми же параметрами, потому что они не являются идемпотентными! Например, предположим, что есть вызов сна, например, наноселек, в течение 5,3 секунд. Он прерывается через 5 секунд. Если он будет перезагружен наивно, он будет спать еще пять секунд. Он должен передать новые параметры перезапущенному вызову для ожидания только на оставшиеся 0,3 секунды; т.е. изменить содержимое блока перезапуска. Есть способ сделать это: вы добавляете разные аргументы в блок перезапуска задачи и используете возвращаемое значение -ERESTART_RESTARTBLOCK.

Чтобы решить второй вопрос: какая разница? Почему бы просто написать программу чтения без проверки возвращаемого значения и возврата -ERESTARTSYS? Ну, потому что это неверно в случае, когда пробуждение происходит из-за сигнала! Вы хотите, чтобы чтение возвращало 0 байтов, читаемых всякий раз, когда поступает сигнал? Это может быть неверно истолковано пользовательским пространством как конец данных. Такая проблема не будет отображаться в тестовых случаях, которые не используют сигналы.