semaphore

来源:互联网 发布:mdb数据库 编辑:程序博客网 时间:2024/06/05 05:11

1 数据结构

struct semaphore {raw_spinlock_tlock;unsigned intcount;struct list_headwait_list;};
typedef struct raw_spinlock {arch_spinlock_t raw_lock;#ifdef CONFIG_GENERIC_LOCKBREAKunsigned int break_lock;#endif#ifdef CONFIG_DEBUG_SPINLOCKunsigned int magic, owner_cpu;void *owner;#endif#ifdef CONFIG_DEBUG_LOCK_ALLOCstruct lockdep_map dep_map;#endif} raw_spinlock_t;

2 初始化

2.1 动态

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);//初始化一个lock的实例lock-class映射信息}
#define __SEMAPHORE_INITIALIZER(name, n)\{\.lock= __RAW_SPIN_LOCK_UNLOCKED((name).lock),\.count= n,\.wait_list= LIST_HEAD_INIT((name).wait_list),\}
如果n为0,表示该信号量不可用;如果n>0,表示信号量可用。
#define __RAW_SPIN_LOCK_UNLOCKED(lockname)\(raw_spinlock_t) __RAW_SPIN_LOCK_INITIALIZER(lockname)
#define __RAW_SPIN_LOCK_INITIALIZER(lockname)\{\.raw_lock = __ARCH_SPIN_LOCK_UNLOCKED,\SPIN_DEBUG_INIT(lockname)\SPIN_DEP_MAP_INIT(lockname) }
也是将next和owner字段初始化为0。
CONFIG_LOCKDEP是一个打开lock debug的宏。
arch/arm/Kconfig
config LOCKDEP_SUPPORT
bool
default y
lib/Kconfig.debug
config LOCKDEP
bool
depends on DEBUG_KERNEL && TRACE_IRQFLAGS_SUPPORT && STACKTRACE_SUPPORT && LOCKDEP_SUPPORT
select STACKTRACE
select FRAME_POINTER if !MIPS && !PPC && !ARM_UNWIND && !S390 && !MICROBLAZE
select KALLSYMS
select KALLSYMS_ALL

2.2 静态

#define DEFINE_SEMAPHORE(name)\struct semaphore name = __SEMAPHORE_INITIALIZER(name, 1)

3 请求信号量

3.1 down()

