• linux 时间模块 三


    LINUX的时钟中断中涉及至二个全局变量一个是xtime,另一个则是jiffies。
    有一个与时间有关的时钟:实时时钟(RTC),这是一个硬件时钟,用来持久存放系统时间,系统关闭后靠主板上的微型电池保持计时。系统启动时,内核
    通过读取RTC来初始化Wall
    Time,并存放在xtime变量中,即xtime是从cmos电路中取得的时间,一般是从某一历史时刻开始到现在的时间,也就是为了取得我们操作系统上
    显示的日期,它的精度是微秒。这是RTC最主要的作用。
    jiffies是记录着从电脑开机到现在总共的时钟中断次数。在linux内核中jiffies远比xtime重要,jiffies取决于系统的频
    率,单位是
    Hz,是周期的倒数,一般是一秒钟中断产生的次数,所以,假如我们需要知道系统的精确的时间单位时,需要换算了,假如我们系统的频率是200Mhz,那么
    一次中断的间隔是1秒/200,000,000Hz=0.000 000
    005秒,所以理论上我们系统的精确度是5ns。LINUX系统时钟频率是一个常数HZ来决定的,
    通常HZ=100(Linux内核从2.5版内核开始把频率从100调高到1000),那么他的精度度就是10ms(毫秒)。也就是说每10ms一次中
    断。所以一般来说Linux的精确度是10毫秒。
    内核一般通过jiffies值来获取当前时间。尽管该数值表示的是自上次系统启动到当前的时间间隔,但因为驱动程序的生命期只限于系统的运行期
    (uptime),所以也是可行的。驱动程序利用jiffies的当前值来计算不同事件间的时间间隔。硬件给内核提供一个系统定时器用以计算和管理时间,
    内核通过编程预设系统定时器的频率(即上面所说的HZ=100)。节拍率(tick
    rate),每一个周期称作一个tick(节拍)。jiffies是内核中的一个全巨变量。系统启动一来产生的节拍数。譬如,如果计算系统运行了多长时
    间,可以用 jiffies/tick rate 来计算。
    jiffies定义在文件
    如果您需要更精确的时间来测量或者记录某些事情的话,内核中有个xtime全局变量,类型是struct timespec {time_t tv_sec; long tv_nsec;}按照这个数据结构,它是ns级的。
    有一个current_kernel_time函数,通过它就可以获取xtime的值。但是xtime是在时钟中断里更新的,而一个tick往往是
    10ms或者100ms,它只能保证在时钟中断ISR调用时刻,它返回的值是精确到ns级,并不能保证任何一个调用这个函数的时刻都能这样,原因是
    xtime的更新速度比它差几个数量级.
    kernel的time基本类型:
    1) system time
    A monotonically increasing value that represents the amount of time the
    system has been running. 单调增长的系统运行时间, 可以通过time source,
    xtime及wall_to_monotonic计算出来.
    2) wall time
    A value representing the the human time of day, as seen on a wrist-watch. Realtime时间: xtime.
    3) time source
    A representation of a free running counter running at a known
    frequency, usually in hardware, e.g GPT.
    可以通过clocksource->read()得到counter值
    4) tick
    A periodic interrupt generated by a hardware-timer, typically with a fixed interval defined by HZ: jiffies
    这些time之间互相关联, 互相可以转换.
    system_time = xtime + cyc2ns(clock->read() - clock->cycle_last) + wall_to_monotonic;
    real_time = xtime + cyc2ns(clock->read() - clock->cycle_last)
    也就是说real time是从1970年开始到现在的nanosecond, 而system time是系统启动到现在的nanosecond.
    这两个是最重要的时间, 由此hrtimer可以基于这两个time来设置过期时间. 所以引入两个clock base:
    CLOCK_REALTIME: base在实际的wall time
    CLOCK_MONOTONIC: base在系统运行system time
    CLOCK_REALTIME 调用ktime_get_real()来获得真实时间, 该函数用上面提到的等式计算出realtime.
    CLOCK_MONOTONIC 调用ktime_get(), 用system_time的等式获得monotonic time.
    Clock API
    clock_gettime(clockid_t, struct timespec *)
    获取对应clock的时间
    clock_settime(clockid_t, const struct timespec *)
    设置对应clock时间
    clock_nanosleep(clockid_t, int, const struct timespec *, struct timespec *)
    进程nano sleep
    clock_getres(clockid_t, struct timespec *)
    获取时间精度, 一般是nanosec
    clockid_t 定义了四种clock:
    CLOCK_REALTIME 
    System-wide realtime clock. Setting this clock requires appropriate privileges. 
    CLOCK_MONOTONIC 
    Clock that cannot be set and represents monotonic time since some unspecified starting point. 
    CLOCK_PROCESS_CPUTIME_ID 
    High-resolution per-process timer from the CPU. 
    CLOCK_THREAD_CPUTIME_ID 
    Thread-specific CPU-time clock.
    前两者前面提到了, 后两个是和进程/线程统计时间有关系, 应用层可以利用这四种clock, 提高灵活性及精度.
    Timer API
    Timer 可以建立进程定时器,单次或者周期性定时。
    int timer_create(clockid_t clockid, struct sigevent *restrict evp, timer_t *restrict timerid);
    创建定时器。
    clockid 指定在哪个clock base下创建定时器。
    evp (sigevent) 可以指定定时器到期后内核发送哪个信号给进程,以及信号所带参数;默认为SIGALRM。
    timerid 返回所建timer的id号。
    在signal 处理函数里,可以通过siginfo_t.si_timerid
    获得当前的信号是由哪个timer过期触发的。试验了一下,最多可创建的timer数目和ulimit里的pending
    signals的有关系,不能超过pending signals的数量。
    int timer_gettime(timer_t timerid, struct itimerspec *value); 
    获得timer的下次过期的时间。
    int timer_settime(timer_t timerid, int flags, const struct itimerspec *restrict value, struct itimerspec *restrict ovalue);
    设置定时器的过期时间及间隔周期。
    int timer_delete(timer_t timerid);
    删除定时器。
    这些系统调用都会建立一个posix_timer的hrtimer,在过期的时候发送信号给进程。

  • 相关阅读:
    Ubuntu 上更新 Flash 插件
    Ubuntu 17.10 安装 “爱壁纸” 时,缺失了 python-support 依赖
    Windows 7 64 位操作系统安装 Ubuntu 17.10
    Linux CentOS 6.9(图形界面)安装中文输入法
    Linux 编译 apr-util 时报错
    Linux 添加普通用户到 sudoers 文件
    PHP 结合实例认识 Socket
    PHP 快速建立一个对象
    使用Git GUI,上传项目到github,并实现预览功能
    用JS判断号码
  • 原文地址:https://www.cnblogs.com/jkred369/p/6693776.html
Copyright © 2020-2023  润新知