Читайте chardevice с libevent - PullRequest
       17

Читайте chardevice с libevent

0 голосов
/ 05 мая 2018

Я написал 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
}
...