不可被中断的请求。
void down(struct semaphore *sem){unsigned long flags;raw_spin_lock_irqsave(&sem->lock, flags);if (likely(sem->count > 0))sem->count--;else__down(sem);raw_spin_unlock_irqrestore(&sem->lock, flags);}
信号量依赖于自旋锁。count>0说明信号量可用;否则,TASK_UNINTERRUPTIBLE的schedule()。
__down(sem)->__down_common(sem, TASK_UNINTERRUPTIBLE, MAX_SCHEDULE_TIMEOUT)->
static inline int __sched __down_common(struct semaphore *sem, long state,long timeout){struct task_struct *task = current;struct semaphore_waiter waiter;list_add_tail(&waiter.list, &sem->wait_list);//加入sem的等待wait_list,sem up的时候,会遍历wait_listwaiter.task = task;waiter.up = false;for (;;) {//如果是可被中断的可能会goto interrupted,否则会schedule,直到waiter.up为true。if (signal_pending_state(state, task))goto interrupted;if (unlikely(timeout <= 0))goto timed_out;__set_task_state(task, state);raw_spin_unlock_irq(&sem->lock);timeout = schedule_timeout(timeout);raw_spin_lock_irq(&sem->lock);if (waiter.up)return 0;} timed_out:list_del(&waiter.list);return -ETIME;//可被中断的请求信号量,被信号中断后返回-EINTR interrupted:list_del(&waiter.list);return -EINTR;}
static inline int signal_pending_state(long state, struct task_struct *p){//不可被中断或者未设置TASK_WAKEKILL(可被致命信号kill)if (!(state & (TASK_INTERRUPTIBLE | TASK_WAKEKILL)))return 0;//没有待处理的信号。TIF_SIGPENDING置位,表示该进程有信号需要处理if (!signal_pending(p))return 0;/*设置了TASK_INTERRUPTIBLE,或者设置TASK_WAKEKILL,并且有待处理的信号就走到了这里。TASK_INTERRUPTIBLE表示可以被信号中断,设置了它,这里会返回非0值;只设置了TASK_WAKEKILL,如果检测到SIGKILL信号也会返回非0值。*/return (state & TASK_INTERRUPTIBLE) || __fatal_signal_pending(p);}

3.2 down_interruptible()

可被中断的请求。
int down_interruptible(struct semaphore *sem){unsigned long flags;int result = 0;raw_spin_lock_irqsave(&sem->lock, flags);if (likely(sem->count > 0))sem->count--;elseresult = __down_interruptible(sem);raw_spin_unlock_irqrestore(&sem->lock, flags);return result;}
__down_interruptible()-> __down_common(sem, TASK_INTERRUPTIBLE, MAX_SCHEDULE_TIMEOUT)
请求成功返回0,如果没有信号将其中断,会schedule(),一直睡眠下去;如果睡眠被信号中断,会返回-EINTR。

3.3 down_killable()

可被kill的请求。
int down_killable(struct semaphore *sem){unsigned long flags;int result = 0;raw_spin_lock_irqsave(&sem->lock, flags);if (likely(sem->count > 0))sem->count--;elseresult = __down_killable(sem);raw_spin_unlock_irqrestore(&sem->lock, flags);return result;}
static noinline int __sched __down_killable(struct semaphore *sem){return __down_common(sem, TASK_KILLABLE, MAX_SCHEDULE_TIMEOUT);}
task标志为
#define TASK_KILLABLE (TASK_WAKEKILL | TASK_UNINTERRUPTIBLE)
不可被中断的请求,并且可被致命信号kill。请求成功返回0;睡眠被致命信号中断,返回-EINTR。

3.4 down_trylock()

尝试原子的请求信号量。
int down_trylock(struct semaphore *sem){unsigned long flags;int count;raw_spin_lock_irqsave(&sem->lock, flags);count = sem->count - 1;if (likely(count >= 0))sem->count = count;raw_spin_unlock_irqrestore(&sem->lock, flags);return (count < 0);}
如果请求成功返回0,不能请求到返回1。请求过程不会睡眠。
注意:spin_trylock and mutex_trylock的返回值是反转的。
mutex_trylock可以用于中断上下文,semaphore可用于任何进程和中断中。

3.5 down_timeout()

超时请求。
int down_timeout(struct semaphore *sem, long jiffies){unsigned long flags;int result = 0;raw_spin_lock_irqsave(&sem->lock, flags);if (likely(sem->count > 0))sem->count--;elseresult = __down_timeout(sem, jiffies);raw_spin_unlock_irqrestore(&sem->lock, flags);return result;}
int down_timeout(struct semaphore *sem, long jiffies){unsigned long flags;int result = 0;raw_spin_lock_irqsave(&sem->lock, flags);if (likely(sem->count > 0))sem->count--;elseresult = __down_timeout(sem, jiffies);raw_spin_unlock_irqrestore(&sem->lock, flags);return result;}
static noinline int __sched __down_timeout(struct semaphore *sem, long jiffies){return __down_common(sem, TASK_UNINTERRUPTIBLE, jiffies);}
之前的几种请求,如果不填这个超时时间,都是用MAX_SCHEDULE_TIMEOUT。该时间指定了请求信号量的超时时间。请求成功返回0,如超时未获取信号量,返回-ETIME。

4 释放信号量

void up(struct semaphore *sem){unsigned long flags;raw_spin_lock_irqsave(&sem->lock, flags);if (likely(list_empty(&sem->wait_list)))sem->count++;else__up(sem);raw_spin_unlock_irqrestore(&sem->lock, flags);}
如果wait_list为NULL,count++释放信号量;否则,不必释放信号量,直接移交给其他的task;需要处理wait_list。
static noinline void __sched __up(struct semaphore *sem){struct semaphore_waiter *waiter = list_first_entry(&sem->wait_list,struct semaphore_waiter, list); //找到第一个waiterlist_del(&waiter->list);waiter->up = true;wake_up_process(waiter->task);}
0 0
原创粉丝点击
热门问题 老师的惩罚 人脸识别 我在镇武司摸鱼那些年 重生之率土为王 我在大康的咸鱼生活 盘龙之生命进化 天生仙种 凡人之先天五行 春回大明朝 姑娘不必设防,我是瞎子 练阴瑜伽腿麻怎么办 瑜伽垫在地板滑怎么办 艾灸后后背发凉怎么办 床上老是有小蜈蚣怎么办 早晚出去胳膊脚觉得凉怎么办 腿凉感觉冒凉气怎么办 冬天腿被冻夏天发酸发凉怎么办 宿舍一楼虫子多怎么办 有虫子在咬床板怎么办 床板上的虫咬了怎么办 住的房间有臭虫怎么办 租的房子有臭虫怎么办 瑜伽垫放地上脏怎么办 瑜伽垫和地面滑怎么办 练瑜伽时瑜伽垫全是汗水怎么办 车钥匙放洗衣机洗了怎么办 瑜伽垫边上掉渣怎么办 晚上睡地上后背不舒服怎么办 小孩子天天晚上看电视不睡觉怎么办 宝宝天天晚上不睡觉怎么办 老公天天晚上不睡觉怎么办 小孩天天晚上不睡觉怎么办 摸了貔貅的眼睛怎么办 买的爬行垫滑怎么办 买了爬行垫有毒怎么办 xpe爬行垫破了怎么办 做瑜伽时平衡不好怎么办 鼻翼两侧发红长痘怎么办 孕后期睡觉背疼怎么办 练了瑜伽后腰痛怎么办 尿路口长疮疼痛怎么办 来月经吃了辣的怎么办 泳衣打湿后特别难脱怎么办 脚臭怎么办教你除臭方法 袜子没干就穿了进湿气怎么办 狗喜欢往床上跑怎么办 泰迪在床上睡觉怎么办 泰迪睡觉换地方怎么办 猫一定要和人睡怎么办 狗喜欢跳到床上怎么办 幼猫晚上不睡觉怎么办