<linux/param.h>
可通过定义的CPUHz值判断时间

使用 jiffies 计数器
这个计数器和用来读取它的工具函数包含在,通常只需包含 ,它会自动放入linux/jiffies.h
jiffies和jiffies_64必须被当作只读变量

#include <linux/jiffies.h>
unsigned long j, stamp_1, stamp_half, stamp_n;
j = jiffies; /* 读取当前时间值 */
stamp_1 = j + HZ; /* 未来1s*/
stamp_half = j + HZ/2; /* 半秒 */
stamp_n = j + n * HZ / 1000; /* n个毫秒 */
大概50天这个计数器会溢出

最好使用以下宏进行比较
time_after(a,b) a比b时间靠后返回1
time_before(a,b) a比b靠前返回1
time_after_eq(a,b) 靠后或者相等
time_before_eq(a,b) 靠前或者相等

计算时间差diff = (ulong)t2-(ulong)tl;转换为毫秒 msec = diff * 1000/Hz

内核时间和用户空间时间转换
extern unsigned long timespec_to_jiffies(const struct timespec *value);
extern void jiffies_to_timespec(const unsigned long jiffies,struct timespec *value);
extern unsigned long timeval_to_jiffies(const struct timeval *value);
extern void jiffies_to_timeval(const unsigned long jiffies,struct timeval *value);

不能直接读64位jiffies_64如需读取则应该 u64 get_jiffies_64(void);

while (time_before(jiffies, j1)) {
    schedule();
}

超时
<linux/wait.h>
#define wait_event_timeout(wq, condition, timeout) (1)当condition为真的时候,会返回 (2)当timeout到达时也会返回,不管此时condition为真为假都会返回
#define wait_event_interruptible(wq, condition)
上述函数会在给定的等待队列上休眠,但是会在超时(jiffies)到期时返回
两个函数实现了一种有界限的休眠,这种休眠不会永远继续
wait_queue_head_t    wait;
wait_event_timeout(ts->wait, ts->stopped,msecs_to_jiffies(5));

获取当前时间
驱动一般无需知道时钟时间(用年月日、小时、分钟、秒来表达的时间),只对用户程序才需要,如 cron 和 syslogd。 内核提供了一个将时钟时间转变为秒数值的函数:
unsigned long
mktime(const unsigned int year0, const unsigned int mon0,
       const unsigned int day, const unsigned int hour,
       const unsigned int min, const unsigned int sec)
{
    unsigned int mon = mon0, year = year0;

/* 1..12 -> 11,12,1..10 */
    if (0 >= (int) (mon -= 2)) {
        mon += 12;    /* Puts Feb last since it has leap day */
        year -= 1;
    }

return ((((unsigned long)
         (year/4 - year/100 + year/400 + 367*mon/12 + day) +
         year*365 - 719499
     )*24 + hour /* now have hours */
     )*60 + min /* now have minutes */
    )*60 + sec; /* finally seconds */
}
/* 这个函数将时间转换成从1970年1月1日0小时0分0秒到你输入的时间所经过的秒数,溢出时间为2106-02-07 06:28:16。本人认为这个函数的使用应这样:若你要计算2000-02-07 06:28:16 到2000-02-09 06:28:16 所经过的秒数:unsigned long time1 = mktime(2000,2,7,6,28,16)-mktime(2000,2,9,6,28,16); 若还要转成jiffies,就再加上:unsigned long time2 = time1*HZ. 注意溢出的情况!*/

#include <linux/time.h>
导出了 do_gettimeofday 函数,它填充一个指向struct timeval 的指针变量。
void do_gettimeofday(struct timeval *tv);
struct timespec current_kernel_time(void);

/*得到的数据都表示当前时间距UNIX时间基准1970-01-01 00:00:00的相对时间*/
以上两个函数在ARM平台都是通过 xtime 变量得到数据的。
全局变量xtime:它是一个timeval结构类型的变量,用来表示当前时间距UNIX时间基准1970-01-01 00:00:00的相对秒数值。

短延迟
当一个设备驱动需要处理硬件的延迟(latency潜伏期), 涉及到的延时通常最多几个毫秒,在这个情况下, 不应依靠时钟嘀哒,而是内核函数 ndelay, udelay和 mdelay ,他们分别延后执行指定的纳秒数, 微秒数或者毫秒数,定义在 ,原型如下:
#include <linux/delay.h>
void ndelay(unsigned long nsecs);
void udelay(unsigned long usecs);
void mdelay(unsigned long msecs);
重要的是记住这 3 个延时函数是忙等待; 其他任务在时间流失时不能运行。
有另一个方法获得毫秒(和更长)延时而不用涉及到忙等待的方法是使用以下函数(在 中声明)
void msleep(unsigned int millisecs);
unsigned long msleep_interruptible(unsigned int millisecs);
void ssleep(unsigned int seconds)
若能够容忍比请求的更长的延时,应使用 schedule_timeout, msleep 或 ssleep。

