NAME:  getitimer, setitimer - Crude itimer implementation 

SYNOPSIS
       #include <sys/time.h>
       #include <sys/itimer.h>

       struct timeval {
         long tv_sec;
         long tv_usec;
       };

       struct itimerval {
           struct timeval it_interval;    /* next value when reset */
           struct timeval it_value;    /* current expiration value */
        };

        int getitimer(const unsigned which, struct itimerval *it);
        int setitimer(const unsigned which, const struct itimerval *it,
                                    struct itimerval *oit);

     MACROS
      _itOneIsSet(const struct itimerval it)
      _itIntvlIsSet(const struct itimerval it)
      _itClear(struct itimerval it) 		/* Zero struct itimerval it */
      _itSetValue(const struct itimerval it,    /* Set it value to micro-seconds */
              const unsigned long micro-seconds)
      _itSetInterval(const struct itimerval it, /* Set it to micro-seconds */
              const unsigned long micro-seconds)
      _tv2mSec(struct timeval tv)  - Convert 'struct timeval' to 
                                       micro-seconds (32-bit signed)
      _itimeradd(const struct timeval *a, const struct timeval *b, struct timeval *result)
      _itimersub(const struct timeval *a, const struct timeval *b, struct timeval *result)

DESCRIPTION
  o getitimer(): 
    Get Remaining Time on Timer 'which' and store to the adress 'it' points to.

  ERRORS
        EFAULT - Argument no valid pointer to struct itimerval 
        EINVAL - Invalid timer selection argument
        ENOSYS - Updating functionality not (yet) implemented on this system


  o setitimer(): 
    Set the interrupt timer 'which' with values pointed to by 'it'. Store old
    values to the adress pointed to by 'oit'. Resetting with 'it.value' 0 stops
    all timing. Use the _itClear macro to zero 'it' before calling setitimer().
    To prevent event losses, always stop timings before resetting to another
    value.

  ERRORS
        EFAULT - Argument no valid pointer to struct itimerval 
        EINVAL - Invalid timer selection argument
        ENOSYS - Functionality not implemented on this system

IMPLEMENTATION
     ITIMER_VIRTUAL  and ITIMER_PROF are not really implemented; they just measure real 
     time only, Fix me !
     We start (or stop) OS/2 asynchronous timers 'which' once (single shot timer) 
     or within specified interval (interval timer), respectively, they post an event 
     semaphore. Upon notification the asynchronously waiting alarm thread generates 
     SIGALARM. The hardware constant _IT_TIMING_GRANULARITY is subtracted automatically.

     Both threads run at foreground server priority as other processes or 
     threads may depend on the service's real time abilities. Stopping has 
     higher priority than waiting; no unwanted alarm will be generated.

    A (positive) side effect is that any unwanted intermediate timer events 
    will be lost. If you experiences other notifications of event losses (can 
    happen with extremely heavy system load) you may want to add 

	'SET PRIORITY = ABSOLUTE' (config.sys)

    and/or to elevate the timing priority even further to a time critical level. 
    Be warned that in this case other threads will have to wait.

AUTHORS
	(C) Arnd Hanses, Alexander Mai.  The code may be used for any purpose,
        provided we will be exempt of ony liability and this disclaimer is not
        removed.
           Though it's released into PD we would appreciate to see any 
           enhancements/fixes that you will apply.
           Thanks in advance!

HINTS
      o compile/link _everything_ with -Zmt
          (you should do for _all_ your projects)

      o Link with -Zbsd-signals !
        (well, probably necessary.  Check for sigaction() in the code and 
         read the appropriate EMX docs)

      o Check that the source is using sigaction() exclusively and do not 
         mix signal() with it or watch out to link with -Zbsd-signals !

      o If the calling thread is thread #1 (of the current process)
         it will work as expected, a SIGALRM will be raised there.
         If not, the sigaction()-defined handler will be called, i.e.
         the handler will be called from a different (the itimer-)thread.
  
        Note that for X11 software it is currently necessary to make
        all X calls from within a single thread. Since this is usually
        thread #1, make sure this is also calling setitimer().

     o The source may not be thread-safe itself yet! Test it and report bugs or 
        success.

     o You may want to redefine the granularity constant according to your
        hardware and recompile the library. Prototype:

     #define _IT_TIMING_GRANULARITY 1000UL /* (micro-seconds; a hardware constant) */

<Arnd.H.Hanses@rz.ruhr-uni-bochum.de>
