Я написал chardevice, который передает некоторые сообщения, полученные из сети, в приложение пространства пользователя. Приложение пользовательского пространства должно одновременно считывать данные chardevice и отправлять / получать сообщения через TCP-сокеты другим приложениям пользовательского пространства. И чтение, и получение должны блокировать.
Поскольку Libevent может обрабатывать несколько событий одновременно, я подумал, что зарегистрировать событие для файла, созданного chardevice, и событие для сокета будет просто работать, но я ошибся.
Но chardevice создает «специальный символьный файл», и libevent, похоже, не сможет его заблокировать. Если я реализую блокирующий механизм внутри chardevice, то есть мьютекса или семафора, то и событие сокета тоже блокируется, и приложение не может получать сообщения.
Приложение пространства пользователя должно принимать внешние подключения в любое время.
Ты знаешь, как заставить это работать? Может быть, также с использованием другой библиотеки, я просто хочу, чтобы поведение блокировки для сокета и чтения файлов.
Заранее спасибо.
Обновление: Спасибо @Ahmed Masud за помощь. Это то, что я сделал
Ядро модуля chardevice:
Реализовать функцию опроса, которая ожидает появления новых данных
struct file_operations fops = {
...
.read = kdev_read,
.poll = kdev_poll,
};
У меня есть глобальная переменная для обработки, если пользовательское пространство должно быть остановлено, и очередь ожидания:
static working = 1;
static wait_queue_head_t access_wait;
Это функция чтения, я возвращаю -1, если в copy_to_user есть ошибка,> 0, если все прошло хорошо, и 0, если модуль должен остановиться. used_buff является атомарным, поскольку он обрабатывает размер общего буфера, читаемого пользовательским приложением и записываемого модулем ядра.
ssize_t
kdev_read(struct file* filep, char* buffer, size_t len, loff_t* offset)
{
int error_count;
if (signal_pending(current) || !working) { // user called sigint
return 0;
}
atomic_dec(&used_buf);
size_t llen = sizeof(struct user_msg) + msg_buf[first_buf]->size;
error_count = copy_to_user(buffer, (char*)msg_buf[first_buf], llen);
if (error_count != 0) {
atomic_inc(&used_buf);
paxerr("send fewer characters to the user");
return error_count;
} else
first_buf = (first_buf + 1) % BUFFER_SIZE;
return llen;
}
Когда есть данные для чтения, я просто увеличиваю used_buf
и вызываю wake_up_interruptible(&access_wait)
.
Это функция опроса, я просто жду, пока used_buff> 0
unsigned int
kdev_poll(struct file* file, poll_table* wait)
{
poll_wait(file, &access_wait, wait);
if (atomic_read(&used_buf) > 0)
return POLLIN | POLLRDNORM;
return 0;
}
Теперь проблема в том, что, если я выгружу модуль во время ожидания приложения из пользовательского пространства, последний перейдет в заблокированное состояние, и остановить его будет невозможно. Вот почему я разбудил приложение, когда модуль выгружен
void
kdevchar_exit(void)
{
working = 0;
atomic_inc(&used_buf); // increase buffer size to application is unlocked
wake_up_interruptible(&access_wait); // wake up application, but this time read will return 0 since working = 0;
... // unregister everything
}
Приложение пространства пользователя
Libevent по умолчанию использует опрос, поэтому просто создайте event_base и событие для чтения.
base = event_base_new();
filep = open(fname, O_RDWR | O_NONBLOCK, 0);
evread = event_new(base, filep, EV_READ | EV_PERSIST,
on_read_file, base);
, где on_read_file просто читает файл, вызов опроса не выполняется (libevent обрабатывает это):
static void
on_read_file(evutil_socket_t fd, short event, void* arg)
{
struct event_base* base = arg;
int len = read(...);
if (len < 0)
return;
if (len == 0) {
printf("Stopped by kernel module\n");
event_base_loopbreak(base);
return;
}
... // handle message
}