1-Linux time system

Linux time system

Linux中跟时间有关的函数变量有很多,但是对开发者来说无非就是用了计时/延时/挂起/获取时间等,下面列出自己所使用过的一些时间接口,供大家理解使用。

jiffies

在内核代码中,到处充斥着jiffies变量,jiffies在include/linux/jiffies.h中定义,在linux启动的时候会将jiffies清0,当系统完成对时钟中断的初始化后,在每个时钟滴答时jiffies都会被加1,所以在驱动程序开发过程中,使用jiffies变量就已足够所有基于jieffies的时间度量任务。

jiffies的使用通常要配合着宏HZ,宏HZ的定义位于.confg,一般都将其设置为1000,1秒1000次即1ms。
例:

time1 = jiffies + 2 * HZ;则time1表示未来的2秒;
time2 = jiffies + 3 * HZ/1000;则time2表示未来的3毫秒;

在jiffies.h还为我们提供了很多接口函数,主要有两类,一类为时间的比较,一类为时间的转化。 下面进行简单说明举例:
1、时间的比较

time_after(a,b);        //如果时间点a在时间点b之后,则返回1
time_before(a,b);       //如果时间点a在时间点b之前,则返回1
time_after_eq(a,b);     //如果时间点a在时间点b之后或等于b,则返回1
time_before_eq(a,b);    //如果时间点a在时间点b之前或等于b,则返回1
time_in_range(a,b,c);   //如果时间点a在时间点b和c之间或等于b或c,则返回1

例:

int time_test()
{
    unsigned long timeout = jiffies + 2 * HZ/1000;  //2ms
    do_time_task();
    if(time_after(jiffies,timeout))    //如果do_time_task()函数执行超过2ms,则成立
		return 1;
    return 0;
}

2.时间转化
为了方便理解,我们需要将jiffies转化成比较直观的毫秒ms或者是微妙us等形式,jiffies.h里面一个了一些比较直观的转化函数,其实现函数在kernel/time.c里面 如:

unsigned int jiffies_to_msecs(const unsigned long j);
unsigned int jiffies_to_usecs(const unsigned long j);
unsigned long msecs_to_jiffie(const unsigned int m);
unsigned long usecs_to_jiffie(const unsigned int u);

do_gettimeofday

当我们需要得到某一段代码所执行的时间是多少,可以使用do_gettimeofday函数,该函数定义在kernel/time/timekeeping.c中,申明在include/linux/time.h中,do_gettimeofday函数是在内核的函数,如果在应用层实现该这个函数则使用gettimeofday,包含sys/time.h即可,使用方法与do_gettimeofday一样。

举个简单的例子:

int gettimeofday_test()
{
	struct timeval tv_start;
    struct timeval tv_end;
    float timeuse;
    
    gettimeofday(&tv_start, NULL);
    do_gettimeofday_task();
    gettimeofday(&tv_end, NULL);
    
	timeuse = 1000000*(tv_end.tv_sec - tv_start.tv_sec) + tv_end.tv_usec - tv_start.tv_usec;
    timeuse /= 1000;
    printf("Time-consuming: %f ms\n",  timeuse);

    return 0;
}

delay

delay函数为死等待,这种函数只能用在短延时上,如微妙甚至纳秒等级的 Linux内核提供了如下短延时接口函数,位于include/linux/delay.h中

void mdelay(usigned long msecs); 
void udelay(usigned long usecs); 
void ndelay(usigned long nsecs);

sleep

上面的短延时为忙等待,当为长延时不能为忙等待,需要将任务挂起,这是我们可以使用sleep函数 在kernel/timer.c里面有实现了msleep()函数,也在include/linux/delay.h中申明,其原型如下,

sleep也是我们在写shell脚本时比较经常使用的延时、循环执行命令,直接调用即可使用。

内核定时器timer

如果希望在内核中以一定的时间间隔来执行执行某项任务,如:每隔一秒查询一次button的状态,可以使用内核定时器来实现。内核中已经为我们提供了定时器数据结构timer_list,和定时器的接口函数,位于include/linux/timer.h中。

定时器timer的实现步骤就两步:

  • 初始化定时器,设置定时器的触发时间,指定该定时器的回调函数。
  • 实现定时器回调函数,如果需要循环执行,则需要在该定时器的回调函数中重新启动该定时器。

