--- BasiliskII/src/Unix/timer_unix.cpp 1999/10/14 16:05:18 1.2 +++ BasiliskII/src/Unix/timer_unix.cpp 2001/07/09 11:22:00 1.11 @@ -1,7 +1,7 @@ /* * timer_unix.cpp - Time Manager emulation, Unix specific stuff * - * Basilisk II (C) 1997-1999 Christian Bauer + * Basilisk II (C) 1997-2001 Christian Bauer * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -19,11 +19,19 @@ */ #include "sysdeps.h" +#include "macos_util.h" #include "timer.h" +#include + #define DEBUG 0 #include "debug.h" +// For NetBSD with broken pthreads headers +#ifndef CLOCK_REALTIME +#define CLOCK_REALTIME 0 +#endif + /* * Return microseconds since boot (64 bit) @@ -50,16 +58,9 @@ void Microseconds(uint32 &hi, uint32 &lo * Return local date/time in Mac format (seconds since 1.1.1904) */ -const uint32 TIME_OFFSET = 0x7c25b080; // Offset Mac->Unix time in seconds - uint32 TimerDateTime(void) { - time_t uct_now = time(NULL); - long tz = timezone; - time_t local_now = uct_now - tz; - if (daylight) - local_now += 3600; - return (uint32)local_now + TIME_OFFSET; + return TimeToMacTime(time(NULL)); } @@ -197,3 +198,101 @@ int32 timer_host2mac_time(tm_time_t host return -t; // Time in negative microseconds } } + + +/* + * Get current value of microsecond timer + */ + +uint64 GetTicks_usec(void) +{ +#ifdef HAVE_CLOCK_GETTIME + struct timespec t; + clock_gettime(CLOCK_REALTIME, &t); + return (uint64)t.tv_sec * 1000000 + t.tv_nsec / 1000; +#else + struct timeval t; + gettimeofday(&t, NULL); + return (uint64)t.tv_sec * 1000000 + t.tv_usec; +#endif +} + + +/* + * Delay by specified number of microseconds (<1 second) + * (adapted from SDL_Delay() source; this function is designed to provide + * the highest accuracy possible) + */ + +#if defined(linux) +// Linux select() changes its timeout parameter upon return to contain +// the remaining time. Most other unixen leave it unchanged or undefined. +#define SELECT_SETS_REMAINING +#elif defined(__FreeBSD__) || defined(__sun__) +#define USE_NANOSLEEP +#elif defined(HAVE_PTHREADS) && defined(sgi) +// SGI pthreads has a bug when using pthreads+signals+nanosleep, +// so instead of using nanosleep, wait on a CV which is never signalled. +#define USE_COND_TIMEDWAIT +#endif + +void Delay_usec(uint32 usec) +{ + int was_error; + +#if defined(USE_NANOSLEEP) + struct timespec elapsed, tv; +#elif defined(USE_COND_TIMEDWAIT) + // Use a local mutex and cv, so threads remain independent + pthread_cond_t delay_cond = PTHREAD_COND_INITIALIZER; + pthread_mutex_t delay_mutex = PTHREAD_MUTEX_INITIALIZER; + struct timespec elapsed; + uint64 future; +#else + struct timeval tv; +#ifndef SELECT_SETS_REMAINING + uint64 then, now, elapsed; +#endif +#endif + + // Set the timeout interval - Linux only needs to do this once +#if defined(SELECT_SETS_REMAINING) + tv.tv_sec = 0; + tv.tv_usec = usec; +#elif defined(USE_NANOSLEEP) + elapsed.tv_sec = 0; + elapsed.tv_nsec = usec * 1000; +#elif defined(USE_COND_TIMEDWAIT) + future = GetTicks_usec() + usec; + elapsed.tv_sec = future / 1000000; + elapsed.tv_nsec = (future % 1000000) * 1000; +#else + then = GetTicks_usec(); +#endif + + do { + errno = 0; +#if defined(USE_NANOSLEEP) + tv.tv_sec = elapsed.tv_sec; + tv.tv_nsec = elapsed.tv_nsec; + was_error = nanosleep(&tv, &elapsed); +#elif defined(USE_COND_TIMEDWAIT) + was_error = pthread_mutex_lock(&delay_mutex); + was_error = pthread_cond_timedwait(&delay_cond, &delay_mutex, &elapsed); + was_error = pthread_mutex_unlock(&delay_mutex); +#else +#ifndef SELECT_SETS_REMAINING + // Calculate the time interval left (in case of interrupt) + now = GetTicks_usec(); + elapsed = now - then; + then = now; + if (elapsed >= usec) + break; + usec -= elapsed; + tv.tv_sec = 0; + tv.tv_usec = usec; +#endif + was_error = select(0, NULL, NULL, NULL, &tv); +#endif + } while (was_error && (errno == EINTR)); +}