Ch5 定时器及时钟服务
代码链接:https://gitee.com/xin_yu_liu/unix-linux-code
本章概要:
- 定时器和定时器服务
- 硬件定时器的原理
- CPU操作和中断处理
- Linux中与定时器相关的系统调用、库 函数和定时器服务命令
- 进程冋隔定时器、定时器生成的信号
5.1 硬件定时器
定时器是由时钟源和可编程计数器组成的硬件设备。
- 时钟源通常是一个晶体振荡 器,会产生周期性电信号,以精确的频率驱动计数器
5.2 个人计算机定时器
5.3 CPU操作
中断处理和异常处理都在操作系统内核中进行。在大多数情况下,用户级程序无法访问它们,但它们是 理解操作系统(如Linux)定时器服务和信号的关键。
5.4 中断处理
-
外部设备(如定时器)的中断被馈送到中断控制器的预定义输入行(Intel 1990 ; Wang 2015),按优先级对中断输入排序,并将具有最高优先级的中断作为中断请求(IRQ)路由 到CPU。
-
在每条指令执行结束时,如果CPU未处于接受中断的状态,即在CPU的状态寄 存器中屏蔽了中断.它将忽略中断请求.使其处于挂起状态,并继续执行下-条指令。
-
如果 CPU处于接受中断状态,即中断未被屏蔽.那么CPU将会转移它正常的执行顺序来进行中 断处理对于每个中断,可以编程中断控制器以生成一个唯一编号,叫作中断向量,标识中 断源。在获取中断向量号后,CPU用它作为内存中中断向量表(AMD64 2011 )中的条目索 引,条目包含一个指向中断处理程序入口地址的指针来实际处理中断。
-
当中断处理结束时, CPU恢复指令的正常执行
5.5 时钟服务函数
在几乎所有的操作系统(os)中,操作系统内核都会提供与时钟相关的各种服务,时钟 服务可通过系统调用、库函数和用户级命令调用。
-
通过gettimeofday()获取系统时间
/********* gettimeofday.c £ile***/ #include <stdio.h> #include <stdlib.h> #include <sys/time.h> stiruct timeval t; int main() { gettimeofday(&tff NULL); printf("sec=%ld usec=%d\n", t.tv_sec, t.tv_usec); printf((char *)ctime(&t.tv_sec)); )
-
通过settimeofday()设置系统时间。
/********* settimeofday.c file***/ #include <stdio.h> #include <stdlib.h> #include <sys/time.h> #include <time.h> struct timeval t; int main() int r; t.tv_sec = 123456789; t.tv_usec= 0; r = set t: imeof day (&t, NULL); if (!r){ printf (''settimeofday () failed\nz,); exit(1); } gettimeofday(&t, NULL); printf("sec=%ld usec=%ld\n"z t.tv_sec, t.tv_usec); printf ctime (&t.tv_sec)) ; // show time in calendar form }
-
time系统调用。
/************ time.c file ***********/ #include <stdio.h> #include <time.h> time_t start, end; int main() ( int i; start = time(NULL); printf (''start=%ld\nw , start); for (i=0; i<123456789; i++); // delay to simulate computation end = time (NULL); printf (''end =%ld time=%ld\nw , end, end-start);
-
time 和 date 命令
- date:打印或设置系统日期和时间。
- time:报告进程在用户模式和系统模式下的执行时间和总时间。
- hwclock:查询并设置硬件时钟(RTC),也可以通过BIOS来完成。
5.6 时间间隔器
Linux为每个进程提供了三种不同类型的间隔计时器,可用作进程计时的虚拟时钟。
间隔定时器由setitimer()系统调用创建。
getitimer()系统调用返回间隔定时器的状态。
int getitimer(int which, struct itimerval *curr_value);
int setitimer(int which, const struct itimeirval *new_value,
struct itimerval *old_value);
/*********** setitimer.c file *********/
#include <signal.h>
#include <Btdia.h>
#include <sys/time.h>
int count = 0;
struct it interval t;
void tizner_handler(int sig)
printf("timer_handler: signal=%d count=%d\n", sig, ++count); if (count>=8)(
printf(■cancel timer\n");
t.it_value.tv_sec = 0;
t.it_value.tv_usec = 0;
setitimer(ITIMER_VIRTUAL, &t, NULL);
int main()
(
struct itimerval timer;
// Install timer_handler as SIGVTALRM signal handler signal(SIGVTALRM, timer_handler);
// Configure the timer to expire after 100 msec
timer.it_value.tv_sec = 0;
timer.it_value.tv_usec = 100000; // 100000 nsec
// and every 1 sec afterward
timer.it_interval.tv_sec = 1;
timer.it_interval.tv_usec = 0;
// Start a VIRTUAL itimer
setitimer(ITIMER_VIRTUALr NULL);
printf("looping: enter Control-C to terminate\n"); while(1);
5.7 REAL模式间隔定时器
VIRTUAL和PROF模式下的间隔计时器仅在执行进程时才有效。
- REAL模式冋隔定时器各不相同,因为无论进程是否正在执行,它们都必须由定时器中断处理程序来更新一因此,操作系统内核必须使用额外的数 据结构来处理进程的REAL模式定时器,并在定时器到期或被取消时采取措施。