内核定时器
当需要调度一个以后发生的动作,而在到达该时间点时不阻塞当前进程,则可使用内核定时器。内核定时器用来调度一个函数在将来一个特定的时间(基于时钟嘀哒)执行,从而可完成各类任务
内核定时器是一个数据结构,它告诉内核在一个用户定义的时间点使用用户定义的参数执行一个用户定义的函数,函数位于和kernel/timer.c。
被调度运行的函数几乎确定不会在注册它们的进程在运行时运行,而是异步运行。实际上,内核定时器通常被作为一个"软件中断"的结果而实现。当在进程上下文之外(即在中断上下文)中运行程序时,必须遵守下列规则:
(1)不允许访问用户空间;
(2)current 指针在原子态没有意义;
(3)不能进行睡眠或者调度. 例如:调用 kmalloc(..., GFP_KERNEL) 是非法的,信号量也不能使用因为它们可能睡眠。
通过调用函数in_interrupt()能够告知是否它在中断上下文中运行,无需参数并如果处理器当前在中断上下文运行就返回非零。
通过调用函数in_atomic()能够告知调度是否被禁止,若调度被禁止返回非零;调度被禁止包含硬件和软件中断上下文以及任何持有自旋锁的时候。
内核定时器的另一个重要特性是任务可以注册它本身在后面时间重新运行,因为每个 timer_list 结构都会在运行前从激活的定时器链表中去连接,因此能够立即链入其他的链表。一个重新注册它自己的定时器一直运行在同一个 CPU.
即便在一个单处理器系统,定时器是一个潜在的态源,这是异步运行直接结果。因此任何被定时器函数访问的数据结构应当通过原子类型或自旋锁被保护,避免并发访问。
内核提供给驱动许多函数来声明、注册以及删除内核定时器:
#include <linux/timer.h>
struct timer_list {
    struct list_head entry;
    unsigned long expires;/*期望定时器运行的绝对 jiffies 值,不是一个 jiffies_64 值,因为定时器不被期望在将来很久到时*/
    void (*function)(unsigned long); /*期望调用的函数*/
    unsigned long data;/*传递给函数的参数,若需要在参数中传递多个数据项,可以将它们捆绑成单个数据结构并且将它的指针强制转换为 unsiged long 的指针传入。这种做法在所有支持的体系上都是安全的并且在内存管理中相当普遍*/
    struct tvec_t_base_s *base;
#ifdef CONFIG_TIMER_STATS
    void *start_site;
    char start_comm[16];
    int start_pid;
#endif
};/*这个结构必须在使用前初始化,以保证所有的成员被正确建立(包括那些对调用者不透明的初始化):*/
void init_timer(struct timer_list *timer);
struct timer_list TIMER_INITIALIZER(_function, _expires, _data);
/*在初始化后和调用 add_timer 前,可以改变 3 个公共成员:expires、function和data*/
void add_timer(struct timer_list * timer);
int del_timer(struct timer_list * timer);/*在到时前禁止一个已注册的定时器*/
int del_timer_sync(struct timer_list *timer); /* 如同 del_timer ,但还保证当它返回时, 定时器函数不在任何 CPU 上运行,以避免在 SMP 系统上竞态, 并且在 单处理器内核中和 del_timer 相同。这个函数应当在大部分情况下优先考虑。 如果它被从非原子上下文调用, 这个函数可能睡眠,但是在其他情况下会忙等待。当持有锁时要小心调用 del_timer_sync ,如果这个定时器函数试图获得同一个锁, 系统会死锁。如果定时器函数重新注册自己, 调用者必须首先确保这个重新注册不会发生; 这通常通过设置一个" 关闭 "标志来实现, 这个标志被定时器函数检查*/
int mod_timer(struct timer_list *timer, unsigned long expires); /*更新一个定时器的超时时间, 常用于超时定时器。也可在正常使用 add_timer时在不活动的定时器上调用mod_timer*/
int timer_pending(const struct timer_list * timer); /*通过调用timer_list结构中一个不可见的成员,返回定时器是否在被调度运行*/

例子

static void timer_func(unsigned long data)
{
    char *str = (char *)data;

printk(KERN_EMERG "%s\n", str);
}

