jiffies 计数器
定时器中断由系统定时硬件以规律地间隔产生; 这个间隔在启动时由内核根据 HZ 值来编程, HZ 是一个体系依赖的值, 每次发生一个时钟中断, 一个内核计数器的值递增. 这个计数器在系统启动时初始化为 0, 因此它代表从最后一次启动以来的时钟嘀哒的数目.

这个计数器和来读取它的实用函数位于 , 尽管你会常常只是包含 ,

#include
unsigned long j, stamp_1, stamp_half, stamp_n;
 
j = jiffies; /* read the current value */
stamp_1 = j + HZ; /* 1 second in the future */
stamp_half = j + HZ/2; /* half a second */
stamp_n = j + n * HZ / 1000; /* n milliseconds */
忙等待

如果你想延时执行多个时钟嘀哒, 允许在值中某些疏忽, 最容易的( 尽管不推荐 ) 的实现是一个监视 jiffy 计数器的循环. 这种忙等待实现常常看来象下面的代码, 这里 j1 是 jiffies 的在延时超时的值:

while (time_before(jiffies, j1)){}

 
超时
    到目前为止所展示的次优化的延时循环通过查看 jiffy 计数器而不告诉任何人来工作. 但是最好的实现一个延时的方法, 如你可能猜想的, 常常是请求内核为你做. 有 2 种方法来建立一个基于 jiffy 的超时, 依赖于是否你的驱动在等待其他的事件.

如果你的驱动使用一个等待队列来等待某些其他事件, 但是你也想确保它在一个确定时间段内运行, 可以使用 wait_event_timeout 或者wait_event_interruptible_timeout:

#include
long wait_event_timeout(wait_queue_head_t q, condition, long timeout);
long wait_event_interruptible_timeout(wait_queue_head_t q, condition, long timeout);

这些函数在给定队列上睡眠, 但是它们在超时(以 jiffies 表示)到后返回. 因此, 它们实现一个限定的睡眠不会一直睡下去. 注意超时值表示要等待的 jiffies数, 不是一个绝对时间值. 这个值由一个有符号的数表示, 因为它有时是一个相减运算的结果, 尽管这些函数如果提供的超时值是负值通过一个 printk 语句抱怨. 如果超时到, 这些函数返回 0; 如果这个进程被其他事件唤醒, 它返回以 jiffies 表示的剩余超时值. 返回值从不会是负值, 甚至如果延时由于系统负载而比期望的值大.

wait_event_timeout 和 wait_event_interruptible_timeout 被设计为有硬件驱动存在, 这里可以用任何一种方法来恢复执行: 或者有人调用 wake_up 在等待队列上, 或者超时到. 这不适用于 jitqueue, 因为没人在等待队列上调用 wake_up ( 毕竟, 没有其他代码知道它 ), 因此这个进程当超时到时一直唤醒. 为适应这个特别的情况, 这里你想延后执行不等待特定事件, 内核提供了 schedule_timeout 函数, 因此你可以避免声明和使用一个多余的等待队列头:

#include
signed long schedule_timeout(signed long timeout);

这里, timeout 是要延时的 jiffies 数. 返回值是 0 除非这个函数在给定的 timeout 流失前返回(响应一个信号). schedule_timeout 请求调用者首先设置当前的进程状态, 因此一个典型调用看来如此:

set_current_state(TASK_INTERRUPTIBLE);
schedule_timeout (delay);

第一行调用 set_current_state 来设定一些东西以便调度器不会再次运行当前进程, 直到超时将它置回 TASK_RUNNING 状态. 为获得一个不可中断的延时, 使用TASK_UNINTERRUPTIBLE 代替.

短延时

当一个设备驱动需要处理它的硬件的反应时间, 涉及到的延时常常是最多几个毫秒.

内核函数 ndelay, udelay, 以及 mdelay 对于短延时好用, 分别延后执行指定的纳秒数, 微秒数或者毫秒数. 它们的原型是:

#include
void ndelay(unsigned long nsecs);
void udelay(unsigned long usecs);
void mdelay(unsigned long msecs);

有另一个方法获得毫秒(和更长)延时而不用涉及到忙等待. 文件 声明这些函数:

void msleep(unsigned int millisecs);
unsigned long msleep_interruptible(unsigned int millisecs);
void ssleep(unsigned int seconds)

前 2 个函数使调用进程进入睡眠给定的毫秒数. 一个对 msleep 的调用是不可中断的; 你能确保进程睡眠至少给定的毫秒数. 如果你的驱动位于一个等待队列并且你想唤醒来打断睡眠, 使用 msleep_interruptible. 从 msleep_interruptible 的返回值正常地是 0; 如果, 但是, 这个进程被提早唤醒, 返回值是在初始请求睡眠周期中剩余的毫秒数. 对 ssleep 的调用使进程进入一个不可中断的睡眠给定的秒数.

