Чтение символа в обработчике прерываний заставляет очередь ожидания ждать вечно

#kernel #driver #wait #interrupt #uart

#ядро #драйвер #подождите #прерывание #uart

Вопрос:

Я программирую драйвер для устройства последовательной связи, которое работает следующим образом:

1 — Я вызываю функцию чтения из пользовательского пространства.

2 — Система переходит в режим ожидания, пока в FIFO не появится первый символ.

3 — Появляется символ, и система его считывает.

4 — Теперь система должна ждать (в состоянии ожидания без занятости), пока не появится следующий символ, таким образом, используется очередь ожидания.

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

Изначально у меня была следующая схема для кода:

 read_function(int number) {
    busy_wait(!fifo_empty)
    for(i = 0, i < number) {
         char_read = global_buffer;
         wait_event_interruptible(queue,!fifo_empty);
    }

 irq_handler() {
    wake_up(queue);
    global_buffer = read_fifo();
    return IRQ_HANDLED;
 }
 

Однако у этого была следующая проблема: после того, как я прочитал fifo в обработчике, условие «fifo_empty» становится истинным. Это означает, что, хотя я разбудил процесс в тот момент, когда он был ложным, перед тем, как я выйду из обработчика, условие вернется к true, и тогда процесс чтения не будет продолжен.

Затем я решил удалить буфер и поместить вызов read_fifo() в функцию чтения. Однако это вызывает некоторые проблемы, а именно:

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

б) Если символ поступает, когда функция чтения не была вызвана, ядро завершает работу, потому что прерывание входит в цикл.

c) По какой-то причине, даже после ввода number символов, система не выйдет из цикла.

Затем я хотел бы знать, должен ли я помещать вызов fifo_read в обработчик или read. Я твердо верю (основываясь на других ответах на этом сайте), что его следует поместить в обработчик. Но тогда как я могу разбудить процесс? Очевидно, что использование некоторых глобальных переменных помогло бы, но мне интересно, есть ли лучший способ сделать это.

Комментарии:

1. Обычно следует вызывать wake_up только после внесения изменений, которые могут повлиять на условие. Похоже, что ваш код делает прямо противоположное тому, что в обработчике. Это может быть причиной предполагаемого случайного поведения.

2. @embedded_dev проблема случайных событий была, как объяснялось, не в случае псевдокода.