init_timer(timer[i]);
timer[i]->expires = jiffies + HZ * (i + 3);
timer[i]->data = (unsigned long)test;
timer[i]->function = timer_func;
add_timer(timer[i]);

时间、延时、延缓操作相关推荐

  1. linux设备驱动七(时间、延迟及延缓操作)

    知识点: 如何度量时间差,如何比较时间 如何获得当前时间 如何将操作延迟指定一段时间 如何调度异步函数到指定时间之后执行 度量时间差 HZ指一秒内产生的时钟中断次数,即时钟中断频率 jiffies_6 ...

  2. 1.7 时间延时器和类的别名

    1. 时间延时器 //等待一段时间,编写延时器 #include <iostream> #include <ctime> using namespace std; //time ...

  3. android 日期时间类,Android 时间与日期操作类

    获取本地日期与时间 public String getCalendar() { @SuppressLint("SimpleDateFormat") SimpleDateFormat ...

  4. java 8时间操作_Java8 时间日期类操作

    Java8 时间日期类操作 Java8的时间类有两个重要的特性 线程安全 不可变类,返回的都是新的对象 显然,该特性解决了原来java.util.Date类与SimpleDateFormat线程不安全 ...

  5. 【MySQL】Java对SQL时间类型的操作(获得当前、昨天、前年。。时间)

    Java获得当前时间 1 java.util.Date date = new java.util.Date(); 2 Timestamp time = new Timestamp(date.getTi ...

  6. Js获取当前日期时间及其它操作(转)

    Js获取当前日期时间及其它操作 var myDate = new Date(); myDate.getYear();        //获取当前年份(2位) myDate.getFullYear(); ...

  7. Oracle关于时间/日期的操作

    在oracle中有很多关于日期的函数,如: 1.add_months()用于从一个日期值增加或减少一些月份 date_value:=add_months(date_value,number_of_mo ...

  8. 时间格式化及操作(moment.js篇)

    # moment.js ## 获取当前时间 //返回当前时间moment()时间对象 moment(); moment(new Date()); //返回当前时间毫秒数 moment().valueO ...

  9. pg 日期和时间的运算操作

    4.日期和时间的运算操作: 日期和时间可以有:加.减.乘.除的运算操作. 例子:指定日期加运算:+10日后的日期 testdb=# select date '2018-08-15' + integer ...

  10. js获取当前日期时间和其他操作

    Js获取当前日期时间及其它操作 var myDate = new Date(); myDate.getYear();        //获取当前年份(2位) myDate.getFullYear(); ...

最新文章

  1. 一文让你秒懂AQS,附带源码剖析!
  2. [记录]使用openGL显示点云的一个程序
  3. Create Maintenance Plans
  4. The Genymotion virtual device could not obtain an IP address
  5. 如何使Flash在Internet Explorer的64位版本中工作
  6. 比较两张大小相同的照片的差异,返回数值
  7. postgresql兴建用户_PostgreSQL 12.2, 11.7, 10.12, 9.6.17, 9.5.21, 和 9.
  8. MySQL表结构管理
  9. 图形驱动程序和显卡驱动什么区别_科普:游戏显卡和专业图形显卡存在的区别...
  10. javascript-练习-数组数据存li中
  11. 邮件实用技巧九:如何快速查看历史邮件
  12. 传统MVP用在项目中是真的方便还是累赘?
  13. 解决shell脚本“syntax error near unexpected token `fi‘”的问题。
  14. XP-在恢复时返回到欢迎屏幕
  15. vcenter客户端控制虚拟服务器报错:“VMRC 控制台的连接已断开”
  16. 深入理解设计模式-建造者模式(生成器模式)
  17. TransCAD 交通规划软件
  18. 报名 | AI产品经理闭门会_第13期_北京_4场主题分享_本周六(2月19日)
  19. 如何做好客户需求分析
  20. 基于SVM的数据分类预測——意大利葡萄酒种类识别

热门文章

  1. RYF-Net: 深度融合网络用于单幅图像去雾(Deep Fusion Network for Single ImageHaze Removal-IEEE_TIP-2020)
  2. flutter 仿哔哩哔哩,视频详情页面效果
  3. Topaz Video Enhance AI v3.2.8
  4. Cloudera Manager 5 Overview
  5. cloudera目录结构
  6. spring核心容器 spring container 详解
  7. 【开源推荐】gnet: 一个轻量级且高性能的 Go 网络库
  8. 亚马逊、Lazada、Shopee、速卖通、eBay、Wish测评自养号运营知识——环境搭建技术详解
  9. 计算机网络(BYSEE)第六章 应用层 学习笔记(0612)
  10. 阿里工程师谈,什么是好的代码