Linux信号量

这篇文章来自我的个人博客里 www.mystone7.com 现在已经关掉了

Linux 中的信号量是一种资源锁,如果有一个任务试图获得一个已经被占用的信号量时,信号量会将其推到一个等待队列中,这时处理器会重获自由从而去执行其它代码,当持有信号量的进程将信号量释放后,处于等待队列中的那个任务将会被唤醒,并将获得该信号量。

信号量分为互斥信号量,以及计数信号量,区别在于 count的值,若为1,则为互斥信号量,若大于1 则为计数信号量。

信号量结构体

struct semaphore {

       spinlock_t              lock;    //防止其它进程同时访问该信号量,并禁止中断

       unsigned int            count; //计值信号量

       struct list_head        wait_list; //加入等待队列的指针

};

 

信号量初始化

#define __SEMAPHORE_INITIALIZER(name,n)                                \

{                                                                       \

       .lock           =__SPIN_LOCK_UNLOCKED((name).lock),           \

       .count          = n,                                            \

       .wait_list      =LIST_HEAD_INIT((name).wait_list),            \

}

 

定义一个信号量并初始化

#define DEFINE_SEMAPHORE(name)  \

       struct semaphore name = __SEMAPHORE_INITIALIZER(name, 1)

 

初始化一个计值信号量

static inline void sema_init(structsemaphore *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); 

}

 

获取一个信号量

extern void down(structsemaphore *sem);   //内核说已经过时了

extern int __must_check down_interruptible(struct semaphore *sem); //acquirethe semaphore unless interrupted, If the sleep is interrupted by a signal, thisfunction will return -EINTR.

extern int __must_check down_killable(struct semaphore *sem); //acquirethe semaphore unless killed, If the sleep is interrupted by a fatal signal,this function will return -EINTR

extern int __must_check down_trylock(struct semaphore *sem); //try toacquire the semaphore, without waiting 

extern int __must_check down_timeout(struct semaphore *sem, long jiffies);//acquire the semaphore within a specified time, If the semaphore is notreleased within the specified number of jiffies, this function returns -ETIME.

extern void up(structsemaphore *sem);

 

以down_interruptible为例

/**

 *down_interruptible - acquire the semaphore unless interrupted

 *@sem: the semaphore to be acquired

 *

 *Attempts to acquire the semaphore.  If nomore tasks are allowed to

 *acquire the semaphore, calling this function will put the task to sleep.

 * If the sleep is interrupted by a signal, thisfunction will return -EINTR.

 * Ifthe semaphore is successfully acquired, this function returns 0.

 */

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--;      //计数值减1

       else

                result = __down_interruptible(sem);  //在切换前会开中断,

       spin_unlock_irqrestore(&sem->lock, flags); //切换后开中断

 

       return result;

}

EXPORT_SYMBOL(down_interruptible);

 

static noinline int __sched __down_interruptible(struct semaphore *sem)

{

       return __down_common(sem, TASK_INTERRUPTIBLE,MAX_SCHEDULE_TIMEOUT);

}

TASK_INTERRUPTIBLE 可被信号中断唤醒

#define MAX_SCHEDULE_TIMEOUT    LONG_MAX 类似于无限睡下去

/*

 *Because this function is inlined, the 'state' parameter will be

 *constant, and thus optimised away by the compiler.  Likewise the

 *'timeout' parameter for the cases without timeouts.

 */

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); //将该任务加入到信号量的等待队列中去

       waiter.task = task;

       waiter.up = 0;

 

       for (;;) {

                if (signal_pending_state(state,task)) //如果该进程被信号中断,则退出,task是在哪被设置了这个任号的呢?遗留问题

                        goto interrupted;

                if (timeout <= 0)  //定时到了

                       goto timed_out;

                __set_task_state(task, state);  //将task的TASK_RUNNING状态变成TASK_INTERRUPTIBEU状态,当该进程被切换出去时,如果没有被置为TASK_RUNNING状态,调度器则不会在调度它了

               spin_unlock_irq(&sem->lock); //吻合前面的spin_lock_irqsave,开中断

                timeout =schedule_timeout(timeout); //将进程切换出去

               spin_lock_irq(&sem->lock);//关中断,吻合后面的spin_unlock_irqsave

                if (waiter.up)

                        return 0;

       }

 

 timed_out:

       list_del(&waiter.list);

       return -ETIME;

 

 interrupted:

       list_del(&waiter.list);

       return -EINTR;

}

struct semaphore_waiter {

       struct list_head list;

       struct task_struct *task; //等待信号量的任务

       int up;

};

 

timeout= schedule_timeout(timeout); //将进程切换出去

当定时timeout时间到过后,返回值timeout变为0, 则__down_common返回-ETIME.

现在假设有4个进程A B C D, A已经获得一个信号量global,而B C D正在按顺序等待该信号量

 

Lock

Count

wait_list

list

up=0

* task=B

list

up=0

* task=d

                                                             

list

up=0

* task=C

                                

唤醒函数,释放信号量

/**

 * up- release the semaphore

 *@sem: the semaphore to release

 *

 *Release the semaphore.  Unlike mutexes,up() may be called from any

 *context and even by tasks which have never called down().

 */

void up(struct semaphore *sem)

{      

       unsigned long flags;

       

       spin_lock_irqsave(&sem->lock, flags);

       if (likely(list_empty(&sem->wait_list)))   //

                sem->count++; //如果队列为空的话,则将计数值加1

       else    

                __up(sem);   //唤醒

       spin_unlock_irqrestore(&sem->lock, flags);

}

EXPORT_SYMBOL(up);

 

static noinline void __sched __up(structsemaphore *sem)

{

       struct semaphore_waiter *waiter =list_first_entry(&sem->wait_list, struct semaphore_waiter, list);

       list_del(&waiter->list); //根据队列,先进先出的原则,第一个down的进程会被先唤醒,将该进程从信号量的等待队列中删除

       waiter->up = 1;   //与down里的if(waiter.up)对应

       wake_up_process(waiter->task); //唤醒进程,将其加入到可运行的进程链表中进程state的状态由TASK_WAKING逐渐变成TASK_RUNNING中去

}

/**    

 *wake_up_process - Wake up a specific process

 *@p: The process to be woken up.

 *

 *Attempt to wake up the nominated process and move it to the set of runnable

 *processes.  Returns 1 if the process waswoken up, 0 if it was already

 *running.

 *

 * Itmay be assumed that this function implies a write memory barrier before

 *changing the task state if and only if any tasks are woken up. 

 */

int wake_up_process(struct task_struct *p)

{

       return try_to_wake_up(p, TASK_ALL, 0);

}

EXPORT_SYMBOL(wake_up_process);

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值