data structure after timer 4 has been set.

Team-FLY

10.4 Using Multiple Timers

The potential interactions of multiple timers make their implementation more complex than that of single timers. All the times in the active array are specified relative to the start of the underlying ITIMER_REAL interval timer. Suppose that a program wants to set timer [4] for seven seconds and that two seconds have elapsed since it set timer [2] for five seconds. Use the following procedure.

  1. Find out how much time is left on the real timer. (Call gethardwaretimer .)

  2. Find the start of the real timer relative to the currently running timer by subtracting the time left on the real timer from the timer value of the running timer. (Use getrunning .)

  3. Calculate the time of the timer to be set relative to the start time by adding the relative start time from step 2 to the requested time.

Figure 10.3 on page 346 shows the timers data structure after a program sets timer 2 for five seconds (5,000,000 microseconds). Suppose that two seconds later the program sets timer [4] for seven seconds (7,000,000 microseconds). Figure 10.5 shows the timers data structure after timer [4] is set. The program calls gethardwaretimer and finds that there are three seconds left (3,000,000 microseconds) on the interval timer, so two seconds (5,000,000 - 3,000,000 microseconds) have elapsed since it set timer [2] . The program then computes the time for timer [4] relative to the start of the original setting of the real timer as nine seconds (2,000,000 + 7,000,000 microseconds).

Figure 10.5. The timers data structure after timer 4 has been set.

graphics/10fig05.gif

The running timer is the same in Figure 10.3 and Figure 10.5 because timer [4] expires after timer [2] . The program did not change the running timer designation or reset the timer in this case. Continuing the situation of Figure 10.5, suppose that a program wants to set timer [3] for one second and a call to gethardwaretimer shows that the real timer has two seconds left. Timer [3] should expire before the real timer is scheduled to expire, so the program must reset the real timer. Figure 10.6 shows the situation after the program sets timer [3] . The program resets the real timer to expire in one second and adjusts all of the other times in active . The new times are relative to the start time of timer [3] rather than to that of timer [2] (three seconds ago), so the program subtracted three seconds from each of the active times.

Figure 10.6. The timers data structure after timer [3] has been set.

graphics/10fig06.gif

Figure 10.7 shows the situation a little over a second after timer [3] was set. Timer [3] expires and timer [2] becomes the running timer. All the times are readjusted to expire relative to timer [2] .

Figure 10.7. The timers data structure after timer [3] expires.

graphics/10fig07.gif

Figure 10.8 shows the situation two seconds later. Timer [2] expires and timer [4] becomes the running timer.

Figure 10.8. The timers data structure after timer [2] expires.

graphics/10fig08.gif

10.4.1 Setting multiple timers

Modify the timerstart function and add a timerstop function to handle all of the cases of timers being set while other timers are active. At any moment, each timer is either active or inactive. An active timer cannot appear in events , but it is added to events when it expires. If any of the timers is active, exactly one of them is running . The running timer is the one that is next to expire. Its expiration time has been used in sethardwaretimer , so a signal is generated when its time expires.

How starting and stopping should affect events is an arbitrary implementation decision. The implementation outlined here removes an event corresponding to the timer to be started or stopped if one is there. This choice ensures that no timer is represented by more than one event in events , so events can be declared to be the same size as active . The bound on events simplifies the implementation.

With multiple timers active, timerhandler must update the timers data structure by subtracting active[running] from all active times. If the time becomes 0, the corresponding timer has expired and that timer number should be placed in events and made inactive. This method handles multiple timers expiring at the same time.

Section 10.3 handled the case of starting a timer when no timer is active. A similar case is the one in which the timer to be started is already active but all other timers are inactive.

Suppose some other timer is the running timer when a timer is started. If the timer to be started expires after the running timer, only one entry in the timers data structure needs to be modified. However, if starting this timer causes it to expire before the currently running timer, the interval timer must be reset. The entries in the active array must also be adjusted relative to the starting time of the new running timer. To make the adjustment, decrement the active times by the time that the currently running timer has been active ( runtime ). Use gethardwaretimer to find the remaining time on the interval timer and calculate runtime = active[running] - remaining .

When the running timer changes, take the following actions.

  1. Remove the new timer from events if it is there.

  2. Adjust all active times by runtime .

  3. Set a new running timer.

  4. Start the interval timer by calling sethardwaretimer .

The case in which the timer to be started is the running timer can be treated either as a special case of the above or as a separate case.

A call to timerstop for a timer that is not active just removes the timer from events . If the timer was active but not running , set it to be inactive. The interesting case is that of stopping the running timer. This case is similar to the case of starting a timer that becomes the running timer because the timers data structure needs to be updated by runtime and a new running timer has to be selected.

In this part, the program should handle all combinations of starting and stopping timers as well as removing events from the event list. Enhance the timerstart and timerhandler functions appropriately and write the functions removetop and timerstop , which were not needed before. Insert appropriate calls to show .

Modify timermain so that it interprets a negative interval as a command to stop the timer. Instead of waiting for an event in the main loop, remove and display all events without blocking before waiting for additional input.

Exercise 10.3

What happens if scanf is used for standard input in this version of timermain ?

Answer:

Neither scanf or sscanf are guaranteed to interact correctly with signals. The scanf function may indicate end-of-file when a signal is caught by the process. Use the readline function from Program 4.1 on page 95. This function detects end-of-file correctly and is not affected by signals. You can then use sscanf to parse the input line (after blocking the signals).

Exercise 10.4

Why can the single timer of Section 10.3 use scanf without a problem?

Answer:

The program waits for the signal to be caught before calling scanf .

10.4.2 Testing with multiple timers

