usleep.c


#if defined(UNIX)
#include <time.h>
#include <unistd.h>

#ifdef HAVE_NANOSLEEP
void usleep (unsigned int useconds) {
  struct timespec ts = { tv_sec: (long int) (useconds / 1000000),
			 tv_nsec: (long int) (useconds % 1000000) * 1000ul };

  __nanosleep (&ts, NULL);
}
#else /* HAVE_NANOSLEEP */
#ifdef HAVE_SELECT_H
#include <sys/select.h>
#endif
void usleep(unsigned long usec) {
        struct timeval timeout;

        timeout.tv_sec = usec / 1000000;
        timeout.tv_usec = usec - 1000000 * timeout.tv_sec;
        select(1, NULL, NULL, NULL, &timeout);
}
#endif /* HAVE_NANOSLEEP */

#elif defined(MSWINDOWS)

#include <windows.h>

void usleep(long usecs) {
	long msecs;

	msecs = usecs / 1000L;
	if (msecs <= 0) msecs = 1;	/* minimum delay is 1 millisecond */
	Sleep((DWORD)msecs);
}

#elif defined(DOS)

#include <dos.h>

static unsigned long start_usecs;
static unsigned long end_usecs;
static int calibrated = 0;
volatile unsigned long dummy = 0;
double delay_factor = 1;

#ifndef USE_DOS_TIME
unsigned long stop_tick;

#ifndef NO_TICKS_MACRO
#define get_bios_ticks() (*((volatile unsigned long far *)(MK_FP(0, 0x46c))))
#else /* !NO_TICKS_MACRO */
unsigned long get_bios_ticks(void)
{
	static unsigned long far *p;

	if (!p)
		p = MK_FP(0, 0x46c);
	return *p;
}
#endif /* !NO_TICKS_MACRO */
#endif /* !USE_DOS_TIME */

void start_time(void) {
#ifndef USE_DOS_TIME
	unsigned long t;

	t = get_bios_ticks() & 0xff;
	start_usecs = 55000L * t;
#else
	struct dostime_t t;

	_dos_gettime(&t);
	start_usecs = 1000000L * t.second + 10000L * t.hsecond;
#endif
}

unsigned long elasped_usecs(void) {
#ifndef USE_DOS_TIME
	unsigned long t;

	t = get_bios_ticks() & 0xff;
	end_usecs = 55000L * t;
	while (end_usecs < start_usecs)
		end_usecs += 55000L * 0xff;
#else
	struct dostime_t t;

	_dos_gettime(&t);
	end_usecs = 1000000L * t.second + 10000L * t.hsecond;
	while (end_usecs < start_usecs)
		end_usecs += 60L * 1000000L;
#endif
	return end_usecs - start_usecs;
}

unsigned long spin_loop(double delay_factor)
{
	unsigned long delay = delay_factor;

#ifndef USE_DOS_TIME
#define CAL_TICKS 4
	dummy = 0;
	if (delay == 0) {
		unsigned long end_tick;
		unsigned long start_tick = get_bios_ticks();

		/* sync with next clock tick */
		while (start_tick == (end_tick = get_bios_ticks()))
			;
		stop_tick = end_tick + CAL_TICKS;
	} else {
		stop_tick = get_bios_ticks() - 1;
	}
#endif /* !USE_DOS_TIME */
	while (--delay > 0) {
		++dummy;
#ifndef USE_DOS_TIME
		if (get_bios_ticks() == stop_tick)
			break;
#endif
	}
#ifndef USE_DOS_TIME
	return dummy / CAL_TICKS;
#else
	return dummy;
#endif
};

#ifndef USE_DOS_TIME
void calibrate_delay(void)
{
	unsigned long loops, loops1, loops2;

	/* calibrate spin_loop() (returns loops per 18.2Hz PC timer tick */
	loops1 = spin_loop(0.0);
	loops2 = spin_loop(0.0);
	/* use larger loop count for delay factor calculation*/
	loops = (loops1 > loops2) ? loops1 : loops2;
	delay_factor = (double)loops / 55000.0;
	calibrated = 1;
}
#else /* USE_DOS_TIME */
void calibrate_delay(void)
{
	int i;
	unsigned long usecs;

	delay_factor = 1;
	for (i = 0; i < 32; ++i) {
		start_time();
		spin_loop(delay_factor);
		usecs = elasped_usecs();
		if (usecs >= 2L * 55L * 1000L) {
			delay_factor = delay_factor / usecs;
			break;
		}
		delay_factor = delay_factor * 4.0;
	}
	calibrated = 1;
}
#endif /* USE_DOS_TIME */

long usleep(long usecs)
{
	if (!calibrated)
		calibrate_delay();
	if (usecs > 200000) {
		start_time();
		while (elasped_usecs() < usecs)
			;
	} else {
		spin_loop(delay_factor * usecs + 1);
	}
}

#else
#error platform not defined
#endif

Back