/*
 * $RCSfile: nanosleep.c,v $
 
 * x-kernel v3.3

 * This file implements the POSIX.4 real-time extensions nanosleep
 * routine.  This function will force the currently running thread to
 * sleep using the primitives in the Linux Pthreads library.  The
 * nanosleep defined in the Pthreads library takes a single argument
 * add does not set the seconds field correctly.

 * WARNING: This routine does not set errno accoring to POSIX rules.
 * Rather it forces the thread to REALLY sleep just as long as you
 * say.  This is done because the pthread __sleep primitive doesn't
 * work and we have to hold its hand all the way to sleep long enough.
 * Because of this all sleep are gauraunteed even if interrupted by a
 * signal.  THIS MAY NOT BE THE DESIRED EFFECT FOR YOUR APPLICATION.
 * If your thread blocks all signals anyway forget I said anything.

 * This code SHOULD BE PROFILED to determine to amount of effective
 * busy waiting occuring.  Note that we cannot implement this using
 * SIGALRM since that is against the POSIX.4 standard AND SIGALRMs are
 * not propogated to the process from the pthread kernel.

 * Copyright (c) 1996  Arizona Board of Regents
 
 * $Log: nanosleep.c,v $
 * Revision 1.1  1996/05/31 23:01:44  rrp
 * Initial revision
 *
 * Revision 1.2  1996/05/09  18:33:53  mjk
 * xnanosleep handles a NULL 2nd argument as per POSIX.
 *
 * Revision 1.1  1996/03/15  22:04:35  mjk
 * Initial revision
 *

 */

#include <stdio.h>
#include <sys/time.h>
#include "thread.h"

				/* pthreads internal function 		*/
extern void __sleep(struct timespec *);


int xnanosleep(const struct timespec *reqnap, struct timespec *remnap) {
  struct timeval	curtime;
  struct timeval	endtime;
  struct timespec	remaining;

  gettimeofday(&curtime, NULL);
  endtime.tv_sec   = curtime.tv_sec + reqnap->tv_sec;
  endtime.tv_usec  = curtime.tv_usec + reqnap->tv_nsec/1e3;
  endtime.tv_sec  += (long)((float)endtime.tv_usec / 1e6);
  endtime.tv_usec %= (long)1e6;

  remaining = *reqnap;
  while ( remaining.tv_sec >= 0 && remaining.tv_nsec >= 0 ) {
    __sleep(&remaining);

				/* How much time is really remaining?
                                   __sleep lies so we must manualy
                                   check. */
    gettimeofday(&curtime, NULL);
    remaining.tv_sec  = (endtime.tv_sec - curtime.tv_sec);
    remaining.tv_nsec = (endtime.tv_usec - curtime.tv_usec) * 1000;
    while ( remaining.tv_nsec < 0 ) {
      remaining.tv_sec--;
      remaining.tv_nsec += (long)1e9;
    }
  }

  if ( remnap )
    *remnap = remaining;
  
  return 0;
}

/* nanosleep.c ends here */


