down函数 linux_down 函数 - CSDN
  • down_interruptible函数和down函数的问题

    千次阅读 2012-06-11 21:35:54
    为什么可能导致睡眠的函数都不能在中断上下文中使用呢? 首先睡眠的含义是将进程置于“睡眠”状态,在这个状态的进程不能被调度执行。然后,在一定的时机,这个进程可能会被重新置为“运行”状态,从而可能被调度...
    中断发生以后,CPU跳到内核设置好的中断处理代码中去,由这部分内核代码来处理中断。这个处理过程中的上下文就是中断上下文。

    为什么可能导致睡眠的函数都不能在中断上下文中使用呢? 首先睡眠的含义是将进程置于“睡眠”状态,在这个状态的进程不能被调度执行。然后,在一定的时机,这个进程可能会被重新置为“运行”状态,从而可能被调度执行。 可见,“睡眠”与“运行”是针对进程而言的,代表进程的task_struct结构记录着进程的状态。内核中的“调度器”通过task_struct对进程进行调度。
    但是,中断上下文却不是一个进程,它并不存在task_struct,所以它是不可调度的。所以,在中断上下文就不能睡眠。

    那么,中断上下文为什么不存在对应的task_struct结构呢?
    中断的产生是很频繁的(至少每毫秒(看配置,可能10毫秒或其他值)会产生一个时钟中断),并且中断处理过程会很快。如果为中断上下文维护一个对应的task_struct结构,那么这个结构频繁地分配、回收、并且影响调度器的管理,这样会对整个系统的吞吐量有所影响。

    但是在某些追求实时性的嵌入式linux中,中断也可能被赋予task_struct结构。这是为了避免大量中断不断的嵌套,导致一段时间内CPU总是运行在中断上下文,使得某些优先级非常高的进程得不到运行。这种做法能够提高系统的实时性,但是代价中吞吐量的降低
    展开全文
  • linux同步机制之信号量down 和up

    万次阅读 2014-01-06 11:03:40
     Linux内核的信号量在概念和原理上和用户态的System V的IPC机制信号量是相同的,不过他绝不可能在内核之外使用,因此他和System V的IPC机制信号量毫不相干。   信号量在创建时需要设置一个初始值,表示同时能有几...

    信号量(semaphore) 

      Linux内核的信号量在概念和原理上和用户态的System V的IPC机制信号量是相同的,不过他绝不可能在内核之外使用,因此他和System V的IPC机制信号量毫不相干。 
      信号量在创建时需要设置一个初始值,表示同时能有几个任务能访问该信号量保护的共享资源,初始值为1就变成互斥锁(Mutex),即同时只能有一个任务能访问信号量保护的共享资源。 
       一个任务要想访问共享资源,首先必须得到信号量,获取信号量的操作将把信号量的值减1,若当前信号量的值为负数,表明无法获得信号量,该任务必须挂起在 该信号量的等待队列等待该信号量可用;若当前信号量的值为非负数,表示能获得信号量,因而能即时访问被该信号量保护的共享资源。 
      当任务访问完被信号量保护的共享资源后,必须释放信号量,释放信号量通过把信号量的值加1实现,如果信号量的值为非正数,表明有任务等待当前信号量,因此他也唤醒所有等待该信号量的任务。 

      信号量的API有: 

    DECLARE_MUTEX(name) 
      该宏声明一个信号量name并初始化他的值为1,即声明一个互斥锁。 

    DECLARE_MUTEX_LOCKED(name) 
      该宏声明一个互斥锁name,但把他的初始值设置为0,即锁在创建时就处在已锁状态。因此对于这种锁,一般是先释放后获得。 

    void sema_init (struct semaphore *sem, int val); 
      该函用于数初始化设置信号量的初值,他设置信号量sem的值为val。 

    void init_MUTEX (struct semaphore *sem); 
      该函数用于初始化一个互斥锁,即他把信号量sem的值设置为1。 

    void init_MUTEX_LOCKED (struct semaphore *sem); 
      该函数也用于初始化一个互斥锁,但他把信号量sem的值设置为0,即一开始就处在已锁状态。 

    void down(struct semaphore * sem); 
      该函数用于获得信号量sem,他会导致睡眠,因此不能在中断上下文(包括IRQ上下文和softirq上下文)使用该函数。该函数将把sem的值减1,如果信号量sem的值非负,就直接返回,否则调用者将被挂起,直到别的任务释放该信号量才能继续运行。 

    int down_interruptible(struct semaphore * sem); 
      该函数功能和down类似,不同之处为,down不会被信号(signal)打断,但down_interruptible能被信号打断,因此该函数有返回值来区分是正常返回还是被信号中断,如果返回0,表示获得信号量正常返回,如果被信号打断,返回-EINTR。 

    int down_trylock(struct semaphore * sem); 
      该函数试着获得信号量sem,如果能够即时获得,他就获得该信号量并返回0,否则,表示不能获得信号量sem,返回值为非0值。因此,他不会导致调用者睡眠,能在中断上下文使用。

     

    int down_killable(struct semaphore *sem);

    int down_timeout(struct semaphore *sem, long jiffies);

    int down_timeout_interruptible(struct semaphore *sem, long jiffies);


    void up(struct semaphore * sem); 
      该函数释放信号量sem,即把sem的值加1,如果sem的值为非正数,表明有任务等待该信号量,因此唤醒这些等待者。

     

      信号量在绝大部分情况下作为互斥锁使用,下面以console驱动系统为例说明信号量的使用。 
      在内核源码树的kernel/printk.c中,使用宏DECLARE_MUTEX声明了一个互斥锁console_sem,他用于保护console驱动列表console_drivers及同步对整个console驱动系统的访问。 
       其中定义了函数acquire_console_sem来获得互斥锁console_sem,定义了release_console_sem来释放互斥 锁console_sem,定义了函数try_acquire_console_sem来尽力得到互斥锁console_sem。这三个函数实际上是分别 对函数down,up和down_trylock的简单包装。 
      需要访问console_drivers驱动列表时就需要使用acquire_console_sem来保护console_drivers列表,当访问完该列表后,就调用release_console_sem释放信号量console_sem。 
       函数 console_unblank,console_device,console_stop,console_start,register_console 和unregister_console都需要访问console_drivers,因此他们都使用函数对acquire_console_sem和 release_console_sem来对console_drivers进行保护。




    入浅出down_interruptible函数

    int down_interruptible(struct semaphore *sem)
    这个函数的功能就是获得信号量,如果得不到信号量就睡眠,此时没有信号打断,那么进入睡眠。但是在睡眠过程中可能被信号打断,打断之后返回-EINTR,主要用来进程间的互斥同步。

    下面是该函数的注释:
    /**
    * down_interruptible - acquire the semaphore unless interrupted
    * @sem: the semaphore to be acquired
    *
    * Attempts to acquire the semaphore. If no more tasks are allowed to
    * acquire the semaphore, calling this function will put the task to sleep.
    * If the sleep is interrupted by a signal, this function will return -EINTR.
    * If the semaphore is successfully acquired, this function returns 0.
    */

    一个进程在调用down_interruptible()之后,如果sem<0,那么就进入到可中断的睡眠状态并调度其它进程运行, 但是一旦该进程收到信号,那么就会从down_interruptible函数中返回。并标记错误号为:-EINTR。一个形象的比喻:传入的信号量为1好比天亮,如果当前信号量为0,进程睡眠,直到(信号量为1)天亮才醒,但是可能中途有个闹铃(信号)把你闹醒。又如:小强下午放学回家,回家了就要开始吃饭嘛,这时就会有两种情况:情况一:饭做好了,可以开始吃;情况二:当他到厨房去的时候发现妈妈还在做,妈妈就对他说:“你先去睡会,待会做好了叫你。”小强就答应去睡会,不过又说了一句:“睡的这段时间要是小红来找我玩,你可以叫醒我。”小强就是down_interruptible,想吃饭就是获取信号量,睡觉对应这里的休眠,而小红来找我玩就是中断休眠。

    使用可被中断的信号量版本的意思是,万一出现了semaphore的死锁,还有机会用ctrl+c发出软中断,让等待这个内核驱动返回的用户态进程退出。而不是把整个系统都锁住了。在休眠时,能被中断信号终止,这个进程是可以接受中断信号的!比如你在命令行中输入# sleep 10000,按下ctrl + c,就给上面的进程发送了进程终止信号。信号发送给用户空间,然后通过系统调用,会把这个信号传给递给驱动。信号只能发送给用户空间,无权直接发送给内核的,那1G的内核空间,我们是无法直接去操作的。

    展开全文
  • Linux内核信号量-up()和down()

    千次阅读 2017-02-17 15:15:04
    内核信号量类似于自旋锁,当锁关闭时,它不...因此,只有可以睡眠的函数才能获取内核信号量;中断处理程序和可延迟函数都不能使用内核信号量。内核信号量结构如下:/** * 内核信号量结构 */ struct semaphore { /**

    内核信号量类似于自旋锁,当锁关闭时,它不允许内核控制路径继续执行。与自旋锁不同的是,当内核控制路径试图获取内核信号量所保护的忙资源时,相应的进程被挂起,进而会导致进程切换;而自旋锁不会导致进程切换。因此,只有可以睡眠的函数才能获取内核信号量;中断处理程序和可延迟函数都不能使用内核信号量。

    内核信号量结构如下:

        /**
         * 内核信号量结构
         */
        struct semaphore {
            /**
             * 如果该值大于0,表示资源是空闲的。如果等于0,表示信号量是忙的,但是没有进程在等待这个资源。
             * 如果count为负,表示资源忙,并且至少有一个进程在等待。
             * 但是请注意,负值并不代表等待的进程数量。
             */
            atomic_t count;
            /**
             * 存放一个标志,表示是否有一些进程在信号量上睡眠。
             * 如果没有进程在信号量等待队列上睡眠时,sleeper通常为0,否则为1(这点很重要,见下面的down函数)
             */
            int sleepers;
            /**
             * 存放等待队列链表的地址。当前等待资源的所有睡眠进程都放在这个链表中。
             * 如果count>=0,那么这个链表就应该是空的。
             */
            wait_queue_head_t wait;
        };

    释放信号量

    当进程希望释放内核信号量锁时,就调用up()函数,如下:

        static inline void up(struct semaphore * sem)
        {
            __asm__ __volatile__(
                "# atomic up operation\n\t"
                /**
                 * 首先增加count的值
                 */
                LOCK "incl %0\n\t"     /* ++sem->count */
                /**
                 * 测试count值,如果当前小于等于0,那么有进程在等待,跳到2f,唤醒等待进程。
                 */
                "jle 2f\n"
                /**
                 * 运行到这里表示count>0,不用做任何事情,返回。
                 * 注意1后面的代码在单独的段中。此处就是函数的结束处。
                 */
                "1:\n"
                LOCK_SECTION_START("")
                /**
                 * 调用__up_wakeup,注意它是从寄存器传参的。
                 * 它最终调用的是__up,再调用wakeup。
                 * eax寄存器中传递的是第一个参数sem
                 */
                "2:\tlea %0,%%eax\n\t"
                "call __up_wakeup\n\t"
                "jmp 1b\n"
                LOCK_SECTION_END
                ".subsection 0\n"
                :"=m" (sem->count)
                :
                :"memory","ax");
        }
    
        fastcall void __up(struct semaphore *sem)
        {
            /*
             * 这里只是唤醒,并不一定能马上恢复执行,所以没有把进程从等待队列移除
             * 移除操作是在__down函数中执行的
             */
            wake_up(&sem->wait);
        }
    

    获取信号量

    当进程希望获取内核信号量锁时,调用down()函数,如下:

        static inline void down(struct semaphore * sem)
        {
            might_sleep();
            __asm__ __volatile__(
                "# atomic down operation\n\t"
                /**
                 * 首先减少并检查sem->count的值
                 * 如果为负(说明减少前就是0或负)就挂起
                 * 这里的减一操作是原子的
                 * 请注意当count<0时,此时-1是不正确的,因为调用进程会被挂起,而没有真正的获得信号量。
                 * 它恢复count值的时机,不在down中,在__down中。
                 */
                LOCK "decl %0\n\t"     /* --sem->count */
                "js 2f\n"
                "1:\n"
                /**
                 * 为负了,调用__down_failed
                 * __down_failed会保存参数并调用__down
                 */
                LOCK_SECTION_START("")
                "2:\tlea %0,%%eax\n\t"
                "call __down_failed\n\t"
                "jmp 1b\n"
                LOCK_SECTION_END
                :"=m" (sem->count)
                :
                :"memory","ax");
        }

    __down()如下:

        /**
         * 当申请信号量失败时,调用__down使线程挂起。直到信号量可用。
         * 本质上,它将线程设置为TASK_UNINTERRUPTIBLE并将进程放到信号量的等待队列。
         */
        fastcall void __sched __down(struct semaphore * sem)
        {
            struct task_struct *tsk = current;
            /*
             * 将当前进程设置为等待队列的结构类型,包括设置唤醒函数
             */
            DECLARE_WAITQUEUE(wait, tsk);
            unsigned long flags;
    
            /**
             * 设置状态为TASK_UNINTERRUPTIBLE。
             */
            tsk->state = TASK_UNINTERRUPTIBLE;
            /**
             * 在将进程放到等待队列前,先获得锁,并禁止本地中断。
             */
            spin_lock_irqsave(&sem->wait.lock, flags);
            /**
             * 等待队列的__locked版本假设在调用函数前已经获得了自旋锁。
             * 请注意加到等待队列上的睡眠进程是互斥的。这样wakeup最多唤醒一个进程。
             * 将进程链入等待队列中
             */
            add_wait_queue_exclusive_locked(&sem->wait, &wait);
    
            sem->sleepers++;
            for (;;) {
                int sleepers = sem->sleepers;
    
                /*
                 * atomic_add_negative把第一个参数加到第二个参数中,并测试第二个参数是否为负,如果为负,返回1,否则返回0
                 * 若count为负,则sleeper将被设为0
                 * 若sleeper为1,则count不变
                 * count不会小于-1,如果进入down前count为-1,则sleeper应该为1,则down将count置为-2,由于上面sleeper++变为2,函数调用后count还是变为-1
                 */
                if (!atomic_add_negative(sleepers - 1, &sem->count)) {
                    sem->sleepers = 0;
                    break;
                }
                sem->sleepers = 1;  
                spin_unlock_irqrestore(&sem->wait.lock, flags);
                /* 
                 * 这里进程会被挂起或者恢复执行
                 * 如果恢复执行则再次进入循环,可以验证上述atomic_add_negative函数仍能正确执行,
                 * 到这里会觉得上面的设计(atomic_add_negative)非常神奇,个人认为可能是经受各种考验之后设计的吧
                 */
                schedule();
    
                spin_lock_irqsave(&sem->wait.lock, flags);
                tsk->state = TASK_UNINTERRUPTIBLE;
            }
    
            /**
             * 将进程从等待队列中移除,注意释放信号量是只是唤醒,唤醒之后可能会再次进入睡眠,所以真正移除是在这里
             */
            remove_wait_queue_locked(&sem->wait, &wait);
            /**
             * 既然上面的进程已经唤醒并恢复执行了,为什么这里还要唤醒一次能,因为有可能前面已经唤醒了很多个进程
             * 但是那些进程还没调度执行(有可能要很久之后才执行,所以这段时间就不要浪费,给另外进程咯),所以这里会试图再唤醒一个进程
             */
            wake_up_locked(&sem->wait);
            spin_unlock_irqrestore(&sem->wait.lock, flags);
            tsk->state = TASK_RUNNING;
        }
    展开全文
  • 信号量,和内核中函数up,down

    千次阅读 2012-01-03 23:11:47
    信号量的原理就是一个整数的增减,up=加1,down = 减1;当这个值>=1时它就是属于资源释放状态,此时使用down能获得,如果down获得。...up的函数就是加1,down函数就是减1. 例子: DECLARE_MUTEX(regs_mutex);


    信号量的原理就是一个整数的增减,up=加1,down = 减1;当这个值>=1时它就是属于资源释放状态,此时使用down能获得,如果<=0则无法down获得。

    其实信号量不是互斥的,linux内核说定义互斥信号量,只是说你把它初始化为1或者0,然后通过配对使用up down来保证。

    up的函数就是加1,down的函数就是减1.

    例子:

    DECLARE_MUTEX(regs_mutex); //声明并初始化互斥信号量为0。

    xxxxx

    xxxx

    static void ov9650_init_regs(void)
    {
    int i;

    down(&regs_mutex);
    for (i=0; i<ARRAY_SIZE(regs); i++)
    {
       if (regs[i].subaddr == 0xff)
       {
        mdelay(regs[i].value);
        continue;
       }
       sccb_write(OV9650_SCCB_ADDR, regs[i].subaddr, regs[i].value);
    }
    up(&regs_mutex);
    }


    展开全文
  • 信号量机制中的down和up函数

    千次阅读 2018-10-08 16:48:48
    转自:https://blog.csdn.net/fzubbsc/article/details/37737159 参考: https://blog.csdn.net/liuxd3000/article/details/17913363 http://blog.chinaunix.net/uid-25845340-id-3017214.html  ...
  • Linux 内核信号量(semaphore)中的 __down() 函数浅析
  • Linux内核开发常见的函数

    千次阅读 2019-06-18 14:06:05
    Linux驱动开发经常要使用到内核相关的函数,本篇只要介绍在做驱动开发的过程...down_interruptible与down函数 writeX与readX宏函数 1. copy_from_user与copy_to_user函数 copy_from_user:从用户空间拷贝数据...
  • Linux error函数 ——Linux编程

    千次阅读 2018-07-23 23:18:26
    error系列函数Linux系统编程中,一种debug的方式,定义在头文件 &lt;errno.h&gt;中。 源代码 使用说明 三个函数如下: 1. void error (int status, int errnum, const char *format,...); 这个函数...
  • Linux时间函数

    万次阅读 多人点赞 2016-03-14 20:51:46
    本文旨在为了解Linux各种时间类型与时间函数提供技术文档。 1、Linux下常用时间类型 Linux下常用时间类型有四种:time_t、struct tm、struct timeval、struct timespec 1.1 time_t时间类型 time_t类型在time.h...
  • linux使用定时器回调函数示例

    千次阅读 2017-03-30 15:55:41
    liunx使用setitimer()函数设置定时器,一定间隔后触发回调函数。#include #include #include #include #include <signal.h>void timer_handler (int signum) { printf("trigger..."); }in
  • linux down up认识

    2013-11-21 11:05:34
    f() { down(sem);此函数第一次调用之后申请资源,继续往下进行。   while(a);这个‘a’可能在中断中会被置0,则退出while往下。... 这时如果再调用这个函数,那么down(sem)就会失败,  
  • Linux时间函数及格式转换

    千次阅读 2018-10-31 10:36:02
    本文转自Linux时间函数,感谢分享。简介 本文旨在为了解Linux各种时间类型与时间函数提供技术文档。 1、Linux下常用时间类型 Linux下常用时间类型有四种:time_t、struct tm、struct timeval、struct timespec ...
  • 信号量(semaphore)是用于...Linux系统中与信号量相关的操作主要有如下4种。 1 定义信号量 下面代码定义名为sem的信号量。 struct semaphore sem; struct semaohore结构体在内核中定义如下: 在/include/linux/semap
  • Linux的write函数奥秘

    万次阅读 2012-12-13 21:24:05
     在Linux下我们在使用设备的时候,都会用到write这个函数,通过这个函数我们可以象使 用文件那样向设备传送数据。可是为什么用户使用write函数就可以把数据写到设备里面 去,这个过程到底是怎么实现的呢?  这...
  • 部分同学 对信号量和信号两概念模糊不清,所以 首先描述一下 信号量和信号的区别:信号量是进程间防止并发和竞争条件的一种同步机制,其根本可以简单的理解成 对flag的增减操作,跟自旋... down_interruptible 和...
  • linux内核编程--4netfiter钩子函数

    千次阅读 2018-03-09 22:16:51
    1. 背景京东金融资深C/C++开发工程师 岗位被面试到,本来在《深入linux内核架构》一书中见过,但由于整本书看的不是很懂,也没实验,当时吱吱唔唔的回答了,答案不是很理想。后来也就没有了后来······2. 概述...
  • linux ceil函数

    2017-07-19 00:09:21
    ceil(取不小于参数的最小整型数)Linux下的使用   ceil(取不小于参数的最小整型数) 相关函数: fabs 表头文件: #include 定义函数: double ceil (double x); 函数说明: ceil()会返回不小于参数
  • 前面文章讲了Linux系统的ethtool框架的一些东西,是从用户空间可以直观认识到的地方入手。同样,本文从Linux系统绝大部分人都熟悉的“ifconfig eth0 up”命令来跟踪一下此命令在内核中的发生了什么事情。由于...
  • linux网络编程之shutdown() 与 close()函数详解

    万次阅读 多人点赞 2012-01-05 21:32:05
    1.close()函数 #include int close(int sockfd); //返回成功为0,出错为-1.  close 一个套接字的默认行为是把套接字标记为已关闭,然后立即返回到调用进程,该套接字描述符不能再由调用进程使用,也就是说它不能...
  • 当使用Linux中的mount命令挂载一个Windows的共享目录的时候有时会出现:mount error(112): Host is downRefer to the mount.cifs(8) manual page (e.g. man mount.cifs)出现Host is down的错误在挂载Windows 8,8.1,10...
1 2 3 4 5 ... 20
收藏数 45,664
精华内容 18,265
关键字:

down函数 linux