Как использовать FIFO в драйвере символьного устройства Linux, чтобы два процесса, использующие драйвер, могли общаться

У меня есть драйвер устройства char для виртуального устройства. Я хочу FIFO в драйвере устройства, чтобы процесс 2, использующий драйвер устройства, мог передавать символы между ними. Я попробовал kfifo, но я новичок в этом, и мне трудно его использовать. Может ли кто-нибудь предложить, пожалуйста, какой-то другой способ реализации драйвера FIFO в Linux.

1 ответ

Решение

Если вы собираетесь разрешить использование драйвера только двум процессам, то вы можете сделать так: open обработчик, убедитесь, что два и только два процесса могут войти в драйвер:

If access mode = READ and not alreadyreading then
  alreadyreading = 1
else
  return -EBUSY

If access mode = WRITE and not alreadywritting then
  alreadywritting = 1
else
  return -EBUSY

В том же обработчике инициализируйте ваш FIFO, который может быть просто одной глобальной символьной переменной и двумя очередями ожидания: одна для чтения и одна для записи. С этими очередями будут связаны две переменные: ready_to_read и ready_to_write. В начале ready_to_read = 0 и ready_to_write = 1.

Затем в release обработчик:

If access mode = READ
  alreadyreading = 0;
If access mode = WRITE
  alreadywritting = 0

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

в write обработчик:

If access mode = READ then  // we only support writting if the access mode is write
  return -EINVAL
Else
  res = wait_event_interruptible (write_queue, ready_to_write);
  if (res)
    return res;  // if process received a signal, exit write
  Take a single character from user space (copy_from_user() )
  Copy it to the FIFO (the global character variable)
  ready_to_write = 0;  // no more writtings until a read is performed
  ready_to_read = 1;   // ready to read! wake up the reading process
  wake_up_interruptible (&read_queue);
  return 1;  // 1 byte written

И, наконец, в read обработчик:

If access mode = READ then  // we only support reading if the access mode is read
  return -EINVAL
Else
  res = wait_event_interruptible (read_queue, ready_to_read);
  if (res)
    return res;  // if process received a signal, exit write
  Take character from global variable (our FIFO) and send it to userspace (copy_to_user() )
  ready_to_read = 0;  // no more reads until a write is performed
  ready_to_write = 1;   // ready to write! wake up the writting process
  wake_up_interruptible (&write_queue);
  return 1;  // 1 byte read

Вы можете расширить этот пример, чтобы разрешить FIFO или более одного символа: вам понадобится массив символов и два индекса: один, чтобы знать, откуда читать, а другой, чтобы знать, куда писать.

Чтобы проверить свой драйвер, вы можете открыть два xterms и сделать

cat /dev/mydriver

в одном и:

cat > /dev/mydriver

В другой. Затем каждая строка, которую вы напишите во втором xterm, будет показана в первой.

Вы даже можете изменить драйвер, чтобы, когда процесс записи закрывал файл, устанавливался флаг, чтобы в следующий раз, когда процесс чтения ожидал что-то прочитать, он обнаружил, что процесс записи завершен, а затем он также возвращает 0 (для EOF для пользователя), поэтому, когда вы нажимаете Ctrl-D во втором xterm, чтобы закончить ввод, первый также заканчивается автоматически. Что-то вроде:

(read обработчик)

res = wait_event_interruptible (read_queue, ready_to_read || write_process_ended);
if (res)
  return res;  // -ERSTARTSYS if signal
if (write_process_ended)
{
  ready_to_write = 1;
  return 0;    // if write process ended, send an EOF to the user
}
else
{
  ...
  ... get byte from FIFO, send to the user, etc.
  ...
  return number_of_bytes_sent_to_user;
}
Другие вопросы по тегам