// Copyright (c) 2004 David Muse // See the COPYING file for more information #include #include #include #if defined(RUDIMENTS_HAVE_NANOSLEEP) || defined(RUDIMENTS_HAVE_CLOCK_NANOSLEEP) #include #else #include #ifdef RUDIMENTS_HAVE_SYS_SELECT_H #include #endif #ifdef RUDIMENTS_HAVE_UNISTD_H #include #endif #endif #ifdef RUDIMENTS_NAMESPACE namespace rudiments { #endif bool snooze::macrosnooze(long seconds) { timespec nanotimetosnooze; nanotimetosnooze.tv_sec=seconds; nanotimetosnooze.tv_nsec=0; return nanosnooze(&nanotimetosnooze); } bool snooze::macrosnooze(long seconds, long *remainingseconds) { timespec nanotimetosnooze; nanotimetosnooze.tv_sec=seconds; nanotimetosnooze.tv_nsec=0; timespec nanotimeremaining; bool retval=nanosnooze(&nanotimetosnooze,&nanotimeremaining); *remainingseconds=nanotimeremaining.tv_sec; return retval; } bool snooze::microsnooze(long seconds, long microseconds) { timeval timetosnooze; timetosnooze.tv_sec=seconds; timetosnooze.tv_usec=microseconds; return microsnooze(&timetosnooze); } bool snooze::microsnooze(long seconds, long microseconds, long *secondsremaining, long *microsecondsremaining) { timeval timetosnooze; timetosnooze.tv_sec=seconds; timetosnooze.tv_usec=microseconds; timeval timeremaining; bool retval=microsnooze(&timetosnooze,&timeremaining); if (secondsremaining) { *secondsremaining=timeremaining.tv_sec; } if (microsecondsremaining) { *microsecondsremaining=timeremaining.tv_usec; } return retval; } bool snooze::microsnooze(timeval *timetosnooze) { timespec nanotimetosnooze; nanotimetosnooze.tv_sec=timetosnooze->tv_sec; nanotimetosnooze.tv_nsec=timetosnooze->tv_usec*1000; return nanosnooze(&nanotimetosnooze); } bool snooze::microsnooze(timeval *timetosnooze, timeval *timeremaining) { timespec nanotimetosnooze; nanotimetosnooze.tv_sec=timetosnooze->tv_sec; nanotimetosnooze.tv_nsec=timetosnooze->tv_usec*1000; timespec nanotimeremaining; bool retval=nanosnooze(&nanotimetosnooze,&nanotimeremaining); timeremaining->tv_sec=nanotimeremaining.tv_sec; timeremaining->tv_usec=nanotimeremaining.tv_nsec/1000; return retval; } bool snooze::nanosnooze(long seconds, long nanoseconds) { timespec timetosnooze; timetosnooze.tv_sec=seconds; timetosnooze.tv_nsec=nanoseconds; return nanosnooze(&timetosnooze); } bool snooze::nanosnooze(long seconds, long nanoseconds, long *secondsremaining, long *nanosecondsremaining) { timespec timetosnooze; timetosnooze.tv_sec=seconds; timetosnooze.tv_nsec=nanoseconds; timespec timeremaining; bool retval=nanosnooze(&timetosnooze,&timeremaining); if (secondsremaining) { *secondsremaining=timeremaining.tv_sec; } if (nanosecondsremaining) { *nanosecondsremaining=timeremaining.tv_nsec; } return retval; } bool snooze::nanosnooze(timespec *timetosnooze) { timespec snoozetime; snoozetime.tv_sec=timetosnooze->tv_sec; snoozetime.tv_nsec=timetosnooze->tv_nsec; timespec remaining; for (;;) { if (nanosnooze(&snoozetime,&remaining)) { return true; } else if (error::getErrorNumber()!=EINTR) { return false; } snoozetime.tv_sec=remaining.tv_sec; snoozetime.tv_nsec=remaining.tv_nsec; } } bool snooze::nanosnooze(timespec *timetosnooze, timespec *timeremaining) { #ifdef RUDIMENTS_HAVE_NANOSLEEP return !::nanosleep(timetosnooze,timeremaining); #elif RUDIMENTS_HAVE_CLOCK_NANOSLEEP return !clock_nanosleep(CLOCK_REALTIME,TIME_ABSTIME, timetosnooze,timeremaining); #elif MINGW32 // on windows, we only have millisecond resolution and we // can't the remaining time back sleep(timetosnooze->tv_sec*1000+timetosnooze->tv_nsec/1000000); // set timeremaining to 0 timeremaining->tv_sec=0; timeremaining->tv_nsec=0; return true; #else // use regular sleep command to handle the whole seconds if (timetosnooze->tv_sec) { unsigned int remainder=::sleep(timetosnooze->tv_sec); if (remainder) { timeremaining->tv_sec=remainder; timeremaining->tv_nsec=timetosnooze->tv_nsec; return false; } } // set timeremaining to 0 timeremaining->tv_sec=0; timeremaining->tv_nsec=0; // Use select or pselect to wait for the remaining time. // // It's tempting just to use select/pselect to sleep the entire // interval. But on many platforms, select() doesn't modify // it's time struct to indicate how much time was left when it // timed out. And on the platforms that it does do that, if // an error occurs such as being interrupted by a signal, then // the values in the time struct are undefined anyway. // // So, when using select/pselect, we can't return the number of // nanoseconds that were left if a signal interrupts the call. // But, at least we can return the number of seconds. #ifdef RUDIMENTS_HAVE_PSELECT timespec ts; ts.tv_sec=0; ts.tv_nsec=timetosnooze->tv_nsec; return (pselect(0,NULL,NULL,NULL,&ts,NULL)!=-1); #else timeval tv; tv.tv_sec=0; tv.tv_usec=timetosnooze->tv_nsec/1000; return (select(0,NULL,NULL,NULL,&tv)!=-1); #endif #endif } #ifdef RUDIMENTS_NAMESPACE } #endif