home *** CD-ROM | disk | FTP | other *** search
/ Amiga Developer CD 1.2 / amidev_cd_12.iso / reference / amiga_mail_vol2 / archives / plain / nd91.lzh / Interval / Interval.txt < prev   
Encoding:
Text File  |  1991-11-18  |  12.4 KB  |  345 lines

  1. (c)  Copyright 1991 Commodore-Amiga, Inc.   All rights reserved.
  2. The information contained herein is subject to change without notice,
  3. and is provided "as is" without warranty of any kind, either expressed
  4. or implied.  The entire risk as to the use of this information is
  5. assumed by the user.
  6.  
  7. Keeping Time--Interval Timers in Amiga UNIX
  8.  
  9. By David Miller
  10.  
  11.  
  12.  
  13. The Sleep() function
  14.  
  15. When you want your program to pause for a number of seconds then continue,
  16. you will typically use the sleep(3) function (the notation NAME(SECTION#)
  17. refers to the manual page NAME in the SECTION# chapter of the UNIX Reference
  18. Manuals; section 1 is commands, section 2 is system calls, and section 3 is
  19. library functions).  There is also a sleep(1) program which provides the same
  20. function to shell scripts.  For example:
  21.  
  22. In C:
  23.         main()
  24.         {
  25.                 printf("Hello world!\n");
  26.                 sleep(5);
  27.         }
  28.  
  29. Shell:
  30. #!/usr/bin/sh
  31.  
  32. echo "Hello world!"
  33. sleep 5
  34.  
  35.  
  36. The following example is an implementation of the sleep(3) function.
  37.  
  38.  
  39. Example 1: SLEEP() Using ALARM()
  40.  
  41.      1  # include       <signal.h>
  42.      2  static void trap ()
  43.      3  {
  44.      4  }
  45.      5  unsigned sleep ( unsigned duration )
  46.      6  {
  47.      7          void            (*oldsig)();
  48.      8          unsigned        oldtime;
  49.      9          oldsig = signal(SIGALRM, trap);
  50.     10          oldtime = alarm(0);
  51.     11          if (oldtime && oldtime < duration)
  52.     12                  alarm(oldtime);
  53.     13          else
  54.     14                  alarm(duration);
  55.     15          pause();
  56.     16          signal(SIGALRM, oldsig);
  57.     17          if (oldtime > duration)
  58.     18                  alarm(oldtime - duration);
  59.     19          if (oldtime && oldtime < duration)
  60.     20                  return(duration - oldtime);
  61.     21          else
  62.     22                  return 0;
  63.     23  }
  64.  
  65.  
  66. Line            Explanation
  67.  
  68.    1    The file signal.h defines the parameters for the signal(2) function.
  69.  
  70.  2-4    trap() is the simple signal handler that just sets a flag that
  71.         another piece of code will examine.
  72.  
  73.    5    Define the sleep() function.
  74.  
  75.  6-8    oldsig is a variable that will be used to save the previous state of
  76.         the signal handler; oldtime will be used to save the state of the alarm clock.
  77.  
  78.    9    Establish trap() as the current signal handler for the alarm signal.
  79.         The previous handler is saved in oldsig.
  80.  
  81.   10    Clear the alarm clock, saving the current state.
  82.  
  83. 11-14   If the previous setting of alarm was sooner than duration, use the
  84.         old value, otherwise use duration to set the alarm.
  85.  
  86.    15   Pause the process until the alarm goes off.
  87.  
  88.    16   Restore the old signal handler.
  89.  
  90. 17-18   If the old alarm setting was later than duration, reset the alarm
  91.         with the difference between duration and oldtime (the time remaining until
  92.         the previous alarm).
  93.  
  94. 19-22   If an existing alarm is making sleep return early, return the time
  95.         remaining on the requested sleep.
  96.  
  97.  
  98.  
  99. To schedule its ``wake up'' time, sleep(3) uses the alarm(2) system call.
  100. The alarm(2) system call asks the OS to deliver a signal (basically a
  101. software interrupt) in some number of seconds according to the system clock.
  102. However, setting an alarm for 2 seconds does not mean that you will receive
  103. an alarm signal in exactly two seconds.
  104.  
  105. The OS processes alarm requests once every second.  Each time an alarm
  106. request is processed, the number of seconds remaining for that alarm is
  107. decremented by one.  When the number of seconds remaining reaches zero, the
  108. OS delivers a signal to the process.  Given this, if a process places a 1
  109. second alarm request 1 microsecond before the OS does its alarm processing,
  110. the signal will arrive in 1 microsecond, not in 1 second.  An alarm set for N
  111. seconds actually means:
  112.  
  113.         deliver a signal after N-1 seconds, but before N seconds.
  114.  
  115. If you'd like to see for yourself, try running this shell script:
  116.  
  117. $ for i in 1 2 3 4 5 6 7 8 9 10
  118. > do
  119. >       time sleep 2
  120. > done
  121.  
  122.  
  123. How many times did the process actually take more than 2 seconds?  If you try
  124. it with both the Korn shell, ksh(1), and the System V shell, sh(1), you'll
  125. find that under ksh(1) it takes about 1.2 seconds and under sh(1) it takes
  126. about 1.8 seconds (There is a difference because sh(1) counts the time
  127. required to start the sleep process whereas ksh(1) only counts the actual
  128. running time).  The sleep(1) program rarely, if ever, actually sleeps for 2
  129. seconds.
  130.  
  131. If you are writing a daemon that checks for some event every 5 minutes, or if
  132. you want to pause the output to give the user a chance to read it, alarm's 1
  133. second granularity is fine.  But what about that daemon that needs to wake up
  134. every second?  Waking up after 1 microsecond could cause the process to run
  135. almost continuously.  For any sort of realtime processing, one second is a
  136. very long time.  So how do you sleep for less than one second reliably?
  137.  
  138. The answer is do not use an alarm, use an interval timer.
  139.  
  140.  
  141. Interval Timers
  142.  
  143. Each interval timer has a resolution of 1 tick of the system's clock, or 1
  144. microsecond (whichever is larger).  Additionally, you can configure an
  145. interval timer to automatically restart itself.  The system provides each
  146. process with three independent interval timers:
  147.  
  148. ITIMER_REAL    This timer will count down in real time.  That is, this timer
  149.     will continue to run when your process is waiting for the OS to perform a
  150.     system call, or when the OS preempts your process.  When the timer expires,
  151.     the OS will deliver a SIGALARM signal.
  152.  
  153.  
  154. ITIMER_VIRTUAL This timer counts down only when your process is running.  If
  155.     your process makes a system call, or is preempted, this timer will stop
  156.     counting.  The timer will resume when your process resumes execution.  When
  157.     this timer reaches zero, the process will receive a SIGVTALRM signal.
  158.  
  159.     Possible uses for this timer include checkpointing (saving data after some
  160.     period of execution) and multithreading.  The virtual timer is more
  161.     desireable for these applications since it counts only when the process is
  162.     running; there is no reason to perform a checkpoint or switch threads if the
  163.     process has been idle.
  164.  
  165.  
  166. ITIMER_PROF    This timer will stop counting any time your process is
  167.     preempted by the OS, but will not stop when the process is waiting for a
  168.     system call to return.  When it expires the OS generates a SIGPROF signal.
  169.  
  170.     This timer is designed to be used for execution profiling by interpreters.
  171.     By having a profiling timer send a signal every second, or fraction of a
  172.     second, and examining the current position in the interpreted code, the
  173.     process can determine where the most execution time is being spent.
  174.  
  175. All three timers operate on the following structure:
  176.  
  177.      struct itimerval
  178.      {
  179.              struct timeval it_interval;
  180.              struct timeval it_value;
  181.      }
  182.  
  183. The timeval structure looks like this:
  184.  
  185.        struct timeval
  186.        {
  187.              long tv_sec;
  188.              long tv_usec;
  189.        }
  190.  
  191. Both of these structures are defined in the <sys/time.h> include file.
  192.  
  193. Note that System V Release 4.0 does not guarantee that these are the only
  194. members of these structures, nor that they will occur in this order.  You
  195. must initialize the members individually.  This can be annoying and tedious,
  196. but it allows the structure to be expanded in future releases.
  197.  
  198. You set and examine timers using these two functions:
  199.  
  200.     int getitimer(int which, struct itimerval *myvalue)
  201.  
  202. places the current timer setting into myvalue
  203.  
  204.     int setitimer(int which, struct itimerval *myvalue, struct itimerval *myovalue);
  205.  
  206. sets the timer.  It gets the new time from myvalue and places the previous
  207. setting in myovalue.
  208.  
  209. Now, let us take a look at the sleep function again.  The code in example 2
  210. creates a new version of sleep that will sleep an exact number of seconds.
  211.  
  212. Example 2: SLEEP() Using an Interval Timer
  213.  
  214.      1  # include       <signal.h>
  215.      2  # include       <sys/time.h>
  216.      3  static void trap ()
  217.      4  {
  218.      5  }
  219.      6  unsigned mysleep ( unsigned duration )
  220.      7  {
  221.      8         void                    (*oldsig)();
  222.      9         struct itimerval        oldtime;
  223.     10         struct itimerval        newtime;
  224.     11         oldsig = signal(SIGALRM, trap);
  225.     12         getitimer(ITIMER_REAL, &oldtime);
  226.     13         if (oldtime.it_value.tv_sec == 0
  227.                         && oldtime.it_value.tv_usec == 0
  228.                         || oldtime.it_value.tv_sec >= duration)
  229.     14         {
  230.     15                 newtime.it_interval.tv_sec = 0;
  231.     16                 newtime.it_interval.tv_usec = 0;
  232.     17                 newtime.it_value.tv_sec = duration;
  233.     18                 newtime.it_value.tv_usec = 0;
  234.     19                 setitimer(ITIMER_REAL, &newtime, NULL);
  235.     20         }
  236.     21         pause();
  237.     22         signal(SIGALRM, oldsig);
  238.     23         if (oldtime.it_value.tv_sec > duration)
  239.     24         {
  240.     25                 oldtime.it_value.tv_sec -= duration;
  241.     26                 setitimer(ITIMER_REAL, &newtime, NULL);
  242.     27         }
  243.     28         if (oldtime && oldtime < n)
  244.     29                 return(n - oldtime);
  245.     30         else
  246.     31                 return 0;
  247.     32  }
  248.  
  249.  
  250.  
  251. Line        Explanation
  252.  
  253.  1-2    The file signal.h defines the parameters of the signal(2) function.
  254.         The file <sys/time.h> defines ITIMER_REAL and the structures used by
  255.         getitimer(3) and setitimer(3).
  256.  
  257.  3-5    trap() is the simple signal handler that just sets a flag that
  258.         another piece of code will examine.
  259.  
  260.  6-7    Define the mysleep() function.
  261.  
  262. 8-10    oldsig will hold the previous state of the signal handler;  oldtime
  263.         will hold the state of the timer; and newtime will be used to set the new
  264.         timer parameters.
  265.  
  266.    11   Establish trap() as the current signal handler for the alarm signal.
  267.         The previous handler is saved in oldsig.
  268.  
  269.    12   Fetch the current settings of the timer.
  270.  
  271. 13-20   If the timer was idle (both parts of it_value are zero) or it is set
  272.         to go off later than duration (it_value.tv_sec is greater than duration), set
  273.         the timer to go off in  duration seconds.
  274.  
  275.    21   pause(2) the process until the timer expires.
  276.  
  277.    22   Restore the old signal handler.
  278.  
  279. 23-27   If the old timer setting was later than duration, reset the timer
  280.         with the difference between duration and oldtime.it_value.tv_sec (the time
  281.         remaining until expiration of the previous setting).
  282.  
  283. 28-32   If an existing timer is making mysleep() return early, return the
  284.         time remaining on the requested mysleep().
  285.  
  286.  
  287. This example uses what is called a ``one-shot'' timer.  The timer goes off
  288. once, and then stops.  By supplying an interval setting, the timer becomes a
  289. clock, generating alarm signals on a regular basis.
  290.  
  291. The code fragment in Example 3 shows how to set the timer to produce a 1.5
  292. second clock that will start ``ticking'' in 1 minute.
  293.  
  294.  
  295. Example 3: Using an Interval Timer as a Clock
  296.  
  297.      1  # include       <sys/time.h>
  298.      2  ...
  299.      3          {
  300.      4                  struct itimerval        newtime;
  301.      5                  newtime.it_value.tv_sec = 60;
  302.      6                  newtime.it_value.tv_usec = 0;
  303.      7                  newtime.it_interval.tv_sec = 5;
  304.      8                  newtime.it_interval.tv_usec = 500000;
  305.      9                  setitimer(ITIMER_REAL, &newtime, 0);
  306.     10          }
  307.     11  ...
  308.  
  309.  
  310. Line        Explanation
  311.  
  312.   1     The file <sys/time.h> defines ITIMER_REAL and the structures
  313.         used by getitimer(3) and setitimer(3).
  314.  
  315.   2     Other code.
  316.  
  317.   3     Start of block.
  318.  
  319.   4     Structure newtime will hold the setting for the timer.
  320.  
  321. 5-6     Set it_value to expire in 1 minute.
  322.  
  323. 7-8     Set it_interval to reload it_value with 5 seconds and 500,000.
  324.         microseconds (one half of a second).
  325.  
  326.  9      Load the new settings into the ITIMER_REAL timer.
  327.  
  328. 10      End of block.
  329.  
  330. 11      Other code.
  331.  
  332.  
  333. When the time interval specified by it_value expires, the contents of
  334. it_interval is copied into it_value and the timer is restarted.  If the
  335. interval specified by it_interval is zero, the timer stops.  Timers can be
  336. stopped at anytime by calling setitimer(3) with the members of it_value set
  337. to zero.
  338.  
  339.  
  340. So there you have the realtime interval timer.  The other timers work exactly
  341. the same way, varying only in when the timer is running.  For more
  342. information on interval timers see UNIX System V Release 4 - Programmer's
  343. Reference Manual, published by Prentice Hall.  Next time, we'll explore
  344. context switching, multithreading, and light weight processes.
  345.