--- BasiliskII/src/Unix/timer_unix.cpp 2004/01/12 15:29:25 1.14 +++ BasiliskII/src/Unix/timer_unix.cpp 2009/08/17 20:42:26 1.21 @@ -1,7 +1,7 @@ /* * timer_unix.cpp - Time Manager emulation, Unix specific stuff * - * Basilisk II (C) 1997-2004 Christian Bauer + * Basilisk II (C) 1997-2008 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 @@ -32,6 +32,23 @@ #define CLOCK_REALTIME 0 #endif +#if defined(__MACH__) +#include +#include + +static clock_serv_t host_clock; +static bool host_clock_inited = false; + +static inline void mach_current_time(tm_time_t &t) { + if(!host_clock_inited) { + host_get_clock_service(mach_host_self(), SYSTEM_CLOCK, &host_clock); + host_clock_inited = true; + } + + clock_get_time(host_clock, &t); +} +#endif + /* * Return microseconds since boot (64 bit) @@ -40,10 +57,14 @@ void Microseconds(uint32 &hi, uint32 &lo) { D(bug("Microseconds\n")); -#ifdef HAVE_CLOCK_GETTIME +#if defined(HAVE_CLOCK_GETTIME) struct timespec t; clock_gettime(CLOCK_REALTIME, &t); uint64 tl = (uint64)t.tv_sec * 1000000 + t.tv_nsec / 1000; +#elif defined(__MACH__) + tm_time_t t; + mach_current_time(t); + uint64 tl = (uint64)t.tv_sec * 1000000 + t.tv_nsec / 1000; #else struct timeval t; gettimeofday(&t, NULL); @@ -72,6 +93,8 @@ void timer_current_time(tm_time_t &t) { #ifdef HAVE_CLOCK_GETTIME clock_gettime(CLOCK_REALTIME, &t); +#elif defined(__MACH__) + mach_current_time(t); #else gettimeofday(&t, NULL); #endif @@ -84,7 +107,7 @@ void timer_current_time(tm_time_t &t) void timer_add_time(tm_time_t &res, tm_time_t a, tm_time_t b) { -#ifdef HAVE_CLOCK_GETTIME +#if defined(HAVE_CLOCK_GETTIME) || defined(__MACH__) res.tv_sec = a.tv_sec + b.tv_sec; res.tv_nsec = a.tv_nsec + b.tv_nsec; if (res.tv_nsec >= 1000000000) { @@ -108,7 +131,7 @@ void timer_add_time(tm_time_t &res, tm_t void timer_sub_time(tm_time_t &res, tm_time_t a, tm_time_t b) { -#ifdef HAVE_CLOCK_GETTIME +#if defined(HAVE_CLOCK_GETTIME) || defined(__MACH__) res.tv_sec = a.tv_sec - b.tv_sec; res.tv_nsec = a.tv_nsec - b.tv_nsec; if (res.tv_nsec < 0) { @@ -132,7 +155,7 @@ void timer_sub_time(tm_time_t &res, tm_t int timer_cmp_time(tm_time_t a, tm_time_t b) { -#ifdef HAVE_CLOCK_GETTIME +#if defined(HAVE_CLOCK_GETTIME) || defined(__MACH__) if (a.tv_sec == b.tv_sec) return a.tv_nsec - b.tv_nsec; else @@ -152,7 +175,7 @@ int timer_cmp_time(tm_time_t a, tm_time_ void timer_mac2host_time(tm_time_t &res, int32 mactime) { -#ifdef HAVE_CLOCK_GETTIME +#if defined(HAVE_CLOCK_GETTIME) || defined(__MACH__) if (mactime > 0) { // Time in milliseconds res.tv_sec = mactime / 1000; @@ -187,7 +210,7 @@ int32 timer_host2mac_time(tm_time_t host if (hosttime.tv_sec < 0) return 0; else { -#ifdef HAVE_CLOCK_GETTIME +#if defined(HAVE_CLOCK_GETTIME) || defined(__MACH__) uint64 t = (uint64)hosttime.tv_sec * 1000000 + hosttime.tv_nsec / 1000; #else uint64 t = (uint64)hosttime.tv_sec * 1000000 + hosttime.tv_usec; @@ -210,6 +233,10 @@ uint64 GetTicks_usec(void) struct timespec t; clock_gettime(CLOCK_REALTIME, &t); return (uint64)t.tv_sec * 1000000 + t.tv_nsec / 1000; +#elif defined(__MACH__) + tm_time_t t; + mach_current_time(t); + return (uint64)t.tv_sec * 1000000 + t.tv_nsec / 1000; #else struct timeval t; gettimeofday(&t, NULL); @@ -228,7 +255,7 @@ uint64 GetTicks_usec(void) // 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__) +#elif defined(__FreeBSD__) || defined(__sun__) || (defined(__MACH__) && defined(__APPLE__)) #define USE_NANOSLEEP #elif defined(HAVE_PTHREADS) && defined(sgi) // SGI pthreads has a bug when using pthreads+signals+nanosleep, @@ -297,3 +324,78 @@ void Delay_usec(uint32 usec) #endif } while (was_error && (errno == EINTR)); } + + +/* + * Suspend emulator thread, virtual CPU in idle mode + */ + +#ifdef HAVE_PTHREADS +#if defined(HAVE_PTHREAD_COND_INIT) +#define IDLE_USES_COND_WAIT 1 +static pthread_mutex_t idle_lock = PTHREAD_MUTEX_INITIALIZER; +static pthread_cond_t idle_cond = PTHREAD_COND_INITIALIZER; +#elif defined(HAVE_SEM_INIT) +#define IDLE_USES_SEMAPHORE 1 +#include +#ifdef HAVE_SPINLOCKS +static spinlock_t idle_lock = SPIN_LOCK_UNLOCKED; +#define LOCK_IDLE spin_lock(&idle_lock) +#define UNLOCK_IDLE spin_unlock(&idle_lock) +#else +static pthread_mutex_t idle_lock = PTHREAD_MUTEX_INITIALIZER; +#define LOCK_IDLE pthread_mutex_lock(&idle_lock) +#define UNLOCK_IDLE pthread_mutex_unlock(&idle_lock) +#endif +static sem_t idle_sem; +static int idle_sem_ok = -1; +#endif +#endif + +void idle_wait(void) +{ +#ifdef IDLE_USES_COND_WAIT + pthread_mutex_lock(&idle_lock); + pthread_cond_wait(&idle_cond, &idle_lock); + pthread_mutex_unlock(&idle_lock); +#else +#ifdef IDLE_USES_SEMAPHORE + LOCK_IDLE; + if (idle_sem_ok < 0) + idle_sem_ok = (sem_init(&idle_sem, 0, 0) == 0); + if (idle_sem_ok > 0) { + idle_sem_ok++; + UNLOCK_IDLE; + sem_wait(&idle_sem); + return; + } + UNLOCK_IDLE; +#endif + + // Fallback: sleep 10 ms + Delay_usec(10000); +#endif +} + + +/* + * Resume execution of emulator thread, events just arrived + */ + +void idle_resume(void) +{ +#ifdef IDLE_USES_COND_WAIT + pthread_cond_signal(&idle_cond); +#else +#ifdef IDLE_USES_SEMAPHORE + LOCK_IDLE; + if (idle_sem_ok > 1) { + idle_sem_ok--; + UNLOCK_IDLE; + sem_post(&idle_sem); + return; + } + UNLOCK_IDLE; +#endif +#endif +}