0
  • 聊天消息
  • 系统消息
  • 评论与回复
登录后你可以
  • 下载海量资料
  • 学习在线课程
  • 观看技术视频
  • 写文章/发帖/加入社区
创作中心

完善资料让更多小伙伴认识你,还能领取20积分哦,立即完善>

3天内不再提示

linux内核中对信号量的DOWN操作方式

书生途 来源:书生途 作者:书生途 2022-05-11 15:41 次阅读

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 <=0)
                     gototimed_out;
              __set_task_state(task,state);
              spin_unlock_irq(&sem->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) 有着很重要的作用。

审核编辑:汤梓红
声明:本文内容及配图由入驻作者撰写或者入驻合作网站授权转载。文章观点仅代表作者本人,不代表电子发烧友网立场。文章及其配图仅供工程师学习之用,如有内容侵权或者其他违规问题,请联系本站处理。 举报投诉
  • Linux
    +关注

    关注

    87

    文章

    10990

    浏览量

    206738
  • down
    +关注

    关注

    0

    文章

    5

    浏览量

    9786
  • 信号量
    +关注

    关注

    0

    文章

    53

    浏览量

    8257
收藏 人收藏

    评论

    相关推荐

    Linux下进程通讯之信号量

    信号量集,就是由多个信号量组成的一个数组。 作为一个整体, 信号量集中所有的信号量使用同一个等待队列。 Linux
    的头像 发表于 08-19 19:55 1610次阅读
    <b class='flag-5'>Linux</b>下进程通讯之<b class='flag-5'>信号量</b>集

    Linux驱动开发笔记-自旋锁和信号量

    :如果在写代码时,有以上的竞态发生,一定要注意进行互斥访问7.解决竞态的方法:中断屏蔽原子操作自旋锁信号量如何使用以上4个机制呢?1.中断屏蔽解决哪些情况的竞态:进程和进程的抢占中断和进程中断和中断
    发表于 08-30 18:08

    【安富莱】【RTX操作系统教程】第14章 信号量

    os_sem_wait由于没有资源可用再次进入到挂起态,等待串口释放信号量资源,如此往复循环。上面就是一个简单RTX中断方式信号量同步过程。实际应用,中断
    发表于 01-29 14:58

    第14章 信号量

    转rtx操作系统 本章节开始讲解RTX的另一个重要的任务间的同步和资源共享机制,信号量。 本章教程配套的例子含Cortex-M3内核的STM32F103和Cortex-M4内核的STM
    发表于 10-05 09:26

    第15章 互斥信号量

    转rtx操作系统 本章节开始讲解RTX的另一个重要的资源共享机制---互斥信号量(Mutex,即Mutual Exclusion的缩写)。注意,建议初学者学习完上个章节的信号量后再学习本章节的互斥
    发表于 10-06 16:40

    ucos信号量、互斥信号量、事件标志组的理解

    可以访问他~!但是同一时间,肯定要保证只有1个任务再操作打印机。那样才能得到大家想要的结果。也就是要独占共享资源的访问权~!ucos2通过互斥信号量来解决这个问题。简单说就是任务1开始访问打印机
    发表于 08-23 10:35

    芯灵思SinlinxA33开发板的Linux内核信号量学习

    被唤醒,转入步骤(1)。    (4) 当进程不再使用一个信号量控制的资源时,信号量值加1。如果此时有进程正在睡眠等待此信号量,则唤醒此进程。     维护信号量状态的是
    发表于 02-20 15:50

    芯灵思SinlinxA64开发板 Linux内核信号量学习

    等待此信号量,则唤醒此进程。     维护信号量状态的是Linux内核操作系统而不是用户进程。我们可以从头文件/usr/src/
    发表于 03-15 16:10

    小熊派华为物联网操作系统 LiteOS内核教程04-信号量

    本帖最后由 小熊派开源社区 于 2020-2-24 17:45 编辑 1. LiteOS内核信号量1.1.信号量在多任务操作系统
    发表于 01-18 11:04

    linux下多线程编程,一次等待多个信号量怎么解决

    linux下多线程(非进程)编程,一次等待多个信号量怎么解决?并且等到信号量来了后,能判断是那一个​功能如同window下waitformultipleobjects()函数,一次就
    发表于 06-17 05:55

    LINUX内核学习指南:构建系统、信号量设计、GPIO操作函数

    控制路径可以睡眠。我们从 LINUX内核信号量最直观的设计/实现出发,通过一步步改进,揭示完整的信号量设计/实现,然后探讨在不同平台上通用的信号量
    发表于 07-08 14:45

    Linux操作系统信号量机制的实时化改造

    为了提高Linux操作系统的实时性,研究了Linux操作系统System V信号量机制在内核中的
    发表于 06-25 16:41 18次下载

    你了解Linux 各类信号量

    内核信号量与用户信号量,用户信号量分为POXIS信号量和SYSTEMV信号量,POXIS
    发表于 05-04 17:19 2309次阅读
    你了解<b class='flag-5'>Linux</b> 各类<b class='flag-5'>信号量</b>?

    LINUX内核信号量设计与实现

    控制路径可以睡眠。我们从 LINUX内核信号量最直观的设计/实现出发,通过一步步改进,揭示在x86平台上完整的信号量设计/实现,然后探讨在不同平台上通用的
    发表于 01-14 16:55 18次下载

    LINUX内核信号量设计与实现

    控制路径可以睡眠。我们从 LINUX内核信号量最直观的设计/实现出发,通过一步步改进,揭示在x86平台上完整的信号量设计/实现,然后探讨在不同平台上通用的
    发表于 01-14 16:55 5次下载