举个简单的例子:

#define TIMER_FUNC(_fn)  void _fn(unsigned long timer_arg)
#define TIMER_INIT(_osdev, _timer, _fn, _arg)        \
do {                                                 \
        init_timer(_timer);                          \
        (_timer)->function = (_fn);                  \
        (_timer)->data = (unsigned long)(_arg);      \
} while (0)
#define TIMER_SET(_timer, _ms)  mod_timer(_timer, jiffies + ((_ms)*HZ)/1000)

struct timer_list os_timer_test; 

static TIMER_FUNC(timer_test_func)
{
	TIMER_SET(&os_timer_test, 1000);   //重新设置该定时器
}

int timer_test()
{
    TIMER_INIT(NULL, &os_timer_test, timer_test_func, &os_timer_test);    //初始化定时器,绑定回调函数
	TIMER_SET(&os_timer_test, 1000);   //1s
    return 0;
}

系统时间date

date主要用来显示和设定系统的日期与时间,通常会在shell中使用到data命令

1.data的显示

最直接的方式即输入date,如下:

# date 
Thu Dec 15 14:28:19 GMT 2016

这种方式会将信息以一定的格式显示出来,星期、月份、日期、时:分:秒、时区、年份
如果我们需要得到更具体的信息可以通过"data +%$"来获取,如:

# date +%H    //小时
14
# date +%m    //月份
12
# date +%y    //年份
16

具体指令如下:

命令含义
%H小时(00…23)
%I小时(01…12)
%k小时(0…23)
%l小时(1…12)
%M分钟(00…59)
%p显示本地 AM 或 PM
%r直接显示时间 (12 小时制,格式为 h : m : s [AP]M)
%s从 1970 年 1 月 1 日 00:00:00 UTC 到目前为止的秒数
%S秒(00…61)
%T直接显示时间 (24 小时制)
%X相当于 %H:%M:%S
%Z显示时区
%a星期几 (Sun…Sat)
%A星期几 (Sunday…Saturday)
%b月份 (Jan…Dec)
%B月份 (January…December)
%c直接显示日期与时间
%d日 (01…31)
%D直接显示日期 (mm/dd/yy)
%h同 %b
%j一年中的第几天 (001…366)
%m月份 (01…12)
%U一年中的第几周 (00…53) (以 Sunday 为一周的第一天的情形)
%w一周中的第几天 (0…6)
%W一年中的第几周 (00…53) (以 Monday 为一周的第一天的情形)
%x直接显示日期 (mm/dd/yy)
%y年份的最后两位数字 (00.99)
%Y完整年份 (0000…9999)

2.data的设置
既然读取到了时钟发现错误时就需要修改,修改的方式有很多,这边就不想弄的那么复杂,用一个最直观简单的格式,如下:

# date -s "2016-12-15 14:43:33"
Thu Dec 15 14:43:33 GMT 2016

RTC时钟hwclock

linux系统时钟有两个,一个是硬件时钟,一般就是RTC时钟,另一个是系统时钟,即上面使用date时得到的信息,它是linux系统Kernel时间。当Linux启动时,系统Kernel会去读取硬件时钟的设置,然后系统时钟就会独立于硬件运作。

硬件时钟可以通过hwclock来获取,如下:

# hwclock 
Thu Dec 15 11:12:07 2016  0.000000 seconds

当我们修改了系统时钟后,想将系统时间同步到硬件时钟可以通过hwclock -w命令实现,如下:

# date -s "2016-12-15 15:40:00"
Thu Dec 15 15:40:00 GMT 2016
# hwclock 
Thu Dec 15 11:24:25 2016  0.000000 seconds
# hwclock -w
# hwclock 
Thu Dec 15 15:40:23 2016  0.000000 seconds

busybox里面也实现从硬件时钟同步到系统时钟的命令hwclock -s,但这个指令一般很少用,因为kernel一启动系统时钟就是读取硬件的时钟,所以两则已经相等了,我们发现系统时钟不对时,则会去修改系统时钟再同步到硬件时钟。

注:以上内容都是本人在学习过程积累的一些心得,难免会有参考到其他文章的一些知识,如有侵权,请及时通知我,我将及时删除或标注内容出处。文章只是起一个引导作用,详细的数据解析内容还请查看Linux相关教程,感谢您的查阅。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值