This example overrides the Title:implementing software timers example of Don Libes
Why this feature is needed because most computer software clock systems usually have only one clock to trigger an interrupt. When running multiple tasks, we would like to have multiple timers with clock tracking concurrency so that the correct time overlap can be generated and the operating system does so.
This example is implemented to implement any number of timer functions using a timer under Linux.
First we need some data types for describing 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; Define the temporal type #define very_long_time ... Maximum time length struct timer {int inuse; Whether the clock is available time time; Timing Time Length Char *event; timeout} timers[max_timers]; /* */
Each timer is described by this data structure, the first member to describe whether the clock is in use, the second member is the timer time, the third member is a pointer, the *event initialization should be 0, when he was set to 1, we know that the timer has timed out, The tasks associated with him can be performed.
Next is the initialization of the timer array, where each clock InUse member is set to False to indicate that the clock is not available.
void Timers_init () {struct timer *t; for (t=timers;t<&timers[max_timers];t++) t->inuse = FALSE;}
Now is the structure implementation section.
The first written timer_undeclare this function, which is opposite to the timer_declare in the back. The main function is to clear a timer.
There are many ways to save the timer's timing record. Machines that do not have complex clock hardware typically process an interrupt handler in each clock cycle. The software then obtains the system time in the handler and then determines whether the timer timeout is set.
Many smarter machines can set timing time in hardware and trigger a hardware interrupt once time expires. This also applies with software interrupts.
They record the current system time by defining a time_now, and volatile tells the machine to take value from the register every time, preventing the data from being optimized by the system.
volatile Time Time_now
Next, define a series of data to record Timer_next means the timer we want to time next. Time_timer_set Save the last acquired system time.
structTimer *timer_next = NULL;/*Timer We expect to run down next*/Time Time_timer_set; /*time when physical timer is set*///Cancel a timervoidTimer_undeclare (structTimer *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 ();}
The Timer_undeclare function cancels a timer. It is important to disable the interrupt first, because the clock data structure is shared among the processes and can be modified in other interrupts, and in order to prevent unnecessary errors, this cancellation operation should be an atomic operation. Let's start by checking if this clock is invalid. If valid, the InUse is set to invalidate it. If the timer we want to cancel is exactly the next timer to wait. Then we need to reassign the next timer that we expect to wait. Until then all timers have to update the time that the previous timer has gone.
Next we see Timers_update (time_t ti) function
//Update Timer table timevoidtimers_update (time_t time) {Static structTimer timer_last={0, {}, NULL}; Timer_last.time.tv_sec=Ten; structTimer *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 is to update all valid timers for a long time while timer_next points to a timer with the shortest delay time. If there is no timer, the timer_next is set to null.
Timer_declare Adding a Timer
structTimer * Timer_declare (Time *ti,Char*Event) {structTimer *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 (); returnt;}
First find an available timer table entry, set the relevant parameters.
Next, if the Timer_next is empty, then the Timer table entry does not require a timer, then we direct the Timer_next point to the new timer, start timing.
If the new timer requires a delay longer than the time remaining for the timer that is currently being delayed, the timer table is updated and the timer currently joined is timed.
in the after the current timer event is processed, the inuse of the newly added timer is set to 1.
Next is the timer interrupt handler function
//Timer Interrupt handler functionvoidTimer_interrupt_hander (intSigno) {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 to do is to update the timer table, and then set the Time_timer_set to the current system time, continue to the next timer event, until all the timer has been processed.
The next few are Linux system related functions
//Fail timer Interruptvoiddisable_interrupts () {sigset_t New_mask;sigemptyset (&new_mask); Sigaddset (&new_mask,sigalrm);if(Sigprocmask (Sig_block,&new_mask,null) <0) perror ("Sig_block Error");}//Enable timer interruptvoidenable_interrupts () {sigset_t New_mask;sigemptyset (&new_mask); Sigaddset (&new_mask,sigalrm);if(Sigprocmask (Sig_unblock,&new_mask,null) <0) perror ("Sig_unblock Error");}//turn on a timer to workvoidStart_physical_timer (time*Time ) {if(Signal (sigalrm,timer_interrupt_hander) = =sig_err) perror ("Signal Error"); structitimerval new_value;sigset_t Zero_mask;sigemptyset (&zero_mask); New_value.it_value.tv_sec=time->tv_sec;new_value.it_value.tv_usec=time->tv_usec;new_value.it_interval.tv_sec=0; New_value.it_interval.tv_usec=0; Setitimer (Itimer_real,&new_value,null); Sigsuspend (&zero_mask);}
Main function Test Section
#include <stdio.h>#include<signal.h>#include"multtime.h"#include<stdlib.h>#include<unistd.h>intMain () {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); }
Experimental results:
21interrupt_handerinterrupt_handerinterrupt_hander
I am a beginner of Linux is a rookie, with their own understanding of the written, to study further after further improvement.
Linux uses a timer implementation to set any number of timers