Как использовать 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;
}