Summary:
This chapter discusses timer and timer service; This paper introduces the principle of code hardware timer and the hardware timer in PC based on Intel x86; Explained the CPU operation and interrupt processing; It refers to the system call, library function and timer service command related to timer in Linux; This paper discusses the process interval timer and the signal generated by the timer, and demonstrates the process interval timer through an example. The purpose of programming project is to realize timer, timer interrupt and interval timer in a multi task processing system. Multitasking system runs as a Linux process, which is a virtual CPU for concurrent tasks in Linux process. The real-time mode interval timer of Linux process is designed to regularly generate SIGALRM signal and act as timer interrupt of virtual CPU. The virtual CPU uses SIGALRM signal catcher as interrupt handler of timer. This project allows the read process to realize task interval limit timer through timer queue, and also allows the read process to realize critical area using Linux signal mask, To prevent race conditions between tasks and interrupt handlers.
hardware timer
Timer is a hardware device composed of clock source and programmable counter. The clock source is usually a crystal oscillator, which will generate periodic electrical signals to drive the counter at a precise frequency. The counter is programmed with a countdown value and each clock signal is decremented by 1. When the count is reduced to 0, the counter generates a timer interrupt to the CPU, reloads the count value into the counter, and repeats the countdown. The counter cycle is called timer scale and is the basic timing unit of the system.
Personal computer timer
(Intel x86 based personal computer)
- Real time clock (RTC): the RTC is powered by a small backup battery. Even when the personal computer is turned off, it can run continuously. It is used to provide time and date information in real time. When Linux starts, it uses RTC to update the system time variable to be consistent with the current time. In all Unix like systems, the time variable is a long integer containing the number of seconds since January 1, 1970.
- Programmable interval timer (PIT):PIT is a hardware timer separated from CPU. It can be programmed to provide a timer scale in milliseconds. Among all I/O devices, pit can interrupt IRQ0 with the highest priority. Pit timer interrupt is handled by the timer interrupt handler of Linux kernel, which provides basic timing units for system operation, such as process scheduling, process interval timer and many other timing events.
- Local timer in multi-core CPU: in multi-core CPU, each core is an independent processor. It has its own local timer driven by CPU clock.
- High resolution timer: most computers have a timestamp timer (TSC) driven by the system clock. Its contents can be read through the 64 bit TSC register. Because the clock frequency of different system motherboards may be different, TSC is not suitable for real-time equipment, but it provides nanosecond timer resolution. Some high-end personal computers may also be equipped with dedicated high-speed timers to provide nanosecond timer resolution.
CPU operation
Each CPU has a program counter (PC), also known as instruction pointer (IP), a flag or status register (SR), a stack pointer (SP) and several general registers. When the PC points to the next instruction to be executed in memory, the SR contains the current state of the CPU, such as operation mode, interrupt mask and condition code, and SP points to the top of the current stack. The stack is an area of memory used by the CPU for special operations (push\pop calls and returns). CPU operations can be modeled through infinite loops.
Interrupt processing
Interrupts from external devices, such as timers, are fed to predefined input lines of the interrupt controller, the interrupt inputs are sorted by priority, and the interrupt with the highest priority is routed to the CPU as an interrupt request (IRQ). At the end of each instruction execution, if the CPU is not in the state of accepting interrupt, that is, the interrupt is masked in the CPU's status register. It will ignore the interrupt request, make it in the suspended state, and continue to execute the next instruction. If the CPU is in the interrupt acceptance state, that is, the interrupt is not masked, the CPU will transfer its normal execution sequence for interrupt processing. For each interrupt, the interrupt controller can be programmed to generate a unique number called interrupt vector to identify the interrupt source. After obtaining the interrupt vector number, the CPU uses it as the entry index in the interrupt vector table in memory. The entry contains a pointer to the entry address of the interrupt handler to actually process the interrupt. When the interrupt processing ends, the CPU resumes the normal execution of the instruction.
Clock service function
The clock service can be called through system calls, library functions and user level commands
- gettimeofday-settimeofday
The gettimeofday() function returns the current time (seconds and microseconds of the current second). The settimeoffday() function is used to set the current time. In Unix/Linux, time represents the number of seconds that have elapsed since 00:00:00 on January 1, 1970. It can be converted to calendar form through the library function CTime (& time).
gettimeofday() function practice:
#include <sys/time.h> int gettimeofday(struct tim *tv, struct timezone *tz); int settimeofday(const struct tim *tv , const struct timezone *tz); struct timeval{ time_t tv_sec; suseconds_t tv_usec; };
code:
#include <sys/time.h> #include <unistd.h> main() { struct timeval tv; gettimeofday(&tv,NULL); printf("tv_sec : %d\n", tv.tv_sec); printf("tv_usec : %d\n", tv.tv_usec); }
Practice of the settimeoffday() function
The code is as follows:
#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=settimeofday(&t,NULL); if(!r) { printf("settimeofday() failed\n"); exit(1); } gettimeofday(&t,NULL); printf("sec=%ld usec=%ld\n",t.tv_sec,t.tv_usec); printf("%s",ctime(&t.tv_sec)); }
- time system call
Returns the current time in seconds. If the parameter t is not NULL, the time is also stored in the memory pointed to by T. The time system call has some limitations. It only provides the resolution in seconds, not microseconds.
#include <time.h> time_t time(time_t *t);
time() function practice
#include <stdio.h> #include <time.h> int main() { time_t seconds; seconds = time(NULL); printf("%ld seconds has passed since 1970.1.1\n",seconds); printf("%ld hours has been passed since 1970.1.1\n",seconds/3600); return(0); }
- times system call
It can be used to obtain the specific execution time of a process. If the parameter t is not NULL, the time is also stored in the memory pointed to by T, which stores the process time in struct tms buf
clock_t times(struct tms *buf);
It can be used to obtain the specific execution time of a process. It stores the process time in struct tms buf
struct tms { clock_t tms_utime; clock_t tms_stime; clock_t tms_cutime; clock_t tms_cstime; };
Of which:
tms_utime Is the time the program runs in user mode. tms_stime Is the time the program runs in kernel mode. tms_cutime Is the time that all subprocesses of the program run in user mode. tms_cstime It refers to the time that all subprocesses of the program run in kernel mode.
- time and data commands
Date: print or set the system date and time.
Time: reports the execution time and total time of the process in user mode and system mode.
Hwlock: query and set the hardware clock (RTC), which can also be completed through BIOS.
Interval timer
Linux provides three different types of interval timers for each process, which can be used as a virtual clock for process timing. The interval timer is created by the settimer() system call. The getitimer() system call returns the status of the interval timer.
int getitimer(int which, struct itimerval *curr_value);
int setitimer(int which, const struct itimerval *new_value, struct itimerval *old_value);
There are three types of interval timers:
(1)ITIMER_REAL: real-time reduction, generating a SIGALRM (14) signal when it expires.
(2)ITIMER_VIRTUAL: it decreases only when the process is executed in user mode, and generates a SIGVTALRM (26) signal when it expires.
(3)ITIMER_PROF: decrease when the process is executing in user mode and system mode. A SIGPROF (27) signal is generated at expiration.
Practice of setitimer() function
code:
#include <signal.h> #include <stdio.h> #include <sys/time.h> int count=0; struct itimerval t; void timer_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; signal(SIGVTALRM,timer_handler); timer.it_value.tv_sec=0; timer.it_value.tv_usec=100000; timer.it_interval.tv_sec=1; timer.it_interval.tv_usec=0; setitimer(ITIMER_VIRTUAL,&timer,NULL); printf("looping:enter Control-C to terminate\n"); while(1); }
REAL mode interval timer
Interval timers in VIRTUAL and PROF modes are only valid when the process is executing. The information of this kind of timer can be saved in the PROC structure of each process.
REAL mode interval timers are different because they must be updated by the timer interrupt handler whether processes are executing or not.