Linux内核:解锁未锁定的互斥锁

时间:2014-08-16 03:04:53

标签: linux linux-kernel mutex spinlock

我正在努力理解"解锁未锁定的互斥锁"不允许会导致不可预知的行为w.r.t Linux内核互斥,当我看代码时我没有看到任何这种效果。

具体做法是:

/**
 * try to promote the mutex from 0 to 1. if it wasn't 0, call <function>
 * In the failure case, this function is allowed to either set the value to
 * 1, or to set it to a value lower than one.
 * If the implementation sets it to a value of lower than one, the
 * __mutex_slowpath_needs_to_unlock() macro needs to return 1, it needs
 * to return 0 otherwise.
 */
static inline void
__mutex_fastpath_unlock(atomic_t *count, void (*fail_fn)(atomic_t *))
{
    if (unlikely(atomic_xchg(count, 1) != 0))
        fail_fn(count);
}

其中fail_fn是

static inline void
__mutex_unlock_common_slowpath(atomic_t *lock_count, int nested)
{
    struct mutex *lock = container_of(lock_count, struct mutex, count);
    unsigned long flags;

    spin_lock_mutex(&lock->wait_lock, flags);
    mutex_release(&lock->dep_map, nested, _RET_IP_);
    debug_mutex_unlock(lock);

    /*
     * some architectures leave the lock unlocked in the fastpath failure
     * case, others need to leave it locked. In the later case we have to
     * unlock it here
     */
    if (__mutex_slowpath_needs_to_unlock())
        atomic_set(&lock->count, 1);

    if (!list_empty(&lock->wait_list)) {
        /* get the first entry from the wait-list: */
        struct mutex_waiter *waiter =
                list_entry(lock->wait_list.next,
                       struct mutex_waiter, list);

        debug_mutex_wake_waiter(lock, waiter);

        wake_up_process(waiter->task);
    }

    spin_unlock_mutex(&lock->wait_lock, flags);
}

从我可以判断它是否已解锁,它将保持解锁状态,无论__mutex_slowpath_needs_to_unlock()是什么,我在这里错过了什么?

1 个答案:

答案 0 :(得分:0)

正如Wyzard所建议的,文档可能希望保持一些开放的方式。例如,某些other implementations可以使用原子增量而不是交换,例如this one

static inline void __mutex_fastpath_unlock(atomic_t *v,
                                           void (*fail_fn)(atomic_t *))
{
        asm_volatile_goto(LOCK_PREFIX "   incl %0\n"
                          "   jg %l[exit]\n"
                          : : "m" (v->counter)
                          : "memory", "cc"
                          : exit);

正如您所看到的,连续两次调用它是不安全的,因为accompanying try_lock除了0和1之外不期望任何其他值:

static inline int __mutex_fastpath_trylock(atomic_t *count,
                                           int (*fail_fn)(atomic_t *))
{
        if (likely(atomic_cmpxchg(count, 1, 0) == 1))