wait_event and lock interaction

倾然丶 夕夏残阳落幕 提交于 2021-01-28 05:09:22

问题


I'm new to linux kernel development and wonder how wait_event/wait_event_interruptible interacts with other locking primitives in the kernel. I'm used to C++ std::condition_variable::wait and want to achieve something similar in the kernel.

I have a queue of receive buffers which are filled using DMA transfers. The list is protected using a spin lock. Finished buffers are added by the DMA finished soft IRQ. I created a character device which allows reading of the finished buffers. So far this works as expected but I want to support blocking reads.

I've read about wait_event which seems like what I want, but I'm really confused how wait_event does not take any lock/mutex parameter. How is evaluating the condition without holding a lock safe? I suppose I can add the necessary locking to my condition, but then I need to lock again once wait_event returns to extract the data. Is this already a case for prepare_to_wait/schedule/finish_wait?


回答1:


Without digging to much into the source first I will say you should be using the wait_event library and you do not need mutex's or other such things the kernel is taking care of them. Personally I only have experience with wait_event_interruptible and wake_up_interruptible but I suspect they all are similar.

Now onto the source which I am pulling from 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;
}

As can be seen the wait library is using spin_locks already which are similar to mutex's (although slightly different). The nice thing about using the wait library is that a lot of safety checks to keep the kernel happy and going are automatically performed for you but it still performs the necessary block on your data. If you need more of an example on using the wait_event_* and it's assosciated wake_up_* calls let me know and I can fetch one.



来源:https://stackoverflow.com/questions/60708825/wait-event-and-lock-interaction

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!