/*
* 2020/12/4 17:35 qing
*/
/*
* mutex
*
* semaphore在初始化count计数的时候,可以分为计数信号量和互斥信号量(二值信号量)。mutex和初始化计数为1的二值信号量有很大的相似之处。
* 他们都可以用做资源互斥。但是mutex却有一个特殊的地方:只有持锁者才能解锁。但是,二值信号量却可以在一个进程中获取信号量,
* 在另一个进程中释放信号量。如果是应用在嵌入式应用的RTOS,针对mutex的实现还会考虑优先级反转问题。
*/
/*
* mutex是一种二值信号量,因此就不需要像semaphore那样需要一个count计数。由于mutex具有"持锁者才能解锁"的特点,
* 所以我们需要一个变量owner记录持锁进程。释放锁的时候必须是同一个进程才能释放。当然也需要一个链表头,主要用来便利睡眠等待的进程。
*
* 原理和semaphore及其相似
*
*/
struct mutex {
/* 1: unlocked, 0: locked, negative: locked, possible waiters */
atomic_t count;
spinlock_t wait_lock;
struct list_head wait_list;
#if defined(CONFIG_DEBUG_MUTEXES) || defined(CONFIG_MUTEX_SPIN_ON_OWNER)
struct task_struct *owner;
#endif
#ifdef CONFIG_MUTEX_SPIN_ON_OWNER
struct optimistic_spin_queue osq; /* Spinner MCS lock */
#endif
#ifdef CONFIG_DEBUG_MUTEXES
void *magic;
#endif
#ifdef CONFIG_DEBUG_LOCK_ALLOC
struct lockdep_map dep_map;
#endif
};
/*
* spinlock_t
*/
typedef struct spinlock {
union {
struct raw_spinlock rlock;
#ifdef CONFIG_DEBUG_LOCK_ALLOC
# define LOCK_PADSIZE (offsetof(struct raw_spinlock, dep_map))
struct {
u8 __padding[LOCK_PADSIZE];
struct lockdep_map dep_map;
};
#endif
};
} spinlock_t;
/*
* mutex_waiter
*/
struct mutex_waiter {
struct list_head list;
struct task_struct *task;
#ifdef CONFIG_DEBUG_MUTEXES
void *magic;
#endif
};
/*
* mutex_lock
*/
void __sched mutex_lock(struct mutex *lock)
{
might_sleep();
/*
* The locking fastpath is the 1->0 transition from
* 'unlocked' into 'locked' state.
*/
__mutex_fastpath_lock(&lock->count, __mutex_lock_slowpath);
mutex_set_owner(lock);
}
#define __sched __attribute__((__section__(".sched.text")))
# define might_sleep() do { might_resched(); } while (0)
# define might_resched() do { } while (0)
static inline void
__mutex_fastpath_lock(atomic_t *count, void (*fail_fn)(atomic_t *))
{
if (unlikely(atomic_dec_return_acquire(count) < 0))
fail_fn(count);
}
__visible void __sched
__mutex_lock_slowpath(atomic_t *lock_count)
{
struct mutex *lock = container_of(lock_count, struct mutex, count);
__mutex_lock_common(lock, TASK_UNINTERRUPTIBLE, 0,
NULL, _RET_IP_, NULL, 0);
}
#define _RET_IP_ (unsigned long)__builtin_return_address(0)
#define _THIS_IP_ ({ __label__ __here; __here: (unsigned long)&&__here; })
static inline void mutex_set_owner(struct mutex *lock)
{
WRITE_ONCE(lock->owner, current);
}
/*
* mutex_unlock
*/
void __sched mutex_unlock(struct mutex *lock)
{
/*
* The unlocking fastpath is the 0->1 transition from 'locked'
* into 'unlocked' state:
*/
#ifndef CONFIG_DEBUG_MUTEXES
/*
* When debugging is enabled we must not clear the owner before time,
* the slow path will always be taken, and that clears the owner field
* after verifying that it was indeed current.
*/
mutex_clear_owner(lock);
#endif
__mutex_fastpath_unlock(&lock->count, __mutex_unlock_slowpath);
}
static inline void
__mutex_fastpath_unlock(atomic_t *count, void (*fail_fn)(atomic_t *))
{
if (unlikely(atomic_inc_return_release(count) <= 0))
fail_fn(count);
}
__visible void
__mutex_unlock_slowpath(atomic_t *lock_count)
{
struct mutex *lock = container_of(lock_count, struct mutex, count);
__mutex_unlock_common_slowpath(lock, 1);
}
/*
* 递归锁(recursivelock)
*/
严格上讲递归锁只是互斥锁的一个特例,同样只能有一个线程访问该对象,但允许同一个线程在未释放其拥有的锁时反复对该锁进行加锁操作;
windows下的临界区默认是支持递归锁的,
而linux下的互斥量则需要设置参数PTHREAD_MUTEX_RECURSIVE_NP,默认则是不支持