Even code instrumented by show is difficult to test systematically, since the action of the program depends on the speed of the input typing. One approach to this problem is to use a driver, testtime , to generate the input for the program. Program 10.3 shows the testtime program. It must be linked to the hardwaretimer object.

As with any filter, testtime reads from standard input and writes to standard output. The input consists of lines containing three integers, n , m and p . The filter reads in these three integers, waits n microseconds, and then outputs m and p on a single line. If m < , testtime exits after waiting n microseconds. The testtime program ignores any characters on the line after the three integers, so a user can add comments to the end of each input line.

Example 10.5

Suppose testtime receives the following input.

 1000000  2  5000000 Timer 2 expires at time 6 2000000  4  7000000 Timer 4 expires at time 10 1000000  3  1000000 Timer 1 preempts 2 to expire at time 5 

The testtime program waits one second and outputs the following line.

 2 5000000 

The program then waits two more seconds and outputs the following line.

 4 7000000 

The program then waits one second and outputs the following line.

 3 1000000 
Exercise 10.6

Suppose the three lines in Example 10.5 are in the file timer.input and you execute the following command. What happens?

 testtime < timer.input  timermain 

Answer:

After getting the third line of the file at time 4 seconds, timermain detects end-of-file when testtime exits. This occurs before any timers expire. We can fix this problem by adding the following line to timer.input .

 7000000 -1 1000000 Everything done 6 units from now 
Program 10.3 testtime.c

The program testtime .

 #include <stdio.h> #include <stdlib.h> #include <sys/time.h> #include "hardwaretimer.h" static int timerexpired = 0; static void myalarm() {    timerexpired = 1; } int main(int argc, char *argv[]) {   /* Test the hardware timer and prototype */    long interval;    int n1;    int n2;    if (argc != 1) {       fprintf(stderr, "Usage: %s\n", argv[0]);       return 1;    }    catchinterrupt(myalarm);    for( ; ; ){       if (scanf("%ld%d%d%*[^\n]", &interval, &n1, &n2) == EOF)          break;       if (interval <= 0)          break;       blockinterrupt();       sethardwaretimer(interval);       while (!timerexpired)          waitforinterrupt();       timerexpired = 0;       if (n1 < 0)          break;       printf("%d %d\n", n1, n2);       fflush(stdout);       fprintf(stderr, "%d %d\n", n1, n2);    }    return 0; } 

If the 4-line file described in Example 10.5 and Exercise 10.6 is used as illustrated , the command causes timer [2] to start 1 second after execution begins and to expire five seconds later (at time 6). Two seconds later (at time 3), timer [4] starts and expires in seven seconds (at time 10). One second later (at time 4), timer [3] is set to expire in one second (at time 5). This is exactly the situation illustrated in Figure 10.6 on page 358.

Figure 10.9 displays the output generated for this input by Program 10.1, using an appropriately instrumented implementation of virtualtimers . Figure 10.10 displays the corresponding output generated by Program 10.2.

Figure 10.9 The output generated by Program 10.1.
 ****   0.0001: Initialize U(-1,-0.000) A: (0E) ****   0.9975: Start Enter 2 5000000 U(-1,-0.000) A: (0E) ****   0.9976: None Running 2 5000000 B(-1,-0.000) A: (0E) ****   0.9977: Start Exit 2 5000000 U(2,5.000) A:(2,5.000) (0E) ****   3.0072: Start Enter 4 7000000 U(2,5.000) A:(2,5.000) (0E) ****   3.0073: Start Another Running 4 2 B(2,5.000) A:(2,5.000) (0E) ****   3.0074: Start Running Used 4 2009705 B(2,5.000) A:(2,5.000) (0E) ****   3.0075: Start Running Expires First 4 B(2,5.000) A:(2,5.000) (4,9.010) (0E) ****   4.0173: Start Enter 3 1000000 U(2,5.000) A:(2,5.000) (4,9.010) (0E) ****   4.0174: Start Another Running 3 2 B(2,5.000) A:(2,5.000) (4,9.010) (0E) ****   4.0175: Start Running Used 3 3019778 B(2,5.000) A:(2,5.000) (4,9.010) (0E) ****   4.0176: Start This Expires First 3 B(3,1.000) A:(2,1.980) (3,1.000) (4,5.990) (0E) ****   5.0269: Handler Start 3 1000000 B(3,1.000) A:(2,1.980) (3,1.000) (4,5.990) (0E) ****   5.0271: Handler Setting Hardware 2 980222 B(2,0.980) A:(2,0.980) (4,4.990) (1E 3) ****   5.0272: Handler Exit B(2,0.980) A:(2,0.980) (4,4.990) (1E 3) ****   6.0170: Handler Start 2 980222 B(2,0.980) A:(2,0.980) (4,4.990) (1E 3) ****   6.0172: Handler Setting Hardware 4 4009705 B(4,4.010) A:(4,4.010) (2E 3 2) ****   6.0173: Handler Exit B(4,4.010) A:(4,4.010) (2E 3 2) ****  10.0369: Handler Start 4 4009705 B(4,4.010) A:(4,4.010) (2E 3 2) ****  10.0371: Handler Setting Hardware 4 B(4,-0.000) A: (3E 3 2 4) ****  10.0372: Handler Exit B(4,-0.000) A: (3E 3 2 4) 
Figure 10.10. The output generated by Program 10.2.

graphics/10fig10.jpg

Team-FLY


Unix Systems Programming
UNIX Systems Programming: Communication, Concurrency and Threads
ISBN: 0130424110
EAN: 2147483647
Year: 2003
Pages: 274

flylib.com © 2008-2017.
If you may any questions please contact us: flylib@qtcs.net