Linux内核驱动之延时 【转】的更多相关文章

  1. Linux内核驱动之延时---内核超时处理【转】

    转自:http://blog.chinaunix.net/uid-24219701-id-3288103.html 内核超时处理 jiffies 计数器 定时器中断由系统定时硬件以规律地间隔产生; 这 ...

  2. linux内核驱动模型

    linux内核驱动模型,以2.6.32内核为例.(一边写一边看的,有点乱.) 1.以内核对象为基础.用kobject表示,相当于其它对象的基类,是构建linux驱动模型的关键.具有相同类型的内核对象构 ...

  3. linux 内核驱动--Platform Device和Platform_driver注册过程

    linux 内核驱动--Platform Device和Platform_driver注册过程 从 Linux 2.6 起引入了一套新的驱动管理和注册机制 :Platform_device 和 Pla ...

  4. Unix/Linux环境C编程新手教程(12) openSUSECCPP以及Linux内核驱动开发环境搭建

    1. openSUSE是一款优秀的linux. watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQvaXRjYXN0Y3Bw/font/5a6L5L2T/font ...

  5. Unix/Linux环境C编程入门教程(12) openSUSECCPP以及Linux内核驱动开发环境搭建

    1. openSUSE是一款优秀的linux. 2.选择默认虚拟机 3.选择稍后安装操作系统 4.选择linux  opensuse 5. 选择默认虚拟机名称 6.设置处理器为双核. 7.内存设置为2 ...

  6. 【引用】Linux 内核驱动--多点触摸接口

    本文转载自James<Linux 内核驱动--多点触摸接口>   译自:linux-2.6.31.14\Documentation\input\multi-touch-protocol.t ...

  7. Linux内核驱动开发之KGDB原理介绍及kgdboe方式配置

    接博文<Linux内核驱动开发之KGDB单步调试内核(kgdboc方式)>.上篇博文中,仅简单介绍使用串口的Kgbd的流程(kgdboc方式),本文将重点介绍KGDB调试Linux内核的原 ...

  8. 嵌入式C语言自我修养 02:Linux 内核驱动中的指定初始化

    2.1 什么是指定初始化 在标准 C 中,当我们定义并初始化一个数组时,常用方法如下: ] = {,,,,,,,,}; 按照这种固定的顺序,我们可以依次给 a[0] 和 a[8] 赋值.因为没有对 a ...

  9. OMAP4之DSP核(Tesla)软件开发学习(二)Linux内核驱动支持OMAP4 DSP核

    注:必须是Linux/arm 3.0以上内核才支持RPMSG,在此使用的是.config - Linux/arm 3.0.31 Kernel Configuration.(soure code fro ...

随机推荐

  1. tjoi2018D2T2(luogu4590) 游园会 (状压dp)

    题解劝退系列 设长的那个串是A,短的那个串是B. 那我们在如果已经知道某个A的时候,A[1..i]和B[1..j]的最长公共子序列$f[i][j]=max\{f[i-1][j],f[i][j-1],f ...

  2. “由于下列错误,Parallel port driver 服务启动失败”,注意了

    最近在“事件查看器”中发现这么一个错误:“由于下列错误,Parallel port driver 服务启动失败”, 我到网上搜索了一下,发现很多网页上都说解决办法: 把HKEY_LOCAL_MACHI ...

  3. typescript接口(学习笔记非干货)

    typescript的核心原则之一就是对所具有的shape类型检查结构性子类型化 One of the core principles of typescript is to check struct ...

  4. 工具函数判断data为整型字符串

    /** * 如果data是整型字符串,则转为整型,否则原样返回 * @param {*} data 整型字符串 */ export const stringToInt = (data) => { ...

  5. linux提取指定列字符并打印所有内容(awk)

    假设有文件长如下样子: CHROM  POS     ID      REF     ALT     QUAL    FILTER  INFO    FORMAT  samplename 1 3552 ...

  6. 2018.9青岛网络预选赛(A)

    传送门:Problem A https://www.cnblogs.com/violet-acmer/p/9664805.html 题意: 求m个PERFECTs中最多有多少个连续的PERFECT和最 ...

  7. gb2312提交的url编码转换成utf8的查询

    使用场景,当一网站是gb2312的编码向另一个是utf8的网站提交查询 如:http://search.chinayq.com/?key=%C0%D6%C6%F7 其中key为gb2312的url编码 ...

  8. Ruler.java

    /****************************************************************************** * Compilation: javac ...

  9. NPOI学习笔记

    NPOI最简单的创建一个Excel,并且在指定单元格内填写一些数据 HSSFWorkbook workbook = new HSSFWorkbook(file); ISheet sheet = wor ...

  10. 同步、异步、阻塞、非阻塞与future

    前言 随着移动互联网的蓬勃发展,手机App层出不穷,其业务也随之变得错综复杂.针对于开发人员来说,可能之前的一个业务只需要调取一次第三方接口以获取数据,而如今随着需求的增加,该业务需调取多个不同的第三 ...