LINUX uses a timer to set any number of timers.
In this example, refer to the Don Libes Title: Implementing Software Timers example to rewrite
Why do we need this function, because most Computer Software Clock systems usually have only one clock to trigger an interruption. When running multiple tasks, we want the clock tracking concurrency of multiple timers to generate correct time overlaps. The operating system does this.
In this example, a timer in Linux is used to implement any number of timers.
First, we need some data types to describe the clock data structure.
# Include <stdio. h> # include <time. h> # define TRUE 1 # define FALSE 0 # define MAX_TIMERS... maximum number of clocks typedef timerval TIME; defines the TIME type # define VERY_LONG_TIME... maximum length of TIME struct timer {int inuse; available time TIME time of the clock; scheduled TIME length char * event; time-out} timers [MAX_TIMERS];/* set of timers */
Each timer is described in this data structure. The first member is used to describe whether the clock is in use, the second member is the timer time of the timer, and the third member is a pointer, * event initialization should be 0. When it is set to 1, we know that this timer has timed out and tasks related to it can be executed.
Next is the initialization of the timer array. Here, each inuse Member of the clock is set to FALSE, indicating that the clock is unavailable.
voidtimers_init() {struct timer *t;for (t=timers;t<&timers[MAX_TIMERS];t++)t->inuse = FALSE;}
Structure implementation
The timer_undeclare function written first. This function is opposite to the timer_declare function. The main function is to clear a timer.
There are many ways to save timer records. Machines without complex clock hardware usually process an interrupt handler at every clock cycle. Then, the software obtains the system time in the processing program and determines whether the preset timer times out.
Many smart machines can set the timing time in the hardware. Once the time times out, a hardware interruption is triggered. This also applies to software interruptions.
They define a time_now to record the current system time. volatile tells the machine to set the value from the register each time to prevent data from being optimized by the system.
volatile TIME time_now
Next, define a series of data to record timer_next, which indicates the Timer we want to timer. Time_timer_set saves the last retrieved system time.
Struct timer * timer_next = NULL;/* timer we recommend CT to run down next */TIME time_timer_set; /* time when physical timer was set * // cancel a timer void timer_undeclare (struct timer * t) {disable_interrupts (); if (! T-> inuse) {enable_interrupts (); return;} t-> inuse = 0; if (t = timer_next) {if (time (& time_now) <0) perror ("time error"); timers_update (time_now-time_timer_set); if (timer_next) {start_physical_timer (& timer_next-> time); time_timer_set = time_now ;}} enable_interrupts ();}
Timer_undeclare is used to cancel a timer. First, let the interrupt expire. This is very important because the clock data structure data is shared among various processes and can be modified in other interruptions. To prevent unnecessary errors, this cancels an atomic operation. First, we can check whether the clock is invalid. If valid, set inuse to make it invalid. If the Timer we want to cancel happens to be the next timer that is expected to wait. Then we need to re-specify the next expected timer. Before that, all timers must update the time that the previous timer has elapsed.
Next we will see the timers_update (time_t ti) Function
// Update the timer table time void timers_update (time_t time) {static struct timer timer_last = {0, {}, NULL}; timer_last.time. TV _sec = 10; struct timer * t; timer_next = & timer_last; for (t = timers; t <& timers [MAX_TIMERS]; t ++) {if (t-> inuse) {if (time <t-> time. TV _sec) {t-> time. TV _sec-= time; if (t-> time. TV _sec <\ timer_next-> time. TV _sec) timer_next = t;} else {* (t-> event) = 1; t-> inuse = 0 ;}} if (! Timer_next-> inuse) timer_next = 0 ;}
This function updates all valid timers for a long time and points timer_next to a timer with the shortest latency. If no timer exists, set timer_next to null.
Timer_declare adds a timer
struct timer * timer_declare(TIME *ti,char *event){ struct timer *t; disable_interrupts(); for(t=timers;t<&timers[MAX_TIMERS];t++) { if(!t->inuse)break; } if(t==&timers[MAX_TIMERS]) { enable_interrupts(); return 0; } t->event=event; t->time.tv_sec=ti->tv_sec; t->time.tv_usec=ti->tv_usec; if(!timer_next) { if(time(&time_now)<0) perror("time() error"); time_timer_set=time_now; start_physical_timer(&((timer_next=t)->time)); }else if((ti->tv_sec+time_now)<(\ timer_next->time.tv_sec+time_timer_set)) { if(time(&time_now)<0) perror("time error"); timers_update(time_now-time_timer_set); time_timer_set=time_now; start_physical_timer(&((timer_next=t)->time)); }else { } t->inuse=1; enable_interrupts(); return t;}
First, find an available timer table item and set relevant parameters.
Next, if timer_next is null, it indicates that no timer is required for the timer table item. Then, we direct timer_next to the newly added timer to start timing.
If the new timer requires a shorter delay time than the remaining time of the timer that is currently being delayed, update the timer table and time the currently added timer.
After processing the current timer event, set inuse of the newly added timer to 1.
Next, the timer interrupt processing function.
// Void timer_interrupt_hander (int signo) {printf ("interrupt_hander \ n"); if (time (& time_now) <0) perror ("time () error "); timers_update (time_now-time_timer_set); if (timer_next) {time_timer_set = time_now; start_physical_timer (& timer_next-> time );}}
Here we print a string of characters to prove the timer time trigger. First, we need to update the timer table, then set time_timer_set to the current system time, and continue the next timer event, until all the timers are processed.
The following are functions related to LINUX.
// Void interrupt () {sigset_t new_mask; sigemptyset (& new_mask); sigaddset (& new_mask, SIGALRM); if (sigprocmask (SIG_BLOCK, & new_mask, NULL) <0) perror ("SIG_BLOCK error");} // enables the timer to interrupt void enable_interrupts () {sigset_t new_mask; sigemptyset (& new_mask); sigaddset (& new_mask, SIGALRM ); if (sigprocmask (SIG_UNBLOCK, & new_mask, NULL) <0) perror ("SIG_UNBLOCK error");} // enable a timer to work void start_physical_timer (TIME * time) {if (signal (SIGALRM, timer_interrupt_hander) = SIG_ERR) perror ("signal error"); struct itimerval new_value; sigset_t zero_mask; sigemptyset (& zero_mask ); new_value.it_value. TV _sec = time-> TV _sec; latency = time-> TV _usec; latency = 0; latency = 0; setimer (ITIMER_REAL, & new_value, NULL); sigsuspend (& zero_mask );}
Main Function Testing
#include<stdio.h>#include<signal.h>#include"multtime.h"#include<stdlib.h>#include<unistd.h>int main(){ pid_t pid; TIME time1,time2,time3; time1.tv_sec=6; time1.tv_usec=0; time2.tv_sec=4; time2.tv_usec=0; time3.tv_sec=2; time3.tv_usec=0; timer_init(); if((pid=fork())<0) { perror("fork() error"); } else if(pid==0) { printf("child 1\n"); timer_undeclare(timer_declare(&time1,0)); } else { if((pid=fork())<0) { perror("fork error"); } else if(pid==0) { printf("child 2\n"); timer_undeclare(timer_declare(&time3,0)); } else { printf("parent\n"); timer_undeclare(timer_declare(&time2,0)); } } exit(0); }
Experiment results:
parentchild 2child 1interrupt_handerinterrupt_handerinterrupt_hander
I am a beginner in LINUX, and I wrote it in my own understanding. I will improve it after further study.