Chinaunix首页 | 论坛 | 博客
  • 博客访问: 13075
  • 博文数量: 7
  • 博客积分: 0
  • 博客等级: 民兵
  • 技术积分: 10
  • 用 户 组: 普通用户
  • 注册时间: 2016-11-04 09:23
文章分类
文章存档

2016年(7)

我的朋友
最近访客

分类: 嵌入式

2016-11-08 15:20:56

一、内核中如何记录时间

任何程序都需要时间控制,其主要目的是:
1.测量时间流逝和比较时间
2.知道当前时间
3.指定时间量的延时操作

        为达到这个目的,应用程序使用日历时间(年月日时分秒)或者自1970年1月1日零时零分零秒到当前的秒数来度量时间的流逝,但内核中需要更加有精度的时间度量,因此内核使用时钟嘀嗒来记录时间。时钟中断发生后内核内部时间计数器增加1(即:增加1个时钟嘀嗒),系统引导时为0,当前值为自上次系统引导以来的时钟滴答数,程序可通过内核定义的全局变量jiffies_64或jiffies来访问。真实硬件上每秒的嘀嗒数从 50 到 1200 不等 ,x86上默认为1000,而tiny4412上默认为200,出于统一编程接口的考虑,内核定义了一个宏HZ(可通过make menuconfig更改),它表示1秒钟的嘀嗒数,可供程序使用。内核一般通过jiffies值来获取当前时间。
Jiffies 和 jiffies_64是 unsigned long 类型只读变量。(1秒加HZ次)
补充:板子默认jiffies初值并不是0,而是-5分钟


比较2个时间的大小,常用内核的如下宏定义:
#include
int time_after(unsigned long a, unsigned long b);
int time_before(unsigned long a, unsigned long b);
int time_after_eq(unsigned long a, unsigned long b);
int time_before_eq(unsigned long a, unsigned long b);

二、内核时间

1.忙等延时

2.睡眠延时

短延时

当一个设备驱动需要等待硬件的反应时间, 涉及到的延时常常是最多几个毫秒 。此种延时就是短延时,一般采用忙等待。相关函数如下:

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

长延时

如果需要延后较长时间,就可以采用长延时。长延时可分为忙等待和睡眠等待两种方式。


struct timeval {
    __kernel_time_t        tv_sec;        /* seconds */
    __kernel_suseconds_t    tv_usec;    /* microseconds */
};
struct timespec {
        long       ts_sec;
        long       ts_nsec;
};
获取当前时间
void do_gettimeofday(struct timeval *tv)
void getnstimeofday(struct timespec *ts)

signed long __sched schedule_timeout(signed long timeout)

高精度定时器是采用红黑树实现的,而普通的定时器是采用时间轮循算法实现的
3.内核定时器(基于软中断)

struct timer_list {
    struct list_head entry;
    unsigned long expires;
    struct tvec_base *base;

    void (*function)(unsigned long);
    unsigned long data;

    int slack;
    .......
};
//初始化定时器
init_timer(&timer);
timer.expires = jiffies + HZ * 5;
timer.function = fun;
timer.data = 100;
//把定时器插入相应的链表中
add_timer(&timer);

del_timer(&timer);

4.高精度定时器

单纯的在高精度定时器模式下操作高精度定时器,整个操作框架如下:

初始化hrtimer_init,通过hetimer结构体设置相关数据,比如定时时长等->开启定时器hrtimer_start->运行高精度定时器hrtimer_run_queues->触发中断,调用中断回调函数,hrtimer_interrupt->移除高精度定时器remove_hrtimer.

高分辨率定时器可以基于两种时钟(时钟基础,clock base):一种是单调时钟(CLOCK_MONOTONIC),在系统启动时,从0开始;另一种时钟(CLOCK_REALTIME)表示系统的实际时间。

struct hrtimer {
    struct timerqueue_node        node;
    ktime_t                _softexpires;
    enum hrtimer_restart        (*function)(struct hrtimer *);
    struct hrtimer_clock_base    *base;
    unsigned long            state;
    .......
};
enum hrtimer_restart {
    HRTIMER_NORESTART,    /* Timer is not restarted */
    HRTIMER_RESTART,    /* Timer must be restarted */
};
static inline u64 hrtimer_forward_now(struct hrtimer *timer,  ktime_t interval)

 hrtimer_init – 给定时钟初始化定时器

 @timer: 将要被初始化的定时器

 @clock_id: 将要被用到的时钟

 @mode: 定时器模式 abs/rel

mode可以使用五个常数,如下:

enum hrtimer_mode {

HRTIMER_MODE_ABS = 0x0, /* 时间是绝对的 */

HRTIMER_MODE_REL = 0x1, /*时间是相对的 */

HRTIMER_MODE_PINNED = 0x02, /* 定时器被绑定到CPU */

HRTIMER_MODE_ABS_PINNED = 0x02,

HRTIMER_MODE_REL_PINNED = 0x03,

};
hrtimer_start(struct hrtimer *timer, ktime_t tim, const enum hrtimer_mode mode),
@timer代表将要被添加的定时器
@tim代表到期时间
@mode代表定时器模式
如果启动成功,则返回0,否则返回1。

int hrtimer_cancel(struct hrtimer *timer)(一直等处理程序执行完毕)
int hrtimer_try_to_cancel(struct hrtimer *timer)(正在执行因而无法停止,则返回-1)

hrtimer_interrupt(struct clock_event_device *dev)
















阅读(1491) | 评论(0) | 转发(0) |
给主人留下些什么吧!~~