--- SheepShaver/src/timer.cpp 2005/03/05 19:07:35 1.4 +++ SheepShaver/src/timer.cpp 2009/07/31 20:43:28 1.10 @@ -1,7 +1,7 @@ /* * timer.cpp - Time Manager emulation * - * SheepShaver (C) 1997-2005 Christian Bauer and Marc Hellwig + * SheepShaver (C) 1997-2008 Christian Bauer and Marc Hellwig * * 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 @@ -18,10 +18,6 @@ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ -/* - * TODO: Prime(0) - */ - #include "sysdeps.h" #include "timer.h" #include "macos_util.h" @@ -70,10 +66,11 @@ static int32 timer_func(void *arg); #endif #ifdef PRECISE_TIMING_POSIX static pthread_t timer_thread; -static volatile bool thread_active = false; +static bool timer_thread_active = false; +static volatile bool timer_thread_cancel = false; static tm_time_t wakeup_time_max = { 0x7fffffff, 999999999 }; static tm_time_t wakeup_time = wakeup_time_max; -static sem_t wakeup_time_sem; +static pthread_mutex_t wakeup_time_lock = PTHREAD_MUTEX_INITIALIZER; static void *timer_func(void *arg); #endif #endif @@ -165,16 +162,13 @@ static struct sigaction sigresume_action static int suspend_count = 0; static pthread_mutex_t suspend_count_lock = PTHREAD_MUTEX_INITIALIZER; static sem_t suspend_ack_sem; +static sigset_t suspend_handler_mask; // Signal handler for suspended thread static void sigsuspend_handler(int sig) { sem_post(&suspend_ack_sem); - - sigset_t mask; - sigfillset(&mask); - sigdelset(&mask, SIGRESUME); - sigsuspend(&mask); + sigsuspend(&suspend_handler_mask); } // Signal handler for resumed thread @@ -187,7 +181,8 @@ static void sigresume_handler(int sig) static bool timer_thread_init(void) { // Install suspend signal handler - sigfillset(&sigsuspend_action.sa_mask); + sigemptyset(&sigsuspend_action.sa_mask); + sigaddset(&sigsuspend_action.sa_mask, SIGRESUME); sigsuspend_action.sa_handler = sigsuspend_handler; sigsuspend_action.sa_flags = SA_RESTART; #ifdef HAVE_SIGNAL_SA_RESTORER @@ -197,7 +192,7 @@ static bool timer_thread_init(void) return false; // Install resume signal handler - sigfillset(&sigresume_action.sa_mask); + sigemptyset(&sigresume_action.sa_mask); sigresume_action.sa_handler = sigresume_handler; sigresume_action.sa_flags = SA_RESTART; #ifdef HAVE_SIGNAL_SA_RESTORER @@ -210,6 +205,12 @@ static bool timer_thread_init(void) if (sem_init(&suspend_ack_sem, 0, 0) < 0) return false; + // Initialize suspend_handler_mask, it excludes SIGRESUME + if (sigfillset(&suspend_handler_mask) != 0) + return false; + if (sigdelset(&suspend_handler_mask, SIGRESUME) != 0) + return false; + // Create thread in running state suspend_count = 0; return (pthread_create(&timer_thread, NULL, timer_func, NULL) == 0); @@ -218,6 +219,7 @@ static bool timer_thread_init(void) // Kill timer thread static void timer_thread_kill(void) { + timer_thread_cancel = true; #ifdef HAVE_PTHREAD_CANCEL pthread_cancel(timer_thread); #endif @@ -268,8 +270,7 @@ void TimerInit(void) resume_thread(timer_thread); #endif #ifdef PRECISE_TIMING_POSIX - sem_init(&wakeup_time_sem, 0, 1); - thread_active = timer_thread_init(); + timer_thread_active = timer_thread_init(); #endif #endif } @@ -293,9 +294,7 @@ void TimerExit(void) delete_sem(wakeup_time_sem); #endif #ifdef PRECISE_TIMING_POSIX - thread_active = false; timer_thread_kill(); - sem_destroy(&wakeup_time_sem); #endif } #endif @@ -354,8 +353,8 @@ int16 RmvTime(uint32 tm) suspend_thread(timer_thread); #endif #if PRECISE_TIMING_POSIX - sem_wait(&wakeup_time_sem); timer_thread_suspend(); + pthread_mutex_lock(&wakeup_time_lock); #endif if (ReadMacInt16(tm + qType) & 0x8000) { @@ -389,7 +388,7 @@ int16 RmvTime(uint32 tm) } while (info.state == B_THREAD_SUSPENDED); // Sometimes, resume_thread() doesn't work (BeOS bug?) #endif #if PRECISE_TIMING_POSIX - sem_post(&wakeup_time_sem); + pthread_mutex_unlock(&wakeup_time_lock); timer_thread_resume(); assert(suspend_count == 0); #endif @@ -425,12 +424,11 @@ int16 PrimeTime(uint32 tm, int32 time) // Yes, tmWakeUp set? if (ReadMacInt32(tm + tmWakeUp)) { - //!! PrimeTime(0) means continue previous delay - // (save wakeup time in RmvTime?) - if (time == 0) { - printf("FATAL: Unsupported PrimeTime(0)\n"); - return 0; - } + // PrimeTime(0) can either mean (a) "the task runs as soon as interrupts are enabled" + // or (b) "continue previous delay" if an expired task was stopped via RmvTime() and + // then re-installed using InsXTime(). Since tmWakeUp was set, this is case (b). + // The remaining time was saved in tmCount by RmvTime(). + timer_mac2host_time(delay, ReadMacInt16(tm + tmCount)); // Yes, calculate wakeup time relative to last scheduled time tm_time_t wakeup; @@ -462,8 +460,8 @@ int16 PrimeTime(uint32 tm, int32 time) suspend_thread(timer_thread); #endif #if PRECISE_TIMING_POSIX - sem_wait(&wakeup_time_sem); timer_thread_suspend(); + pthread_mutex_lock(&wakeup_time_lock); #endif WriteMacInt16(tm + qType, ReadMacInt16(tm + qType) | 0x8000); enqueue_tm(tm); @@ -484,7 +482,7 @@ int16 PrimeTime(uint32 tm, int32 time) } while (info.state == B_THREAD_SUSPENDED); // Sometimes, resume_thread() doesn't work (BeOS bug?) #endif #ifdef PRECISE_TIMING_POSIX - sem_post(&wakeup_time_sem); + pthread_mutex_unlock(&wakeup_time_lock); timer_thread_resume(); assert(suspend_count == 0); #endif @@ -522,22 +520,22 @@ static int32 timer_func(void *arg) #ifdef PRECISE_TIMING_POSIX static void *timer_func(void *arg) { - while (thread_active) { + while (!timer_thread_cancel) { // Wait until time specified by wakeup_time clock_nanosleep(CLOCK_REALTIME, TIMER_ABSTIME, &wakeup_time, NULL); - sem_wait(&wakeup_time_sem); tm_time_t system_time; timer_current_time(system_time); if (timer_cmp_time(wakeup_time, system_time) < 0) { // Timer expired, trigger interrupt + pthread_mutex_lock(&wakeup_time_lock); wakeup_time = wakeup_time_max; + pthread_mutex_unlock(&wakeup_time_lock); SetInterruptFlag(INTFLAG_TIMER); TriggerInterrupt(); } - sem_post(&wakeup_time_sem); } return NULL; } @@ -584,8 +582,8 @@ void TimerInterrupt(void) suspend_thread(timer_thread); #endif #if PRECISE_TIMING_POSIX - sem_wait(&wakeup_time_sem); timer_thread_suspend(); + pthread_mutex_lock(&wakeup_time_lock); #endif wakeup_time = wakeup_time_max; for (int j=0; j