一、引言
练习编写调用内核的时间测量功能为应用程序测量和精确定时。
通过这个实验进一步了解Linux内核的定时机制及其数据结构以及怎样从用户空间去访问内核空间的时间数据。
二、实验内容
问题A:使用ITIMER_REAL型定时器实现一个gettimeofday(),将它设置为每秒产生一个信号,并计算已经经过的秒数。
问题B:使用以上实现的gettimeofday()实现一个精确到微秒级的“壁钟”。
三、实验代码
/*****************************************
*
* 内核的定时机制
*
* Copyright: (C) 2018.4.24 by shaomingshan
*
* Compile: gcc -g -o main_a main_a.c
*
* Execute: ./main_a
*
*****************************************/
#include <stdio.h>
#include <unistd.h>
#include <stdlib.h>
#include <sys/time.h>
#include <signal.h>
static void sig_real(int);
static long real_secs = 0;
static struct itimerval realt;
int main(int argc, char *argv[])
{
signal(SIGALRM, sig_real);
realt.it_interval.tv_sec = 0;
realt.it_value.tv_sec = 0;
realt.it_interval.tv_usec = 999999;
realt.it_value.tv_usec = 999999;
setitimer(ITIMER_REAL, &realt, NULL);
for(;;);
return 0;
}
static void sig_real(int non) {
real_secs += 1;
printf("%ld\r", real_secs);
fflush(stdout);
}
/*****************************************
*
* 内核的定时机制
*
* Copyright: (C) 2018.4.24 by shaomingshan
*
* Compile: gcc -g -o main_b main_b.c
*
* Execute: ./main_b
*
*****************************************/
#include <sys/time.h>
#include <stdio.h>
#include <signal.h>
static void sighandle(int);
struct timeval now;
int today;
int main(){
struct itimerval v;
signal(SIGALRM,sighandle);
v.it_interval.tv_sec = 0;
v.it_interval.tv_usec = 1;
v.it_value.tv_sec = 0;
v.it_value.tv_usec = 1;
setitimer(ITIMER_REAL, &v, NULL);
for(;;);
}
static void sighandle(int s){
gettimeofday(&now, NULL);
today = now.tv_sec%(3600*24);
printf("%02d:%02d:%02d:%ld\r",today/3600+8,(today%3600)/60,(today%3600)%60,now.tv_usec);
fflush(stdout);
}
/*****************************************
*
* 内核的定时机制
*
* Copyright: (C) 2018.4.24 by shaomingshan
*
* Compile: gcc -g -o main_c main_c.c
*
* Execute: ./main_c
*
*****************************************/
#include <stdio.h>
#include <unistd.h>
#include <stdlib.h>
#include <signal.h>
#include <sys/time.h>
#include <wait.h>
// 父进程定时中断处理
static void psig_real(int);
static void psig_virtual(int);
static void psig_prof(int);
// 子进程1定时中断处理
static void c1sig_real(int);
static void c1sig_virtual(int);
static void c1sig_prof(int);
// 子进程2定时中断处理
static void c2sig_real(int);
static void c2sig_virtual(int);
static void c2sig_prof(int);
long unsigned int fibonnacci(unsigned int n);
static long p_real_secs = 0,
c1_real_secs = 0,
c2_real_secs = 0,
p_virtual_secs = 0,
c1_virtual_secs = 0,
c2_virtual_secs = 0,
p_prof_secs = 0,
c1_prof_secs = 0,
c2_prof_secs = 0;
static struct itimerval p_realt, c1_realt, c2_realt;
static struct itimerval p_virtt, c1_virtt, c2_virtt;
static struct itimerval p_proft, c1_proft, c2_proft;
int main(int argc, char *argv[])
{
long unsigned fib = 0;
int pid1, pid2;
unsigned int fibarg;
int status;
int i;
if (argc < 3) {
printf("Usage: testsig arg1 arg2 arg3\n");
return 1;
}
pid1 = fork();
if (pid1==0) {
signal(SIGALRM, c1sig_real);
signal(SIGVTALRM, c1sig_virtual);
signal(SIGPROF, c1sig_prof);
c1_realt.it_interval.tv_sec = 9;
c1_realt.it_interval.tv_usec = 999999;
c1_realt.it_value.tv_sec = 9;
c1_realt.it_value.tv_usec = 999999;
setitimer(ITIMER_REAL, &c1_realt, NULL);
c1_virtt.it_interval.tv_sec = 9;
c1_virtt.it_interval.tv_usec = 999999;
c1_virtt.it_value.tv_sec = 9;
c1_virtt.it_value.tv_usec = 999999;
setitimer(ITIMER_VIRTUAL, &c1_virtt, NULL);
c1_proft.it_interval.tv_sec = 9;
c1_proft.it_interval.tv_usec = 999999;
c1_proft.it_value.tv_sec = 9;
c1_proft.it_value.tv_usec = 999999;
setitimer(ITIMER_PROF, &c1_proft, NULL);
fib = fibonnacci(atoi(argv[1]));
getitimer(ITIMER_REAL, &c1_realt);
printf("Child1 fib = %ld\nChild1 Real Time = %2ldSec: %03ldMsec\n",
fib, c1_real_secs+9-c1_realt.it_value.tv_sec,
(999999-c1_realt.it_value.tv_usec)/1000);
getitimer(ITIMER_VIRTUAL, &c1_virtt);
printf("Child1 Virtual Time = %2ldSec: %03ldMsec\n",
c1_virtual_secs+9-c1_virtt.it_value.tv_sec,
(999999-c1_virtt.it_value.tv_usec)/1000);
getitimer(ITIMER_PROF, &c1_proft);
printf("Child1 Prof Time = %2ldSec: %03ldMsec\n\n",
c1_prof_secs+9-c1_proft.it_value.tv_sec,
(999999-c1_proft.it_value.tv_usec)/1000);
} else if ((pid2=fork())==0) {
signal(SIGALRM, c2sig_real);
signal(SIGVTALRM, c2sig_virtual);
signal(SIGPROF, c2sig_prof);
c2_realt.it_interval.tv_sec = 9;
c2_realt.it_interval.tv_usec = 999999;
c2_realt.it_value.tv_sec = 9;
c2_realt.it_value.tv_usec = 999999;
setitimer(ITIMER_REAL, &c2_realt, NULL);
c2_virtt.it_interval.tv_sec = 9;
c2_virtt.it_interval.tv_usec = 999999;
c2_virtt.it_value.tv_sec = 9;
c2_virtt.it_value.tv_usec = 999999;
setitimer(ITIMER_VIRTUAL, &c2_virtt, NULL);
c2_proft.it_interval.tv_sec = 9;
c2_proft.it_interval.tv_usec = 999999;
c2_proft.it_value.tv_sec = 9;
c2_proft.it_value.tv_usec = 999999;
setitimer(ITIMER_PROF, &c2_proft, NULL);
fib = fibonnacci(atoi(argv[2]));
getitimer(ITIMER_REAL, &c2_realt);
printf("Child2 fib = %ld\nChild2 Real Time = %2ldSec: %03ldMsec\n",
fib, c2_real_secs+9-c2_realt.it_value.tv_sec,
(999999-c2_realt.it_value.tv_usec)/1000);
getitimer(ITIMER_VIRTUAL, &c2_virtt);
printf("Child2 Virtual Time = %2ldSec: %03ldMsec\n",
c2_virtual_secs+9-c2_virtt.it_value.tv_sec,
(999999-c2_virtt.it_value.tv_usec)/1000);
getitimer(ITIMER_PROF, &c2_proft);
printf("Child2 Prof Time = %2ldSec: %03ldMsec\n\n",
c2_prof_secs+9-c2_proft.it_value.tv_sec,
(999999-c2_proft.it_value.tv_usec)/1000);
} else {
// 父进程设置3种定时处理入口
signal(SIGALRM, psig_real);
signal(SIGVTALRM, psig_virtual);
signal(SIGPROF, psig_prof);
// 初始化父进程3种时间定时器
p_realt.it_interval.tv_sec = 9;
p_realt.it_interval.tv_usec = 999999;
p_realt.it_value.tv_sec = 9;
p_realt.it_value.tv_usec = 999999;
setitimer(ITIMER_REAL, &p_realt, NULL);
p_virtt.it_interval.tv_sec = 9;
p_virtt.it_interval.tv_usec = 999999;
p_virtt.it_value.tv_sec = 9;
p_virtt.it_value.tv_usec = 999999;
setitimer(ITIMER_VIRTUAL, &p_virtt, NULL);
p_proft.it_interval.tv_sec = 9;
p_proft.it_interval.tv_usec = 999999;
p_proft.it_value.tv_sec = 9;
p_proft.it_value.tv_usec = 999999;
setitimer(ITIMER_PROF, &p_proft, NULL);
fib = fibonnacci(atoi(argv[3]));
getitimer(ITIMER_REAL, &p_realt);
printf("Parent fib = %ld\nParent Real Time = %2ldSec: %03ldMsec\n",
fib, p_real_secs+9-p_realt.it_value.tv_sec,
(999999-p_realt.it_value.tv_usec)/1000);
getitimer(ITIMER_VIRTUAL, &p_virtt);
printf("Parent Virtual Time = %2ldSec: %03ldMsec\n",
p_virtual_secs+9-p_virtt.it_value.tv_sec,
(999999-p_virtt.it_value.tv_usec)/1000);
getitimer(ITIMER_PROF, &p_proft);
printf("Parent Prof Time = %2ldSec: %03ldMsec\n\n",
p_prof_secs+9-p_proft.it_value.tv_sec,
(999999-p_proft.it_value.tv_usec)/1000);
waitpid(0, &status, 0);
waitpid(0, &status, 0);
}
return 0;
}
static void psig_real(int non) {
p_real_secs += 10;
}
static void psig_virtual(int non) {
p_virtual_secs += 10;
}
static void psig_prof(int non) {
p_prof_secs += 10;
}
static void c1sig_real(int non) {
c1_real_secs += 10;
}
static void c1sig_virtual(int non) {
c1_virtual_secs += 10;
}
static void c1sig_prof(int non) {
c1_prof_secs += 10;
}
static void c2sig_real(int non) {
c2_real_secs += 10;
}
static void c2sig_virtual(int non) {
c2_virtual_secs += 10;
}
static void c2sig_prof(int non) {
c2_prof_secs += 10;
}
long unsigned int fibonnacci(unsigned int n) {
if (n < 3) return 1;
return fibonnacci(n-1)+fibonnacci(n-2);
}
四、运行结果
如有错误请指正