1 |
|
/* |
2 |
|
* timer.cpp - Time Manager emulation |
3 |
|
* |
4 |
< |
* SheepShaver (C) 1997-2005 Christian Bauer and Marc Hellwig |
4 |
> |
* SheepShaver (C) 1997-2008 Christian Bauer and Marc Hellwig |
5 |
|
* |
6 |
|
* This program is free software; you can redistribute it and/or modify |
7 |
|
* it under the terms of the GNU General Public License as published by |
74 |
|
static volatile bool timer_thread_cancel = false; |
75 |
|
static tm_time_t wakeup_time_max = { 0x7fffffff, 999999999 }; |
76 |
|
static tm_time_t wakeup_time = wakeup_time_max; |
77 |
< |
static sem_t wakeup_time_sem; |
77 |
> |
static pthread_mutex_t wakeup_time_lock = PTHREAD_MUTEX_INITIALIZER; |
78 |
|
static void *timer_func(void *arg); |
79 |
|
#endif |
80 |
|
#endif |
185 |
|
static bool timer_thread_init(void) |
186 |
|
{ |
187 |
|
// Install suspend signal handler |
188 |
< |
sigfillset(&sigsuspend_action.sa_mask); |
188 |
> |
sigemptyset(&sigsuspend_action.sa_mask); |
189 |
> |
sigaddset(&sigsuspend_action.sa_mask, SIGRESUME); |
190 |
|
sigsuspend_action.sa_handler = sigsuspend_handler; |
191 |
|
sigsuspend_action.sa_flags = SA_RESTART; |
192 |
|
#ifdef HAVE_SIGNAL_SA_RESTORER |
196 |
|
return false; |
197 |
|
|
198 |
|
// Install resume signal handler |
199 |
< |
sigfillset(&sigresume_action.sa_mask); |
199 |
> |
sigemptyset(&sigresume_action.sa_mask); |
200 |
|
sigresume_action.sa_handler = sigresume_handler; |
201 |
|
sigresume_action.sa_flags = SA_RESTART; |
202 |
|
#ifdef HAVE_SIGNAL_SA_RESTORER |
274 |
|
resume_thread(timer_thread); |
275 |
|
#endif |
276 |
|
#ifdef PRECISE_TIMING_POSIX |
276 |
– |
sem_init(&wakeup_time_sem, 0, 1); |
277 |
|
timer_thread_active = timer_thread_init(); |
278 |
|
#endif |
279 |
|
#endif |
299 |
|
#endif |
300 |
|
#ifdef PRECISE_TIMING_POSIX |
301 |
|
timer_thread_kill(); |
302 |
– |
sem_destroy(&wakeup_time_sem); |
302 |
|
#endif |
303 |
|
} |
304 |
|
#endif |
357 |
|
suspend_thread(timer_thread); |
358 |
|
#endif |
359 |
|
#if PRECISE_TIMING_POSIX |
361 |
– |
sem_wait(&wakeup_time_sem); |
360 |
|
timer_thread_suspend(); |
361 |
+ |
pthread_mutex_lock(&wakeup_time_lock); |
362 |
|
#endif |
363 |
|
if (ReadMacInt16(tm + qType) & 0x8000) { |
364 |
|
|
392 |
|
} while (info.state == B_THREAD_SUSPENDED); // Sometimes, resume_thread() doesn't work (BeOS bug?) |
393 |
|
#endif |
394 |
|
#if PRECISE_TIMING_POSIX |
395 |
< |
sem_post(&wakeup_time_sem); |
395 |
> |
pthread_mutex_unlock(&wakeup_time_lock); |
396 |
|
timer_thread_resume(); |
397 |
|
assert(suspend_count == 0); |
398 |
|
#endif |
428 |
|
// Yes, tmWakeUp set? |
429 |
|
if (ReadMacInt32(tm + tmWakeUp)) { |
430 |
|
|
431 |
+ |
// PrimeTime(0) can either mean (a) "the task runs as soon as interrupts are enabled" |
432 |
+ |
// or (b) "continue previous delay" if an expired task was stopped via RmvTime() and |
433 |
+ |
// then re-installed using InsXTime(). This currently only handles (a). |
434 |
+ |
// |
435 |
+ |
// API reference: http://developer.apple.com/documentation/mac/Processes/Processes-68.html |
436 |
+ |
|
437 |
+ |
#if 0 |
438 |
|
//!! PrimeTime(0) means continue previous delay |
439 |
|
// (save wakeup time in RmvTime?) |
440 |
|
if (time == 0) { |
441 |
|
printf("FATAL: Unsupported PrimeTime(0)\n"); |
442 |
|
return 0; |
443 |
|
} |
444 |
+ |
#endif |
445 |
|
|
446 |
|
// Yes, calculate wakeup time relative to last scheduled time |
447 |
|
tm_time_t wakeup; |
473 |
|
suspend_thread(timer_thread); |
474 |
|
#endif |
475 |
|
#if PRECISE_TIMING_POSIX |
469 |
– |
sem_wait(&wakeup_time_sem); |
476 |
|
timer_thread_suspend(); |
477 |
+ |
pthread_mutex_lock(&wakeup_time_lock); |
478 |
|
#endif |
479 |
|
WriteMacInt16(tm + qType, ReadMacInt16(tm + qType) | 0x8000); |
480 |
|
enqueue_tm(tm); |
495 |
|
} while (info.state == B_THREAD_SUSPENDED); // Sometimes, resume_thread() doesn't work (BeOS bug?) |
496 |
|
#endif |
497 |
|
#ifdef PRECISE_TIMING_POSIX |
498 |
< |
sem_post(&wakeup_time_sem); |
498 |
> |
pthread_mutex_unlock(&wakeup_time_lock); |
499 |
|
timer_thread_resume(); |
500 |
|
assert(suspend_count == 0); |
501 |
|
#endif |
538 |
|
// Wait until time specified by wakeup_time |
539 |
|
clock_nanosleep(CLOCK_REALTIME, TIMER_ABSTIME, &wakeup_time, NULL); |
540 |
|
|
534 |
– |
sem_wait(&wakeup_time_sem); |
541 |
|
tm_time_t system_time; |
542 |
|
timer_current_time(system_time); |
543 |
|
if (timer_cmp_time(wakeup_time, system_time) < 0) { |
544 |
|
|
545 |
|
// Timer expired, trigger interrupt |
546 |
+ |
pthread_mutex_lock(&wakeup_time_lock); |
547 |
|
wakeup_time = wakeup_time_max; |
548 |
+ |
pthread_mutex_unlock(&wakeup_time_lock); |
549 |
|
SetInterruptFlag(INTFLAG_TIMER); |
550 |
|
TriggerInterrupt(); |
551 |
|
} |
544 |
– |
sem_post(&wakeup_time_sem); |
552 |
|
} |
553 |
|
return NULL; |
554 |
|
} |
595 |
|
suspend_thread(timer_thread); |
596 |
|
#endif |
597 |
|
#if PRECISE_TIMING_POSIX |
591 |
– |
sem_wait(&wakeup_time_sem); |
598 |
|
timer_thread_suspend(); |
599 |
+ |
pthread_mutex_lock(&wakeup_time_lock); |
600 |
|
#endif |
601 |
|
wakeup_time = wakeup_time_max; |
602 |
|
for (int j=0; j<NUM_DESCS; j++) { |
613 |
|
} while (info.state == B_THREAD_SUSPENDED); // Sometimes, resume_thread() doesn't work (BeOS bug?) |
614 |
|
#endif |
615 |
|
#if PRECISE_TIMING_POSIX |
616 |
< |
sem_post(&wakeup_time_sem); |
616 |
> |
pthread_mutex_unlock(&wakeup_time_lock); |
617 |
|
timer_thread_resume(); |
618 |
|
assert(suspend_count == 0); |
619 |
|
#endif |