--- BasiliskII/src/Unix/timer_unix.cpp 2004/01/12 15:29:25 1.14 +++ BasiliskII/src/Unix/timer_unix.cpp 2006/05/01 13:13:18 1.19 @@ -1,7 +1,7 @@ /* * timer_unix.cpp - Time Manager emulation, Unix specific stuff * - * Basilisk II (C) 1997-2004 Christian Bauer + * Basilisk II (C) 1997-2005 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 @@ -228,7 +228,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 +297,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 +}