转自:
Linux设备驱动之semaphore机制
在Linux系统中,信号号是一种重要的加锁机制,特别在互斥型资源中,semaphore更能很好的工作。1: semaphore结构体定义在Linux2.6.35内核中,semaphore的实现机制与以前的版本一点不同,在其中去除了DECLARE_MUTEX_LOCKED这个初始化互斥宏定义,但是,又添加了一个特别重要的函数,down_killable,这个函数的添加,使此版本的semaphore机制比以往的更强。semaphore结构全定义如下所示。- C/C++ code
- struct semaphore { spinlock_t lock; /* 自旋锁结构体变量 */ unsigned int count; /* 用于计录资料数量 */ struct list_head wait_list; /* 内部链表结构体变量 */ };
- C/C++ code
- #define DECLARE_MUTEX(name) \ struct semaphore name = __SEMAPHORE_INITIALIZER(name, 1)
- C/C++ code
- DECLARE_MUTEX(my_semaphore);
- C/C++ code
- #define __SEMAPHORE_INITIALIZER(name, n) \ { \ .lock = __SPIN_LOCK_UNLOCKED((name).lock), \ .count = n, \ .wait_list = LIST_HEAD_INIT((name).wait_list), \ }
- C/C++ code
- #define init_MUTEX(sem) sema_init(sem, 1)
- C/C++ code
- 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); }
- C/C++ code
- #define init_MUTEX_LOCKED(sem) sema_init(sem, 0)
- C/C++ code
- static inline int __sched __down_common(struct semaphore *sem, long state, long timeout)
- C/C++ code
- timeout = schedule_timeout(timeout);
- C/C++ code
- 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); }
- C/C++ code
- static noinline void __sched __down(struct semaphore *sem) { __down_common(sem,TASK_UNINTERRUPTIBLE,\ MAX_SCHEDULE_TIMEOUT); }
- C/C++ code
- #define MAX_SCHEDULE_TIMEOUT LONG_MAX
- C/C++ code
- #define LONG_MAX ((long)(~0UL>>1))
- C/C++ code
- 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); }
- C/C++ code
- int down_timeout(struct semaphore *sem, long jiffies) { unsigned long flags; int result = 0; spin_lock_irqsave(&sem->lock, flags); if (likely(sem->count > 0)) sem->count--; else result = __down_timeout(sem, jiffies); spin_unlock_irqrestore(&sem->lock, flags); return result; }
- C/C++ code
- 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); }