down操作:linux内核中,对信号量的down操作有如下几种:
void down(struct semaphore *sem); //不可中断int down_interruptible(struct semaphore *sem);//可中断int down_killable(struct semaphore *sem);//睡眠的进程可以因为受到致命信号而被唤醒,中断获取信号量的操作。int down_trylock(struct semaphore *sem);//试图获取信号量,若无法获得则直接返回1而不睡眠。返回0则 表示获取到了信号量int down_timeout(struct semaphore *sem,long jiffies);//表示睡眠时间是有限制的,如果在jiffies指明的时间到期时仍然无法获得信号量,则将返回错误码。 在以上四种函数中,驱动程序使用的最频繁的就是down_interruptible函数,以下将对该函数进行分析。
down_interruptible函数的定义如下:
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;} 函数分析:函数首先通过spin_lock_irqsave的调用来保证对sem->count操作的原子性。如果count>0,表示当前进程可以获得信号量,将count的值减1然后退出。如果count不大于0,表明当前进程无法获取信号量,则调用__down_interruptible,后者会继续调用__down_common。
__down_common 函数定义如下:
static inline int __sched __down_common(struct semaphore *sem, longstate, longtimeout){ struct task_struct *task= current; struct semaphore_waiterwaiter; list_add_tail(&waiter.list,&sem->wait_list); waiter.task = task; waiter.up = 0; for (;;) { if(signal_pending_state(state, task)) gotointerrupted; if (timeout lock); timeout =schedule_timeout(timeout); spin_lock_irq(&sem->lock); if (waiter.up) return 0; } timed_out: list_del(&waiter.list); return -etime; interrupted: list_del(&waiter.list); return -eintr;} 函数分析:在__down_common函数数执行了以下操作。
(1)将当前进程放到信号量成员变量wait_list所管理的队列中。
(2)在一个for循环中把当前的进程状态这是为task_interruptible,在调用schedule_timeout使当前进程进入睡眠状态,函数将停留在schedule_timeout调用上,知道再次被调度执行。
(3) 当该进程再一次被调度时,按原因执行相应的操作:如果waiter.up不为0说明进程被该信号量的up操作所唤醒,进程可以获得信号量。如果进程是因为被用户空间的信号所中断或超时信号所引起的唤醒,则返回相应的错误代码。
up操作:linux内核只提供了一个up函数
up函数定义如下:
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);} 函数分析:如果sem的wait_list队列为空,则表明没有其他进程正在等待该信号量,那么只需要把sem的count加1即可。如果wait_list队列不为空,则说明有其他进程正睡眠在wait_list上等待该信号,此时调用__up(sem)来唤醒进程:
__up()函数定义如下:
static noinline void __sched __up(struct semaphore *sem){ struct semaphore_waiter*waiter = list_first_entry(&sem->wait_list, structsemaphore_waiter, list); list_del(&waiter->list); waiter->up = 1; wake_up_process(waiter->task);} 函数分析:在函数中,调用了wake_up_process来唤醒进程,这样进程就从之前的__down_interruptible调用中的timeout=schedule_timeout(timeout)处醒来,wait-up=1, __down_interruptible返回0,进程获得了信号量。
up()与down()函数之间的联系:由上面对两个函数的分析可以知道,__down_common函数中timeout=schedule_timeout(timeout) 有着很重要的作用。
磷酸铁锂电池装机占比超越三元电池 锂金属电池会是未来
5v2A适配器电源ic U9513B介绍
2023年全球车载显示面板出货量有望达到2亿片
呼叫中心未来发展的五大趋势解读
数字电源取代模拟电源的关键性因素是什么
linux内核中对信号量的DOWN操作方式
IT与医疗碰撞,未来的AI技术更需要走向工程化
线性稳压电源和开关稳压电源详解
Windows CE 6.0 Multi-bin的设计与实现
智能魔镜,让你如同生活在童话世界一般
英特尔逻辑芯片3D堆叠技术“Foveros” 将实现世界一流性能
ATP细菌检测仪产品介绍
超声波焊接时遇到问题?灵高超声波教你如何解决
为什么高刷电视的120Hz显示效果不同?
学习一下钙钛矿LED
AR眼镜走入全息世界,法国研究机构迈出了重要一步
还未成型发展的5G,为何被贴上“无用论”标签?
MediaTek天玑9000+旗舰5G移动平台的技术优势
搜狗发布4款新品 未来或将引领着整个录音笔行业走向AI时代
离线电源的理想选择UC3845