typedef struct { volatile int counter; } atomic_t;
#ifndef _ASM_X86_ATOMIC_32_H #define _ASM_X86_ATOMIC_32_H #include <linux/compiler.h> #include <linux/types.h> #include <asm/processor.h> #include <asm/cmpxchg.h> #define ATOMIC_INIT(i) { (i) } static inline int atomic_read(const atomic_t *v) { return v->counter; } static inline void atomic_set(atomic_t *v, int i) { v->counter = i; } static inline void atomic_add(int i, atomic_t *v) { asm volatile(LOCK_PREFIX "addl %1,%0" : "+m" (v->counter) : "ir" (i)); } static inline void atomic_sub(int i, atomic_t *v) { asm volatile(LOCK_PREFIX "subl %1,%0" : "+m" (v->counter) : "ir" (i)); } static inline int atomic_sub_and_test(int i, atomic_t *v) { unsigned char c; asm volatile(LOCK_PREFIX "subl %2,%0; sete %1" : "+m" (v->counter), "=qm" (c) : "ir" (i) : "memory"); return c; } ......除了原子整数之外,内核还提供了一组针对位操作的函数,这些操作也是和体系结构相关的。例如在x86下set_bit实现如下: static __always_inline void
set_bit(unsigned int nr, volatile unsigned long *addr) { if (IS_IMMEDIATE(nr)) { asm volatile(LOCK_PREFIX "orb %1,%0" : CONST_MASK_ADDR(nr, addr) : "iq" ((u8)CONST_MASK(nr)) : "memory"); } else { asm volatile(LOCK_PREFIX "bts %1,%0" : BITOP_ADDR(addr) : "Ir" (nr) : "memory"); } }
方法 | spinlock中的定义 |
定义spin lock并初始化 | DEFINE_SPINLOCK() |
动态初始化spin lock | spin_lock_init() |
获取指定的spin lock | spin_lock() |
获取指定的spin lock同时disable本CPU中断 | spin_lock_irq() |
保存本CPU当前的irq状态,disable本CPU中断并获取指定的spin lock | spin_lock_irqsave() |
获取指定的spin lock同时disable本CPU的bottom half | spin_lock_bh() |
释放指定的spin lock | spin_unlock() |
释放指定的spin lock同时enable本CPU中断 | spin_lock_irq() |
释放指定的spin lock同时恢复本CPU的中断状态 | spin_lock_irqsave() |
获取指定的spin lock同时enable本CPU的bottom half | spin_unlock_bh() |
尝试去获取spin lock,如果失败,不会spin,而是返回非零值 | spin_trylock() |
判断spin lock是否是locked,如果其他的thread已经获取了该lock,那么返回非零值,否则返回0 | spin_is_locked() |
typedef struct { raw_spinlock_t raw_lock; #ifdef CONFIG_GENERIC_LOCKBREAK unsigned int break_lock; #endif #ifdef CONFIG_DEBUG_SPINLOCK unsigned int magic, owner_cpu; void *owner; #endif #ifdef CONFIG_DEBUG_LOCK_ALLOC struct lockdep_map dep_map; #endif } spinlock_t;
DEFINE_SPINLOCK(lock); spin_lock(&lock); /* 临界区 */ spin_unlock(&lock);
void spin_lock(spinlock_t *lock); void spin_lock_irq(spinlock_t *lock); //相当于spin_lock() + local_irq_disable()。 void spin_lock_irqsave(spinlock_t *lock, unsigned long flags);//禁止中断(只在本地处理器)在获得自旋锁之前; 之前的中断状态保存在 flags里。相当于spin_lock() + local_irq_save()。 void spin_lock_bh(spinlock_t *lock); //获取锁之前禁止软件中断, 但是硬件中断留作打开的,相当于spin_lock() + local_bh_disable()。也有 4 个方法来释放一个自旋锁; 你用的那个必须对应你用来获取锁的函数.
void spin_unlock(spinlock_t *lock); void spin_unlock_irqrestore(spinlock_t *lock, unsigned long flags); void spin_unlock_irq(spinlock_t *lock); void spin_unlock_bh(spinlock_t *lock);下面看一下DEFINE_SPINLOCK()、spin_lock_init()、spin_lock()、spin_lock_irqsave()的实现:
#define DEFINE_SPINLOCK(x) spinlock_t x = __SPIN_LOCK_UNLOCKED(x) # define spin_lock_init(lock) do { *(lock) = SPIN_LOCK_UNLOCKED; } while (0) #endif spin_lock: #define spin_lock(lock) _spin_lock(lock) void __lockfunc _spin_lock(spinlock_t *lock) { __spin_lock(lock); } static inline void __spin_lock(spinlock_t *lock) { preempt_disable(); spin_acquire(&lock->dep_map, 0, 0, _RET_IP_); LOCK_CONTENDED(lock, _raw_spin_trylock, _raw_spin_lock); }spin_lock_irqsave:
#define spin_lock_irqsave(lock, flags) do { typecheck(unsigned long, flags); flags = _spin_lock_irqsave(lock); } while (0) unsigned long __lockfunc _spin_lock_irqsave(spinlock_t *lock) { return __spin_lock_irqsave(lock); } static inline unsigned long __spin_lock_irqsave(spinlock_t *lock) { unsigned long flags; local_irq_save(flags); //spin_lock的实现没有禁止本地中断这一步 preempt_disable(); spin_acquire(&lock->dep_map, 0, 0, _RET_IP_); #ifdef CONFIG_LOCKDEP LOCK_CONTENDED(lock, _raw_spin_trylock, _raw_spin_lock); #else _raw_spin_lock_flags(lock, &flags); #endif return flags; }
rwlock_t my_rwlock = RW_LOCK_UNLOCKED;动态方式:
rwlock_t my_rwlock; rwlock_init(&my_rwlock);可用函数的列表现在应当看来相当类似。 对于读者, 有下列函数可用:
void read_lock(rwlock_t *lock); void read_lock_irqsave(rwlock_t *lock, unsigned long flags); void read_lock_irq(rwlock_t *lock); void read_lock_bh(rwlock_t *lock); void read_unlock(rwlock_t *lock); void read_unlock_irqrestore(rwlock_t *lock, unsigned long flags); void read_unlock_irq(rwlock_t *lock); void read_unlock_bh(rwlock_t *lock);对于写存取的函数是类似的:
void write_lock(rwlock_t *lock); void write_lock_irqsave(rwlock_t *lock, unsigned long flags); void write_lock_irq(rwlock_t *lock); void write_lock_bh(rwlock_t *lock); int write_trylock(rwlock_t *lock); void write_unlock(rwlock_t *lock); void write_unlock_irqrestore(rwlock_t *lock, unsigned long flags); void write_unlock_irq(rwlock_t *lock); void write_unlock_bh(rwlock_t *lock);
struct semaphore { spinlock_t lock; unsigned int count; struct list_head wait_list; };
struct semaphore sem; void sema_init(struct semaphore *sem, int val);//初始化信号量,并设置信号量 sem 的值为 val。
static inline void sema_init(struct semaphore *sem, int val) { static struct lock_class_key __key; *sem = (struct semaphore) __SEMAPHORE_INITIALIZER(*sem, val); lockdep_init_map(&sem->lock.dep_map, "semaphore->lock", &__key, 0); }
DECLARE_MUTEX(name);定义一个名为 name 的信号量并初始化为1。
#define DECLARE_MUTEX(name) struct semaphore name = __SEMAPHORE_INITIALIZER(name, 1)方法三:
#define init_MUTEX(sem) sema_init(sem, 1) //以不加锁状态动态创建信号量 #define init_MUTEX_LOCKED(sem) sema_init(sem, 0) //以加锁状态动态创建信号量信号量初始化后就可以使用了,使用信号量主要有如下方法:
void down(struct semaphore * sem);//该函数用于获得信号量 sem,它会导致睡眠,因此不能在中断上下文使用; int down_interruptible(struct semaphore * sem);//该函数功能与 down 类似,不同之处为,因为 down()而进入睡眠状态的进程不能被信号打断,但因为 down_interruptible()而进入睡眠状态的进程能被信号打断,信号也会导致该函数返回,这时候函数的返回值非 0; int down_trylock(struct semaphore * sem);//该函数尝试获得信号量 sem,如果能够立刻获得,它就获得该信号量并返回0,否则,返回非0值。它不会导致调用者睡眠,可以在中断上下文使用。 up(struct semaphore * sem); //释放指定信号量,如果睡眠队列不空,则唤醒其中一个队列。信号量一般这样使用:
/* 定义信号量 DECLARE_MUTEX(mount_sem); //down(&mount_sem);/* 获取信号量,保护临界区,信号量被占用之后进入不可中断睡眠状态 down_interruptible(&mount_sem);/* 获取信号量,保护临界区,信号量被占用之后进入不可中断睡眠状态 . . . critical section /* 临界区 . . . up(&mount_sem);/* 释放信号量
void down(struct semaphore *sem) { unsigned long flags; spin_lock_irqsave(&sem->lock, flags); if (likely(sem->count > 0)) sem->count--; else __down(sem); spin_unlock_irqrestore(&sem->lock, flags); } static noinline void __sched __down(struct semaphore *sem) { __down_common(sem, TASK_UNINTERRUPTIBLE, MAX_SCHEDULE_TIMEOUT); }
int down_interruptible(struct semaphore *sem) { unsigned long flags; int result = 0; spin_lock_irqsave(&sem->lock, flags); if (likely(sem->count > 0)) sem->count--; else result = __down_interruptible(sem); spin_unlock_irqrestore(&sem->lock, flags); return result; } static noinline int __sched __down_interruptible(struct semaphore *sem) { return __down_common(sem, TASK_INTERRUPTIBLE, MAX_SCHEDULE_TIMEOUT); }down_trylock():
int down_trylock(struct semaphore *sem) { unsigned long flags; int count; spin_lock_irqsave(&sem->lock, flags); count = sem->count - 1; if (likely(count >= 0)) sem->count = count; spin_unlock_irqrestore(&sem->lock, flags); return (count < 0); }
void up(struct semaphore *sem) { unsigned long flags; spin_lock_irqsave(&sem->lock, flags); if (likely(list_empty(&sem->wait_list))) sem->count++; else __up(sem); spin_unlock_irqrestore(&sem->lock, flags); } static noinline void __sched __up(struct semaphore *sem) { struct semaphore_waiter *waiter = list_first_entry(&sem->wait_list, struct semaphore_waiter, list); list_del(&waiter->list); waiter->up = 1; wake_up_process(waiter->task); }
struct rw_semaphore { signed long count; spinlock_t wait_lock; struct list_head wait_list; #ifdef CONFIG_DEBUG_LOCK_ALLOC struct lockdep_map dep_map; #endif };
DECLARE_RWSEM(name) //声明名为name的读写信号量,并初始化它。 void init_rwsem(struct rw_semaphore *sem); //对读写信号量sem进行初始化。 void down_read(struct rw_semaphore *sem); //读者用来获取sem,若没获得时,则调用者睡眠等待。 void up_read(struct rw_semaphore *sem); //读者释放sem。 int down_read_trylock(struct rw_semaphore *sem); //读者尝试获取sem,如果获得返回1,如果没有获得返回0。可在中断上下文使用。 void down_write(struct rw_semaphore *sem); //写者用来获取sem,若没获得时,则调用者睡眠等待。 int down_write_trylock(struct rw_semaphore *sem); //写者尝试获取sem,如果获得返回1,如果没有获得返回0。可在中断上下文使用 void up_write(struct rw_semaphore *sem); //写者释放sem。 void downgrade_write(struct rw_semaphore *sem); //把写者降级为读者。
struct mutex { /* 1: unlocked, 0: locked, negative: locked, possible waiters */ atomic_t count; spinlock_t wait_lock; struct list_head wait_list; ...... };
DEFINE_MUTEX(name);实现如下:
#define DEFINE_MUTEX(mutexname) struct mutex mutexname = __MUTEX_INITIALIZER(mutexname) #define __MUTEX_INITIALIZER(lockname) { .count = ATOMIC_INIT(1) , .wait_lock = __SPIN_LOCK_UNLOCKED(lockname.wait_lock) , .wait_list = LIST_HEAD_INIT(lockname.wait_list) __DEBUG_MUTEX_INITIALIZER(lockname) __DEP_MAP_MUTEX_INITIALIZER(lockname) }
mutex_init(&mutex);
# define mutex_init(mutex) do { static struct lock_class_key __key; __mutex_init((mutex), #mutex, &__key); } while (0) void __mutex_init(struct mutex *lock, const char *name, struct lock_class_key *key) { atomic_set(&lock->count, 1); spin_lock_init(&lock->wait_lock); INIT_LIST_HEAD(&lock->wait_list); mutex_clear_owner(lock); debug_mutex_init(lock, name, key); }
mutex_lock(&mutex); /* 临界区 */ mutex_unlock(&mutex);
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); } 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); }
int mutex_trylock(struct mutex *); //视图获取指定互斥体,成功返回1;否则返回0。 int mutex_is_locked(struct mutex *lock); //判断锁是否被占用,是返回1,否则返回0。
preempt_enable() //内核抢占计数preempt_count减1 preempt_disable() //内核抢占计数preempt_count加1,当该值降为0时检查和执行被挂起的需要调度的任务 preempt_enable_no_resched()//内核抢占计数preempt_count减1,但不立即抢占式调度 preempt_check_resched () //如果必要进行调度 preempt_count() //返回抢占计数 preempt_schedule() //内核抢占时的调度程序的入口点
#define preempt_enable() do { preempt_enable_no_resched(); barrier(); \ // 加内存屏障,阻止gcc编译器对内存进行优化 preempt_check_resched(); } while (0) #define preempt_enable_no_resched() do { barrier(); dec_preempt_count(); } while (0) #define dec_preempt_count() sub_preempt_count(1) # define sub_preempt_count(val) do { preempt_count() -= (val); } while (0) //此处减少抢占计数 #define preempt_check_resched() do { if (unlikely(test_thread_flag(TIF_NEED_RESCHED))) preempt_schedule(); } while (0) asmlinkage void __sched preempt_schedule(void) { struct thread_info *ti = current_thread_info(); /* * If there is a non-zero preempt_count or interrupts are disabled, * we do not want to preempt the current task. Just return.. */ if (likely(ti->preempt_count || irqs_disabled())) return; do { add_preempt_count(PREEMPT_ACTIVE); schedule(); sub_preempt_count(PREEMPT_ACTIVE); /* * Check again in case we missed a preemption opportunity * between schedule and now. */ barrier(); } while (need_resched());
版权声明:本文为博主原创文章,未经博主允许不得转载。
原文地址:http://blog.csdn.net/shallnet/article/details/47176683