| 
							- /*
 -  *                       s e m _ t i m e d w a i t
 -  *
 -  *  Function:
 -  *     Implements a version of sem_timedwait().
 -  *
 -  *  Description:
 -  *     Not all systems implement sem_timedwait(), which is a version of
 -  *     sem_wait() with a timeout. Mac OS X is one example, at least up to
 -  *     and including version 10.6 (Leopard). If such a function is needed,
 -  *     this code provides a reasonable implementation, which I think is
 -  *     compatible with the standard version, although possibly less
 -  *     efficient. It works by creating a thread that interrupts a normal
 -  *     sem_wait() call after the specified timeout.
 -  *
 -  *  Call:
 -  *
 -  *     The Linux man pages say:
 -  *
 -  *     #include <semaphore.h>
 -  *
 -  *     int sem_timedwait(sem_t *sem, const struct timespec *abs_timeout);
 -  *
 -  *     sem_timedwait() is the same as sem_wait(), except that abs_timeout 
 -  *     specifies a limit on the amount of time that the call should block if 
 -  *     the decrement cannot be immediately performed. The abs_timeout argument
 -  *     points to a structure that specifies an absolute timeout in seconds and
 -  *     nanoseconds since the Epoch (00:00:00, 1 January 1970). This structure 
 -  *     is defined as follows:
 -  *
 -  *     struct timespec {
 -  *        time_t tv_sec;      Seconds
 -  *        long   tv_nsec;     Nanoseconds [0 .. 999999999]
 -  *     };
 -  *
 -  *     If the timeout has already expired by the time of the call, and the 
 -  *     semaphore could not be locked immediately, then sem_timedwait() fails 
 -  *     with a timeout error (errno set to ETIMEDOUT).
 -  *     If the operation can be performed immediately, then sem_timedwait() 
 -  *     never fails with a timeout error, regardless of the value of abs_timeout.
 -  *     Furthermore, the validity of abs_timeout is not checked in this case.
 -  *
 -  *  Limitations:
 -  *
 -  *     The mechanism used involves sending a SIGUSR2 signal to the thread
 -  *     calling sem_timedwait(). The handler for this signal is set to a null
 -  *     routine which does nothing, and with any flags for the signal 
 -  *     (eg SA_RESTART) cleared. Note that this effective disabling of the
 -  *     SIGUSR2 signal is a side-effect of using this routine, and means it
 -  *     may not be a completely transparent plug-in replacement for a
 -  *     'normal' sig_timedwait() call. Since OS X does not declare the
 -  *     sem_timedwait() call in its standard include files, the relevant 
 -  *     declaration (shown above in the man pages extract) will probably have
 -  *     to be added to any code that uses this.
 -  *
 -  *  Compiling:
 -  *     This compiles and runs cleanly on OS X (10.6) with gcc with the
 -  *     -Wall -ansi -pedantic flags. On Linux, using -ansi causes a sweep of
 -  *     compiler complaints about the timespec structure, but it compiles
 -  *     and works fine with just -Wall -pedantic. (Since Linux provides
 -  *     sem_timedwait() anyway, this really isn't needed on Linux.) However,
 -  *     since Linux provides sem_timedwait anyway, the sem_timedwait()
 -  *     code in this file is only compiled on OS X, and is a null on other
 -  *     systems.
 -  *
 -  *  Testing:
 -  *     This file contains a test program that exercises the sem_timedwait
 -  *     code. It is compiled if the pre-processor variable TEST is defined.
 -  *     For more details, see the comments for the test routine at the end
 -  *     of the file.
 -  *
 -  *  Author: Keith Shortridge, AAO.
 -  *
 -  *  History:
 -  *      8th Sep 2009. Original version. KS.
 -  *     24th Sep 2009. Added test that the calling thread still exists before
 -  *                    trying to set the timed-out flag. KS.
 -  *      2nd Oct 2009. No longer restores the original SIGUSR2 signal handler.
 -  *                    See comments in the body of the code for more details.
 -  *                    Prototypes for now discontinued internal routines removed.
 -  *     12th Aug 2010. Added the cleanup handler, so that this code no longer
 -  *                    leaks resources if the calling thread is cancelled. KS.
 -  *     21st Sep 2011. Added copyright notice below. Modified header comments
 -  *                    to describe the use of SIGUSR2 more accurately in the 
 -  *                    light of the 2/10/09 change above. Now undefs DEBUG
 -  *                    before defining it, to avoid any possible clash. KS.
 -  *     14th Feb 2012. Tidied out a number of TABs that had got into the
 -  *                    code. KS.
 -  *      6th May 2013. Copyright notice modified to one based on the MIT licence,
 -  *                    which is more permissive than the previous notice. KS.
 -  *
 -  *  Copyright (c) Australian Astronomical Observatory (AAO), (2013).
 -  *  Permission is hereby granted, free of charge, to any person obtaining a 
 -  *  copy of this software and associated documentation files (the "Software"), 
 -  *  to deal in the Software without restriction, including without limitation 
 -  *  the rights to use, copy, modify, merge, publish, distribute, sublicense, 
 -  *  and/or sell copies of the Software, and to permit persons to whom the 
 -  *  Software is furnished to do so, subject to the following conditions:
 -  *
 -  *  The above copyright notice and this permission notice shall be included in 
 -  *  all copies or substantial portions of the Software.
 -  *
 -  *  THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 
 -  *  IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 
 -  *  FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
 -  *  AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 
 -  *  LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING 
 -  *  FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
 -  *  IN THE SOFTWARE.
 -  */
 - 
 - #ifdef __APPLE__
 - 
 - #include <semaphore.h>
 - #include <time.h>
 - #include <sys/time.h>
 - #include <pthread.h>
 - #include <errno.h>
 - #include <signal.h>
 - #include <stdio.h>
 - #include <sys/types.h>
 - #include <sys/stat.h>
 - #include <sys/fcntl.h>
 - #include <setjmp.h>
 - 
 - /*  Some useful definitions - TRUE and FALSE */
 - 
 - #undef TRUE
 - #define TRUE 1
 - #undef FALSE
 - #define FALSE 0
 - 
 - /*  A structure of type timeoutDetails is passed to the thread used to 
 -  *  implement the timeout.
 -  */
 - 
 - typedef struct {
 -    struct timespec delay;            /* Specifies the delay, relative to now */
 -    pthread_t callingThread;          /* The thread doing the sem_wait call */
 -    volatile short *timedOutShort;    /* Address of a flag set to indicate that
 -                                       * the timeout was triggered. */
 - } timeoutDetails;
 - 
 - /*  A structure of type cleanupDetails is passed to the thread cleanup 
 -  *  routine which is called at the end of the routine or if the thread calling
 -  *  it is cancelled.
 -  */
 -  
 - typedef struct {
 -    pthread_t *threadIdAddr;          /* Address of the variable that holds 
 -                                       * the Id of the timeout thread. */
 -    struct sigaction *sigHandlerAddr; /* Address of the old signal action
 -                                       * handler. */
 -    volatile short *timedOutShort;    /* Address of a flag set to indicate that
 -                                       * the timeout was triggered. */
 - } cleanupDetails;
 - 
 - /*  Forward declarations of internal routines */
 - 
 - static void* timeoutThreadMain (void* passedPtr);
 - static int triggerSignal (int Signal, pthread_t Thread);
 - static void ignoreSignal (int Signal);
 - static void timeoutThreadCleanup (void* passedPtr);
 - 
 - /* -------------------------------------------------------------------------- */
 - /*
 -  *                      s e m _ t i m e d w a i t
 -  *
 -  *  This is the main code for the sem_timedwait() implementation.
 -  */
 - 
 - static int sem_timedwait (
 -    sem_t *sem,
 -    const struct timespec *abs_timeout)
 - {
 -    int result = 0;                   /* Code returned by this routine 0 or -1 */
 -    
 -    /*  "Under no circumstances shall the function fail if the semaphore
 -     *  can be locked immediately". So we try to get it quickly to see if we
 -     *  can avoid all the timeout overheads.
 -     */
 -    
 -    if (sem_trywait(sem) == 0) {
 -       
 -       /*  Yes, got it immediately. */
 -       
 -       result = 0;
 -       
 -    } else {
 -       
 -       /*  No, we've got to do it with a sem_wait() call and a thread to run
 -        *  the timeout. First, work out the time from now to the specified
 -        *  timeout, which we will pass to the timeout thread in a way that can
 -        *  be used to pass to nanosleep(). So we need this in seconds and
 -        *  nanoseconds. Along the way, we check for an invalid passed time,
 -        *  and for one that's already expired.
 -        */
 -       
 -       if ((abs_timeout->tv_nsec < 0) || (abs_timeout->tv_nsec > 1000000000)) {
 -          
 -          /* Passed time is invalid */
 -          
 -          result = -1;
 -          errno = EINVAL;
 -          
 -       } else {
 -          
 -          struct timeval currentTime;                              /* Time now */
 -          long secsToWait,nsecsToWait;            /* Seconds and nsec to delay */
 -          gettimeofday (¤tTime,NULL);
 -          secsToWait = abs_timeout->tv_sec - currentTime.tv_sec;
 -          nsecsToWait = (abs_timeout->tv_nsec - (currentTime.tv_usec * 1000));
 -          while (nsecsToWait < 0) {
 -             nsecsToWait += 1000000000;
 -             secsToWait--;
 -          }
 -          if ((secsToWait < 0) || ((secsToWait == 0) && (nsecsToWait < 0))) {
 -             
 -             /*  Time has passed. Report an immediate timeout. */
 -             
 -             result = -1;
 -             errno = ETIMEDOUT;
 -             
 -          } else {
 -             
 -             /*  We're going to have to do a sem_wait() with a timeout thread.
 -              *  The thread will wait the specified time, then will issue a
 -              *  SIGUSR2 signal that will interrupt the sem_wait() call. 
 -              *  We pass the thread the id of the current thread, the delay,
 -              *  and the address of a flag to set on a timeout, so we can 
 -              *  distinguish an interrupt caused by the timeout thread from
 -              *  one caused by some other signal.
 -              */
 -          
 -             volatile short timedOut;                /* Flag to set on timeout */
 -             timeoutDetails details;     /* All the stuff the thread must know */
 -             struct sigaction oldSignalAction;       /* Current signal setting */
 -             pthread_t timeoutThread;                  /* Id of timeout thread */
 -             cleanupDetails cleaningDetails; /* What the cleanup routine needs */
 -             int oldCancelState;                /* Previous cancellation state */
 -             int ignoreCancelState;               /* Used in call, but ignored */
 -             int createStatus;              /* Status of pthread_create() call */
 -             
 -             /*  If the current thread is cancelled (and CML does do this)
 -              *  we don't want to leave our timer thread running - if we've
 -              *  started the thread we want to make sure we join it in order
 -              *  to release its resources. So we set a cleanup handler to
 -              *  do this. We pass it the address of the structure that will
 -              *  hold all it needs to know. While we set all this up,
 -              *  we prevent ourselves being cancelled, so all this data is
 -              *  coherent.
 -              */
 -             
 -             pthread_setcancelstate (PTHREAD_CANCEL_DISABLE,&oldCancelState);
 -             timeoutThread = (pthread_t) 0;
 -             cleaningDetails.timedOutShort = &timedOut;
 -             cleaningDetails.threadIdAddr = &timeoutThread;
 -             cleaningDetails.sigHandlerAddr = &oldSignalAction;
 -             pthread_cleanup_push (timeoutThreadCleanup,&cleaningDetails);
 -             
 -             /*  Set up the details for the thread. Clear the timeout flag,
 -              *  record the current SIGUSR2 action settings so we can restore
 -              *  them later.
 -              */
 -             
 -             details.delay.tv_sec = secsToWait;
 -             details.delay.tv_nsec = nsecsToWait;
 -             details.callingThread = pthread_self();
 -             details.timedOutShort = &timedOut;
 -             timedOut = FALSE;
 -             sigaction (SIGUSR2,NULL,&oldSignalAction);
 -             
 -             /*  Start up the timeout thread. Once we've done that, we can
 -              *  restore the previous cancellation state.
 -              */
 -             
 -             createStatus = pthread_create(&timeoutThread,NULL,
 -                                          timeoutThreadMain, (void*)&details);
 -             pthread_setcancelstate (oldCancelState,&ignoreCancelState);
 -             
 -             if (createStatus < 0) {
 -                
 -                /* Failed to create thread. errno will already be set properly */
 -                
 -                result = -1;
 -                
 -             } else {
 -                
 -                /*  Thread created OK. This is where we wait for the semaphore.
 -                 */
 -                
 -                if (sem_wait(sem) == 0) {
 -                   
 -                   /*  Got the semaphore OK. We return zero, and all's well. */
 -                   
 -                   result = 0;
 -                   
 -                } else {
 -                   
 -                   /*  If we got a -1 error from sem_wait(), it may be because
 -                    *  it was interrupted by a timeout, or failed for some
 -                    *  other reason. We check for the expected timeout 
 -                    *  condition, which is an 'interrupted' status and the
 -                    *  timeout flag set by the timeout thread. We report that as
 -                    *  a timeout error. Anything else is some other error and
 -                    *  errno is already set properly.
 -                    */
 -                   
 -                   result = -1;
 -                   if (errno == EINTR) {
 -                      if (timedOut) errno = ETIMEDOUT;
 -                   }
 -                }
 -                
 -             }
 -             
 -             /*  The cleanup routine - timeoutThreadCleanup() - packages up
 -              *  any tidying up that is needed, including joining with the
 -              *  timer thread. This will be called if the current thread is
 -              *  cancelled, but we need it to happen anyway, so we set the
 -              *  execute flag true here as we remove it from the list of
 -              *  cleanup routines to be called. So normally, this line amounts
 -              *  to calling timeoutThreadCleanup().
 -              */
 -              
 -             pthread_cleanup_pop (TRUE);
 -          }
 -       }
 -    }
 -    return (result);
 - }
 - 
 - /* -------------------------------------------------------------------------- */
 - /*
 -  *                  t i m e o u t  T h r e a d  C l e a n u p
 -  *
 -  *  This internal routine tidies up at the end of a sem_timedwait() call.
 -  *  It is set as a cleanup routine for the current thread (not the timer
 -  *  thread) so it is executed even if the thread is cancelled. This is
 -  *  important, as we need to tidy up the timeout thread. If we took the
 -  *  semaphore (in other words, if we didn't timeout) then the timer thread
 -  *  will still be running, sitting in its nanosleep() call, and we need
 -  *  to cancel it. If the timer thread did signal a timeout then it will
 -  *  now be closing down. In either case, we need to join it (using a call
 -  *  to pthread_join()) or its resources will never be released.
 -  *  The single argument is a pointer to a cleanupDetails structure that has
 -  *  all the routine needs to know.
 -  */
 -    
 - static void timeoutThreadCleanup (void* passedPtr)
 - {
 -    /*  Get what we need from the structure we've been passed. */
 -    
 -    cleanupDetails *detailsPtr = (cleanupDetails*) passedPtr;
 -    short timedOut = *(detailsPtr->timedOutShort);
 -    pthread_t timeoutThread = *(detailsPtr->threadIdAddr);
 -    
 -    /*  If we created the thread, stop it - doesn't matter if it's no longer
 -     *  running, pthread_cancel can handle that. We make sure we wait for it 
 -     *  to complete, because it is this pthread_join() call that releases any 
 -     *  memory the thread may have allocated. Note that cancelling a thread is 
 -     *  generally not a good idea, because of the difficulty of cleaning up 
 -     *  after it, but this is a very simple thread that does nothing but call 
 -     *  nanosleep(), and that we can cancel quite happily.
 -     */
 -       
 -    if (!timedOut) pthread_cancel(timeoutThread);
 -    pthread_join(timeoutThread,NULL);
 -    
 -    /*  The code originally restored the old action handler, which generally 
 -     *  was the default handler that caused the task to exit. Just occasionally,
 -     *  there seem to be cases where the signal is still queued and ready to 
 -     *  trigger even though the thread that presumably sent it off just before
 -     *  it was cancelled has finished. I had thought that once we'd joined
 -     *  that thread, we could be sure of not seeing the signal, but that seems 
 -     *  not to be the case, and so restoring a handler that will allow the task
 -     *  to crash is not a good idea, and so the line below has been commented
 -     *  out.
 -     *
 -     *  sigaction (SIGUSR2,detailsPtr->sigHandlerAddr,NULL);
 -     */
 - }
 - 
 - /* -------------------------------------------------------------------------- */
 - /*
 -  *                  t i m e o u t  T h r e a d  M a i n
 -  *
 -  *  This internal routine is the main code for the timeout thread.
 -  *  The single argument is a pointer to a timeoutDetails structure that has
 -  *  all the thread needs to know - thread to signal, delay time, and the
 -  *  address of a flag to set if it triggers a timeout.
 -  */
 -    
 - static void* timeoutThreadMain (void* passedPtr)
 - {
 -    void* Return = (void*) 0;
 -    
 -    /*  We grab all the data held in the calling thread right now. In some
 -     *  cases, we find that the calling thread has vanished and released
 -     *  its memory, including the details structure, by the time the timeout
 -     *  expires, and then we get an access violation when we try to set the
 -     *  'timed out' flag.
 -     */
 -    
 -    timeoutDetails details = *((timeoutDetails*) passedPtr);
 -    struct timespec requestedDelay = details.delay;
 -    
 -    /*  We do a nanosleep() for the specified delay, and then trigger a
 -     *  timeout. Note that we allow for the case where the nanosleep() is
 -     *  interrupted, and restart it for the remaining time. If the 
 -     *  thread that is doing the sem_wait() call gets the semaphore, it
 -     *  will cancel this thread, which is fine as we aren't doing anything
 -     *  other than a sleep and a signal.
 -     */
 -    
 -    for (;;) {
 -       struct timespec remainingDelay;
 -       if (nanosleep (&requestedDelay,&remainingDelay) == 0) {
 -          break;
 -       } else if (errno == EINTR) {
 -          requestedDelay = remainingDelay;
 -       } else {
 -          Return = (void*) (long) errno;
 -          break;
 -       }
 -    }
 -    
 -    /*  We've completed the delay without being cancelled, so we now trigger
 -     *  the timeout by sending a signal to the calling thread. And that's it,
 -     *  although we set the timeout flag first to indicate that it was us
 -     *  that interrupted the sem_wait() call. One precaution: before we
 -     *  try to set the timed-out flag, make sure the calling thread still
 -     *  exists - this may not be the case if things are closing down a bit
 -     *  messily. We check this quickly using a zero test signal.
 -     */
 -    
 -    if (pthread_kill(details.callingThread,0) == 0) {
 -       *(details.timedOutShort) = TRUE;
 -       if (triggerSignal (SIGUSR2,details.callingThread) < 0) {
 -          Return = (void*) (long) errno;
 -       }
 -    }
 -    
 -    return Return;
 - }
 -    
 - /* -------------------------------------------------------------------------- */
 - /*
 -  *                    t r i g g e r  S i g n a l
 -  *
 -  *  This is a general purpose routine that sends a specified signal to
 -  *  a specified thread, setting up a signal handler that does nothing,
 -  *  and then giving the signal. The only effect will be to interrupt any
 -  *  operation that is currently blocking - in this case, we expect this to
 -  *  be a sem_wait() call.
 -  */
 -    
 - static int triggerSignal (int Signal, pthread_t Thread)
 - {
 -    int Result = 0;
 -    struct sigaction SignalDetails;
 -    SignalDetails.sa_handler = ignoreSignal;
 -    SignalDetails.sa_flags = 0;
 -    (void) sigemptyset(&SignalDetails.sa_mask);
 -    if ((Result = sigaction(Signal,&SignalDetails,NULL)) == 0) {
 -       Result = pthread_kill(Thread,Signal);
 -    }
 -    return Result;
 - }
 -    
 - /* -------------------------------------------------------------------------- */
 - /*
 -  *                     i g n o r e  S i g n a l
 -  *
 -  *  And this is the signal handler that does nothing. (It clears its argument,
 -  *  but this has no effect and prevents a compiler warning about an unused
 -  *  argument.)
 -  */
 -     
 - static void ignoreSignal (int Signal) {
 -    Signal = 0;
 - } 
 - 
 - #endif
 - 
 - /* -------------------------------------------------------------------------- */
 - /*
 -  *                           T e s t  c o d e
 -  *
 -  *   The rest of the code here is used to test sem_timedwait(), and is 
 -  *   compiled only if the pre-processor variable TEST is set. The test
 -  *   program sets up a random timeout and a random delay after which a
 -  *   test semaphore will become available. It starts a thread to release the
 -  *   semaphore after the specified delay, and issues a sem_timedwait() call
 -  *   to take the semaphore, with the specified timeout. It repeats this 
 -  *   several times, and finally reports the number of times the semaphore 
 -  *   was taken, the number of times it timed out, and the number of these
 -  *   occurrences that were unexpected - ie a semaphore being taken although
 -  *   the timeout was less than the delay before it was set, or vice versa.
 -  *   The main() routine of the test returns the number of unexpected
 -  *   occurrences, which will be zero if the code is working properly.
 -  *
 -  *   To run:
 -  *   
 -  *   gcc -o timed -Wall -ansi -pedantic -DTEST sem_timedwait.c -lpthread
 -  *   ./timed [count] [timescale]
 -  *
 -  *   On some Linux systems, you may need to drop the -ansi - see comments
 -  *   at start of file. On OS X systems, most tests up to a time frame of
 -  *   0.001 secs show nothing happening in an unexpected sequence. On a
 -  *   Linux 2.4 system, with its lower time resolution, tests will show
 -  *   occasional cases where things don't happen in the expected order, but
 -  *   these are not counted as unexpected if the two random times are less
 -  *   than 10 msec apart. 
 -  */
 - 
 - #ifdef TEST
 - 
 - #include <stdio.h>
 - #include <unistd.h>
 - #include <stdlib.h>
 - 
 - /*  A giverDetails structure is used to pass the necessary information
 -  *  to the thread that is started to release the semaphore.
 -  */
 - 
 - typedef struct {
 -    sem_t *semAddr;                        /*  Address of semaphore to release */
 -    float delaySecs;                            /* Time to wait before release */
 - } giverDetails;
 - 
 - /* -------------------------------------------------------------------------- */
 - /*
 -  *                           g i v e r  T h r e a d  M a i n
 -  *
 -  *  This is the main code for the thread that releases the semaphore after
 -  *  a specified delay. The single argument is the address of a giverDetails
 -  *  structure, which specifies the delay time and the semaphore to release.
 -  *  If the sem_timedwait() call in the main thread times-out, this thread
 -  *  is cancelled and so will not release the semaphore.
 -  */
 - 
 - static void* giverThreadMain (void* passedPtr)
 - {
 -    /*  All we do is sleep the specified time and then release the semaphore */
 -    
 -    giverDetails *details = (giverDetails*) passedPtr;
 -    long uSecs = (long)(details->delaySecs * 1000000.0);
 -    usleep (uSecs);
 -    if (sem_post(details->semAddr) < 0) {
 -       perror ("sem_post");
 -    }
 -    return NULL;
 - }
 -    
 - /* -------------------------------------------------------------------------- */
 - /*
 -  *                                 m a i n
 -  *
 -  *   The main test routine. This creates a semaphore, then sets up a series
 -  *   of sem_timedwait() calls on it. For each call it starts a thread that 
 -  *   will release the semaphore after a random time, and specifies another
 -  *   similar random time as the timeout for the sem_timedwait() call. It 
 -  *   then checks that what happens is what it expects.
 -  *
 -  *   The pogram takes two optional arguments. The first is an integer giving
 -  *   the nuber of sem_timedwait() calls it is to attempt (default 10) and the
 -  *   second is a floatig point value that gives the time scale - it is the
 -  *   maximum time in seconds for the two random times that are generated for
 -  *   each sem_timedwait() call. The times should be fairly evenly distributed
 -  *   between this value and a hard-coded minimum of 0.001 seconds. The default
 -  *   time scale is 1.0.
 -  *
 -  *   Note that on all systems, if the difference between the two random times
 -  *   (the timeout and the delay before the semaphore is given) is comparable 
 -  *   with the scheduling resolution of the system - which is only 10 
 -  *   milliseconds on a standard Linux 2.4 kernel - you can expect to get
 -  *   some cases where the 'wrong' timer goes off first. So these cases are
 -  *   logged, but anything with a difference of less than 10 msec isn't
 -  *   included in the unexpected count.
 -  */
 - 
 - int main (
 -    int argc,
 -    char* argv[])
 - {
 -    char semName[1024];           /* Semaphore name if we need to use sem_open */
 -    sem_t theSem;                                      /* The semaphore itself */
 -    sem_t *semAddr;                            /* The address of the semaphore */
 -    struct timespec absTime;              /* Absolute time at which we timeout */
 -    struct timeval currentTime;                          /* The time right now */
 -    pthread_t giverThread;          /* Id for the thread that releases the sem */
 -    giverDetails details;                /* Details passed to the giver thread */
 -    int randomShort;                        /* Random number in range 0..65535 */
 -    float randomDelaySecs;              /* Random delay before semaphore given */
 -    float randomTimeoutSecs;                           /* Random timeout value */
 -    int intSecs;                                  /* Integer number of seconds */
 -    long intNsecs;                                /* Nanoseconds in delay time */
 -    int msecs;                           /* Milliseconds between the two times */
 -    short retry;                                   /* Controls the EAGAIN loop */
 -    int count;                      /* Number of tries at the semaphore so far */
 -    int takenCount = 0;              /* Number ot time the semaphore was taken */
 -    int unexpectedCount = 0;               /* Number of unexpected occurrences */
 -    int timeoutCount = 0;                      /* Number of times we timed out */
 -    float timeScaleSecs = 1.0;               /* Time scale - from command line */
 -    int maxCount = 10;      /* Times through the test loop - from command line */
 -    
 -    /*  Get the command line arguments, the number of tries, and the time
 -     *  scale to use.
 -     */
 -    
 -    if (argc >= 3) {
 -       timeScaleSecs = atof(argv[2]);
 -    }
 -    if (argc >= 2) {
 -       maxCount = atoi(argv[1]);
 -    }
 -    
 -    /*  Creating a semaphore is awkward - some systems support sem_init(),
 -     *  which is nice, but OS X only supports sem_open() and returns ENOSYS
 -     *  for sem_init(). This code handles both cases. The semaphore is
 -     *  created taken.
 -     */
 -    
 -    semName[0] = '\0';
 -    semAddr = &theSem;
 -    if (sem_init(semAddr,0,0) < 0) {
 -       if (errno == ENOSYS) {
 -          sprintf (semName,"/tmp/test_%ld.sem",(long)getpid());
 -          if ((semAddr = sem_open(semName,
 -                              O_CREAT|O_EXCL,S_IWUSR | S_IRUSR,0))
 -                                                 == (sem_t*)SEM_FAILED) {
 -             perror ("creating semaphore");
 -          }
 -       }
 -    }
 -    
 -    /*  Loop through the specified number of tests. */
 -    
 -    for (count = 0; count < maxCount; count++) {
 -       
 -       /*  Generate random times for the timeout and for the delay before
 -        *  the semaphore is given. I'm only using the last 16 bits from random()
 -        *  becasuse that's good enough for this and saves me worrying about
 -        *  handling really big integers near the 32 bit limit. First for the
 -        *  delay used by the giver thread.
 -        */
 -       
 -       randomShort = random() & 0xffff;
 -       randomDelaySecs = ((float)randomShort)/65536.0 * timeScaleSecs;
 -       if (randomDelaySecs < 0.001) randomDelaySecs = 0.001;
 -       details.semAddr = semAddr;
 -       details.delaySecs = randomDelaySecs;
 -       
 -       /*  And now for the timeout, which has to be converted into an absolute
 -        *  time from now in the form required by sem_timedwait.
 -        */
 -       
 -       randomShort = random() & 0xffff;
 -       randomTimeoutSecs = ((float)randomShort)/65536.0 * timeScaleSecs;
 -       if (randomTimeoutSecs < 0.001) randomTimeoutSecs = 0.001;
 -       intSecs = (int)randomTimeoutSecs;
 -       intNsecs = (long)((randomTimeoutSecs - (float)intSecs) * 1000000000.0);
 -       gettimeofday (¤tTime,NULL);
 -       absTime.tv_sec = currentTime.tv_sec + intSecs;
 -       absTime.tv_nsec = (currentTime.tv_usec * 1000) + intNsecs;
 -       while (absTime.tv_nsec > 1000000000) {
 -          absTime.tv_sec++;
 -          absTime.tv_nsec -= 1000000000;
 -       }
 -       
 -       /*  Create the 'giver' thread, which will release the semaphore after
 -        *  the specified delay time.
 -        */
 -       
 -       pthread_create(&giverThread,NULL,giverThreadMain,(void*)&details);
 -       
 -       /*  Now try to take the semaphore and see what happens - timeout or
 -        *  a taken semaphore? The retry loop handles any cases where an
 -        *  EAGAIN problem is signalled.
 -        */
 -       
 -       retry = TRUE;
 -       while (retry) {
 -          retry = FALSE;
 -          if (sem_timedwait (semAddr,&absTime) == 0) {
 -             
 -             /*  We got the semaphore. See if we expected to. */
 -             
 -             takenCount++;
 -             if (randomDelaySecs > randomTimeoutSecs) {
 -                msecs = (int)((randomDelaySecs - randomTimeoutSecs) * 1000.0);
 -                printf (
 -                   "Sem taken first, delay %f timeout %f, diff %d msec\n",
 -                                       randomDelaySecs,randomTimeoutSecs,msecs);
 -                if (msecs < 10) {
 -                   printf ("Time difference too short to count as an error\n");
 -                } else {
 -                   unexpectedCount++;
 -                }
 -             }
 -          } else {
 -             
 -             /*  We failed. See if this was a timeout, in which case see if
 -              *  it was expected. If not, check for EAGAIN and retry, or log
 -              *  an error in all other cases.
 -              */
 -             
 -             if (errno != ETIMEDOUT) {
 -                if (errno == EAGAIN) {
 -                   retry = TRUE;
 -                } else {
 -                   perror ("Timed wait");
 -                }
 -             } else {
 -                timeoutCount++;
 -                if (randomDelaySecs < randomTimeoutSecs) {
 -                   msecs = (int)((randomTimeoutSecs - randomDelaySecs) * 1000.0);
 -                   printf (
 -                      "Timedout first, delay %f timeout %f, diff %d msec\n",
 -                                      randomDelaySecs,randomTimeoutSecs,msecs);
 -                   if (msecs < 10) {
 -                      printf (
 -                           "Time difference too short to count as an error\n");
 -                   } else {
 -                      unexpectedCount++;
 -                   }
 -                }
 -             }
 -          }
 -       }
 -       
 -       /*  Cancel the giver thread if it's still running (ie a timeout or other
 -        *  error), and wait for it to complete - that's needed to release its
 -        *  resources.
 -        */
 -       
 -       pthread_cancel(giverThread);
 -       pthread_join(giverThread,NULL);
 -       
 -       /*  Something to show we're still running. */
 -       
 -       if (((count + 1) % 25) == 0) {
 -          printf ("Tries: %d, Taken %d, Timedout %d, unexpected %d\n",
 -                            count + 1,takenCount, timeoutCount,unexpectedCount);
 -       }
 -       
 -       /*  And then back to try again. Note that the semaphore shuld now be
 -        *  taken. Either it was releaed by the giver and we took it in the
 -        *  sem_timedwait() call, or we timed out, in which case it's still
 -        *  taken. So the next sem_timedwait() call will wait, just like this
 -        *  one.
 -        */
 -    }
 -    printf ("Final results: Taken %d, Timedout %d, unexpected %d\n",
 -                                     takenCount,timeoutCount,unexpectedCount);
 -    return unexpectedCount;
 - }
 - 
 - #endif
 
 
  |