Имитация эффекта выбора ()и опроса ()в программировании сокетов ядра

Один из разрабатываемых мной драйверов ядра Linux использует сетевое взаимодействие в ядре (sock_create()., sock->ops->bind()и так далее ).

Проблема в том, что будет несколько сокетов для получения данных. Поэтому мне нужно что-то, что будет имитировать select()или poll()в пространстве ядра. Поскольку эти функции используют файловые дескрипторы, я не могу использовать системные вызовы, если я не использую системные вызовы для создания сокетов, но это кажется ненужным, поскольку я работаю в ядре.

Поэтому я подумал о том, чтобы обернуть обработчик по умолчанию sock->sk_data_readyв свой собственный обработчик (custom_sk_data_ready())., который разблокирует семафор. Затем я могу написать свою собственную функцию kernel_select(), которая пытается заблокировать семафор и блокирует ожидание, пока он не будет открыт. Таким образом, функция ядра переходит в спящий режим до тех пор, пока семафор не будет разблокирован с помощью custom_sk_data_ready(). Как только kernel_select()получает блокировку, она разблокируется и вызывает custom_sk_data_ready(), чтобы повторно заблокировать ее. Таким образом, единственная дополнительная инициализация — запустить custom_sk_data_ready()перед привязкой сокета, чтобы первый вызов custom_select()не срабатывал ложно.

Я вижу одну возможную проблему. Если происходит несколько приемов, то несколько вызовов custom_sk_data_ready()попытаются разблокировать семафор. Таким образом, чтобы не потерять несколько вызовов и отслеживать использование sock, должна быть таблица или список указателей на используемые сокеты. И custom_sk_data_ready()должен будет указать в таблице/списке, какой сокет был передан.

Является ли этот метод надежным? Или я должен просто бороться с проблемой пространства пользователя/ядра при использовании стандартных системных вызовов?

Первоначальный вывод:

Все функции обратного вызова в структуре sockвызываются в контексте прерывания. Это означает, что они не могут спать.Чтобы основной поток ядра мог спать в списке готовых сокетов, используются мьютексы, но custom_sk_data_ready()должен действовать как спин-блокировка мьютексов (, многократно вызывающих mutex_trylock()). Это также означает, что любое динамическое выделение должно использовать флаг GFP_ATOMIC.


Дополнительная возможность:

Для каждого открытого сокета замените sk_data_ready()каждого сокета на пользовательский (custom_sk_data_ready()). и создайте рабочего(struct work_struct)и очередь работ(struct workqueue_struct). Для каждого работника будет использоваться общая функция process_msg(). Создайте глобальный список уровня модуля ядра -, где каждый элемент списка имеет указатель на сокет и содержит рабочую структуру. Когда данные в сокете будут готовы, custom_sk_data_ready()выполнит и найдет соответствующий элемент списка с тем же сокетом, а затем вызовет queue_work()с рабочей очередью элемента списка и рабочим процессом. Затем будет вызвана функция process_msg(), которая может либо найти соответствующий элемент списка по содержимому параметра struct work_struct *(по адресу ), либо использовать макрос container_of()для получения адреса списка структура, которая содержит рабочую структуру.

Какая техника самая правильная?

12
задан Joshua 6 July 2012 в 22:03
поделиться