wait_event и блокировка взаимодействия - PullRequest
0 голосов
/ 16 марта 2020

Я новичок в linux разработке ядра и удивляюсь, как wait_event/wait_event_interruptible взаимодействует с другими примитивами блокировки в ядре. Я привык к C ++ std::condition_variable::wait и хочу добиться чего-то похожего в ядре.

У меня есть очередь приемных буферов, которые заполняются с использованием передач DMA. Список защищен с помощью спин-блокировки. Готовые буферы добавляются готовым мягким IRQ DMA. Я создал символьное устройство, которое позволяет читать готовые буферы. Пока это работает, как и ожидалось, но я хочу поддержать блокировку чтения.

Я читал о wait_event, что похоже на то, что я хочу, но я действительно запутался, как wait_event не берет никакой блокировки Параметр / mutex. Как оценивается состояние без удержания блокировки? Я полагаю, что могу добавить необходимую блокировку к своему состоянию, но затем мне нужно снова заблокировать, как только wait_event вернется, чтобы извлечь данные. Это уже случай для prepare_to_wait/schedule/finish_wait?

1 Ответ

0 голосов
/ 16 марта 2020

Не вдаваясь сначала в источник, я скажу, что вы должны использовать библиотеку wait_event, и вам не нужны мьютексы или другие подобные вещи, о которых заботится ядро. Лично у меня есть только опыт работы с wait_event_interruptible и wake_up_interruptible , но я подозреваю, что все они похожи.

Теперь на источник, который я извлекаю из https://elixir.bootlin.com/linux/latest/source/include/linux/wait.h#L302

#define ___wait_event(wq_head, condition, state, exclusive, ret, cmd)       \
({                                      \
    __label__ __out;                            \
    struct wait_queue_entry __wq_entry;                 \
    long __ret = ret;   /* explicit shadow */               \
                                        \
    init_wait_entry(&__wq_entry, exclusive ? WQ_FLAG_EXCLUSIVE : 0);    \
    for (;;) {                              \
        long __int = prepare_to_wait_event(&wq_head, &__wq_entry, state);\
                                        \
        if (condition)                          \
            break;                          \
                                        \
        if (___wait_is_interruptible(state) && __int) {         \
            __ret = __int;                      \
            goto __out;                     \
        }                               \
                                        \
        cmd;                                \
    }                                   \
    finish_wait(&wq_head, &__wq_entry);                 \
__out:  __ret;                                  \
})

long prepare_to_wait_event(struct wait_queue_head *wq_head, struct wait_queue_entry *wq_entry, int state)
{
    unsigned long flags;
    long ret = 0;

    spin_lock_irqsave(&wq_head->lock, flags);
....
    spin_unlock_irqrestore(&wq_head->lock, flags);

    return ret;
}

Как видно, библиотека ожидания уже использует spin_locks, которые похожи на mutex (хотя и немного отличаются). Хорошая вещь в использовании библиотеки ожидания заключается в том, что для вас автоматически выполняется множество проверок безопасности, чтобы ядро ​​работало и работало, но оно по-прежнему выполняет необходимый блок для ваших данных. Если вам нужно больше примеров использования wait_event_ * и связанных с ним вызовов wake_up_ *, дайте мне знать, и я смогу его получить.

...