ViewVC Help
View File | Revision Log | Show Annotations | Revision Graph | Root Listing
root/cebix/SheepShaver/src/timer.cpp
Revision: 1.15
Committed: 2011-12-28T18:14:58Z (12 years, 4 months ago) by asvitkine
Branch: MAIN
CVS Tags: HEAD
Changes since 1.14: +1 -1 lines
Log Message:
don't deref desc after deleting it!

File Contents

# User Rev Content
1 cebix 1.1 /*
2     * timer.cpp - Time Manager emulation
3     *
4 gbeauche 1.8 * SheepShaver (C) 1997-2008 Christian Bauer and Marc Hellwig
5 cebix 1.1 *
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
8     * the Free Software Foundation; either version 2 of the License, or
9     * (at your option) any later version.
10     *
11     * This program is distributed in the hope that it will be useful,
12     * but WITHOUT ANY WARRANTY; without even the implied warranty of
13     * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14     * GNU General Public License for more details.
15     *
16     * You should have received a copy of the GNU General Public License
17     * along with this program; if not, write to the Free Software
18     * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
19     */
20    
21     #include "sysdeps.h"
22     #include "timer.h"
23     #include "macos_util.h"
24     #include "main.h"
25     #include "cpu_emulation.h"
26    
27 gbeauche 1.4 #ifdef PRECISE_TIMING_POSIX
28     #include <pthread.h>
29     #include <semaphore.h>
30     #endif
31    
32 asvitkine 1.12 #ifdef PRECISE_TIMING_MACH
33     #include <mach/mach.h>
34     #endif
35    
36 cebix 1.1 #define DEBUG 0
37     #include "debug.h"
38    
39    
40     #define TM_QUEUE 0 // Enable TMQueue management (doesn't work)
41    
42    
43     // Definitions for Time Manager
44     enum { // TMTask struct
45     tmAddr = 6,
46     tmCount = 10,
47     tmWakeUp = 14,
48     tmReserved = 18
49     };
50    
51    
52     // Array of additional info for each installed TMTask
53     struct TMDesc {
54     uint32 task; // Mac address of associated TMTask
55     tm_time_t wakeup; // Time this task is scheduled for execution
56 asvitkine 1.13 TMDesc *next;
57 cebix 1.1 };
58    
59 asvitkine 1.13 static TMDesc *tmDescList;
60 cebix 1.1
61     #if PRECISE_TIMING
62 gbeauche 1.4 #ifdef PRECISE_TIMING_BEOS
63 cebix 1.1 static thread_id timer_thread = -1;
64     static bool thread_active = true;
65 gbeauche 1.4 static const tm_time_t wakeup_time_max = 0x7fffffffffffffff;
66     static volatile tm_time_t wakeup_time = wakeup_time_max;
67 cebix 1.1 static sem_id wakeup_time_sem = -1;
68     static int32 timer_func(void *arg);
69     #endif
70 gbeauche 1.4 #ifdef PRECISE_TIMING_POSIX
71     static pthread_t timer_thread;
72 gbeauche 1.5 static bool timer_thread_active = false;
73     static volatile bool timer_thread_cancel = false;
74 gbeauche 1.4 static tm_time_t wakeup_time_max = { 0x7fffffff, 999999999 };
75     static tm_time_t wakeup_time = wakeup_time_max;
76 gbeauche 1.6 static pthread_mutex_t wakeup_time_lock = PTHREAD_MUTEX_INITIALIZER;
77 gbeauche 1.4 static void *timer_func(void *arg);
78     #endif
79 asvitkine 1.12 #ifdef PRECISE_TIMING_MACH
80     static clock_serv_t system_clock;
81     static thread_act_t timer_thread;
82     static bool timer_thread_active = false;
83     static tm_time_t wakeup_time_max = { 0x7fffffff, 999999999 };
84     static tm_time_t wakeup_time = wakeup_time_max;
85     static semaphore_t wakeup_time_sem;
86     static void *timer_func(void *arg);
87     #endif
88 gbeauche 1.4 #endif
89 cebix 1.1
90    
91 asvitkine 1.13 inline static void free_desc(TMDesc *desc)
92 cebix 1.1 {
93 asvitkine 1.13 if (desc == tmDescList) {
94     tmDescList = desc->next;
95     } else {
96     for (TMDesc *d = tmDescList; d; d = d->next) {
97     if (d->next == desc) {
98     d->next = desc->next;
99     break;
100     }
101 cebix 1.1 }
102 asvitkine 1.13 }
103     delete desc;
104 cebix 1.1 }
105    
106     /*
107     * Find descriptor associated with given TMTask
108     */
109    
110 asvitkine 1.13 inline static TMDesc *find_desc(uint32 tm)
111 cebix 1.1 {
112 asvitkine 1.13 TMDesc *desc = tmDescList;
113     while (desc) {
114     if (desc->task == tm) {
115     return desc;
116     }
117     desc = desc->next;
118     }
119     return NULL;
120 cebix 1.1 }
121    
122    
123     /*
124     * Enqueue task in Time Manager queue
125     */
126    
127     static void enqueue_tm(uint32 tm)
128     {
129     #if TM_QUEUE
130     uint32 tm_var = ReadMacInt32(0xb30);
131     WriteMacInt32(tm + qLink, ReadMacInt32(tm_var));
132     WriteMacInt32(tm_var, tm);
133     #endif
134     }
135    
136    
137     /*
138     * Remove task from Time Manager queue
139     */
140    
141     static void dequeue_tm(uint32 tm)
142     {
143     #if TM_QUEUE
144     uint32 p = ReadMacInt32(0xb30);
145     while (p) {
146     uint32 next = ReadMacInt32(p + qLink);
147     if (next == tm) {
148     WriteMacInt32(p + qLink, ReadMacInt32(next + qLink));
149     return;
150     }
151     }
152     #endif
153     }
154    
155    
156     /*
157 gbeauche 1.4 * Timer thread operations
158     */
159    
160     #ifdef PRECISE_TIMING_POSIX
161     const int SIGSUSPEND = SIGRTMIN + 6;
162     const int SIGRESUME = SIGRTMIN + 7;
163     static struct sigaction sigsuspend_action;
164     static struct sigaction sigresume_action;
165    
166     static int suspend_count = 0;
167     static pthread_mutex_t suspend_count_lock = PTHREAD_MUTEX_INITIALIZER;
168     static sem_t suspend_ack_sem;
169 gbeauche 1.5 static sigset_t suspend_handler_mask;
170 gbeauche 1.4
171     // Signal handler for suspended thread
172     static void sigsuspend_handler(int sig)
173     {
174     sem_post(&suspend_ack_sem);
175 gbeauche 1.5 sigsuspend(&suspend_handler_mask);
176 gbeauche 1.4 }
177    
178     // Signal handler for resumed thread
179     static void sigresume_handler(int sig)
180     {
181     /* simply trigger a signal to stop clock_nanosleep() */
182     }
183    
184     // Initialize timer thread
185     static bool timer_thread_init(void)
186     {
187     // Install suspend signal handler
188 gbeauche 1.6 sigemptyset(&sigsuspend_action.sa_mask);
189     sigaddset(&sigsuspend_action.sa_mask, SIGRESUME);
190 gbeauche 1.4 sigsuspend_action.sa_handler = sigsuspend_handler;
191     sigsuspend_action.sa_flags = SA_RESTART;
192     #ifdef HAVE_SIGNAL_SA_RESTORER
193     sigsuspend_action.sa_restorer = NULL;
194     #endif
195     if (sigaction(SIGSUSPEND, &sigsuspend_action, NULL) < 0)
196     return false;
197    
198     // Install resume signal handler
199 gbeauche 1.6 sigemptyset(&sigresume_action.sa_mask);
200 gbeauche 1.4 sigresume_action.sa_handler = sigresume_handler;
201     sigresume_action.sa_flags = SA_RESTART;
202     #ifdef HAVE_SIGNAL_SA_RESTORER
203     sigresume_action.sa_restorer = NULL;
204     #endif
205     if (sigaction(SIGRESUME, &sigresume_action, NULL) < 0)
206     return false;
207    
208     // Initialize semaphore
209     if (sem_init(&suspend_ack_sem, 0, 0) < 0)
210     return false;
211    
212 gbeauche 1.5 // Initialize suspend_handler_mask, it excludes SIGRESUME
213     if (sigfillset(&suspend_handler_mask) != 0)
214     return false;
215     if (sigdelset(&suspend_handler_mask, SIGRESUME) != 0)
216     return false;
217    
218 gbeauche 1.4 // Create thread in running state
219     suspend_count = 0;
220     return (pthread_create(&timer_thread, NULL, timer_func, NULL) == 0);
221     }
222    
223     // Kill timer thread
224     static void timer_thread_kill(void)
225     {
226 gbeauche 1.5 timer_thread_cancel = true;
227 gbeauche 1.4 #ifdef HAVE_PTHREAD_CANCEL
228     pthread_cancel(timer_thread);
229     #endif
230     pthread_join(timer_thread, NULL);
231     }
232    
233     // Suspend timer thread
234     static void timer_thread_suspend(void)
235     {
236     pthread_mutex_lock(&suspend_count_lock);
237     if (suspend_count == 0) {
238     suspend_count ++;
239     if (pthread_kill(timer_thread, SIGSUSPEND) == 0)
240     sem_wait(&suspend_ack_sem);
241     }
242     pthread_mutex_unlock(&suspend_count_lock);
243     }
244    
245     // Resume timer thread
246     static void timer_thread_resume(void)
247     {
248     pthread_mutex_lock(&suspend_count_lock);
249     assert(suspend_count > 0);
250     if (suspend_count == 1) {
251     suspend_count = 0;
252     pthread_kill(timer_thread, SIGRESUME);
253     }
254     pthread_mutex_unlock(&suspend_count_lock);
255     }
256     #endif
257    
258    
259     /*
260 cebix 1.1 * Initialize Time Manager
261     */
262    
263     void TimerInit(void)
264     {
265 asvitkine 1.13 TimerReset();
266 cebix 1.1
267     #if PRECISE_TIMING
268     // Start timer thread
269 gbeauche 1.4 #ifdef PRECISE_TIMING_BEOS
270 cebix 1.1 wakeup_time_sem = create_sem(1, "Wakeup Time");
271     timer_thread = spawn_thread(timer_func, "Time Manager", B_REAL_TIME_PRIORITY, NULL);
272     resume_thread(timer_thread);
273 asvitkine 1.12 #elif PRECISE_TIMING_MACH
274     pthread_t pthread;
275    
276     host_get_clock_service(mach_host_self(), REALTIME_CLOCK, &system_clock);
277     semaphore_create(mach_task_self(), &wakeup_time_sem, SYNC_POLICY_FIFO, 1);
278    
279     pthread_create(&pthread, NULL, &timer_func, NULL);
280 cebix 1.1 #endif
281 gbeauche 1.4 #ifdef PRECISE_TIMING_POSIX
282 gbeauche 1.5 timer_thread_active = timer_thread_init();
283 gbeauche 1.4 #endif
284     #endif
285 cebix 1.1 }
286    
287    
288     /*
289     * Exit Time Manager
290     */
291    
292     void TimerExit(void)
293     {
294     #if PRECISE_TIMING
295     // Quit timer thread
296     if (timer_thread > 0) {
297 gbeauche 1.4 #ifdef PRECISE_TIMING_BEOS
298 cebix 1.1 status_t l;
299     thread_active = false;
300     suspend_thread(timer_thread);
301     resume_thread(timer_thread);
302     wait_for_thread(timer_thread, &l);
303     delete_sem(wakeup_time_sem);
304 gbeauche 1.4 #endif
305 asvitkine 1.12 #ifdef PRECISE_TIMING_MACH
306     timer_thread_active = false;
307     semaphore_destroy(mach_task_self(), wakeup_time_sem);
308     #endif
309 gbeauche 1.4 #ifdef PRECISE_TIMING_POSIX
310     timer_thread_kill();
311     #endif
312 cebix 1.1 }
313     #endif
314     }
315    
316    
317     /*
318     * Emulator reset, remove all timer tasks
319     */
320    
321     void TimerReset(void)
322     {
323 asvitkine 1.13 TMDesc *desc = tmDescList;
324     while (desc) {
325     TMDesc *next = desc->next;
326     delete desc;
327 asvitkine 1.15 desc = next;
328 asvitkine 1.13 }
329     tmDescList = NULL;
330 cebix 1.1 }
331    
332    
333     /*
334     * Insert timer task
335     */
336    
337     int16 InsTime(uint32 tm, uint16 trap)
338     {
339     D(bug("InsTime %08lx, trap %04x\n", tm, trap));
340     WriteMacInt16((uint32)tm + qType, ReadMacInt16((uint32)tm + qType) & 0x1fff | (trap << 4) & 0x6000);
341 asvitkine 1.13 if (find_desc(tm))
342     printf("WARNING: InsTime(%08lx): Task re-inserted\n", tm);
343 cebix 1.1 else {
344 asvitkine 1.13 TMDesc *desc = new TMDesc;
345     desc->task = tm;
346     desc->next = tmDescList;
347     tmDescList = desc;
348 cebix 1.1 }
349     return 0;
350     }
351    
352    
353     /*
354     * Remove timer task
355     */
356    
357     int16 RmvTime(uint32 tm)
358     {
359     D(bug("RmvTime %08lx\n", tm));
360    
361     // Find descriptor
362 asvitkine 1.13 TMDesc *desc = find_desc(tm);
363     if (!desc) {
364 cebix 1.1 printf("WARNING: RmvTime(%08lx): Descriptor not found\n", tm);
365     return 0;
366     }
367    
368     // Task active?
369 gbeauche 1.4 #if PRECISE_TIMING_BEOS
370 cebix 1.1 while (acquire_sem(wakeup_time_sem) == B_INTERRUPTED) ;
371     suspend_thread(timer_thread);
372     #endif
373 asvitkine 1.12 #ifdef PRECISE_TIMING_MACH
374     semaphore_wait(wakeup_time_sem);
375     thread_suspend(timer_thread);
376     #endif
377 gbeauche 1.4 #if PRECISE_TIMING_POSIX
378     timer_thread_suspend();
379 gbeauche 1.6 pthread_mutex_lock(&wakeup_time_lock);
380 gbeauche 1.4 #endif
381 cebix 1.1 if (ReadMacInt16(tm + qType) & 0x8000) {
382    
383     // Yes, make task inactive and remove it from the Time Manager queue
384     WriteMacInt16(tm + qType, ReadMacInt16(tm + qType) & 0x7fff);
385     dequeue_tm(tm);
386     #if PRECISE_TIMING
387     // Look for next task to be called and set wakeup_time
388 gbeauche 1.4 wakeup_time = wakeup_time_max;
389 asvitkine 1.13 for (TMDesc *d = tmDescList; d; d = d->next)
390     if ((ReadMacInt16(d->task + qType) & 0x8000))
391     if (timer_cmp_time(d->wakeup, wakeup_time) < 0)
392     wakeup_time = d->wakeup;
393 cebix 1.1 #endif
394    
395     // Compute remaining time
396     tm_time_t remaining, current;
397     timer_current_time(current);
398 asvitkine 1.13 timer_sub_time(remaining, desc->wakeup, current);
399 cebix 1.1 WriteMacInt32(tm + tmCount, timer_host2mac_time(remaining));
400     } else
401     WriteMacInt32(tm + tmCount, 0);
402     D(bug(" tmCount %ld\n", ReadMacInt32(tm + tmCount)));
403 gbeauche 1.4 #if PRECISE_TIMING_BEOS
404 cebix 1.1 release_sem(wakeup_time_sem);
405     thread_info info;
406     do {
407     resume_thread(timer_thread); // This will unblock the thread
408     get_thread_info(timer_thread, &info);
409     } while (info.state == B_THREAD_SUSPENDED); // Sometimes, resume_thread() doesn't work (BeOS bug?)
410     #endif
411 asvitkine 1.12 #ifdef PRECISE_TIMING_MACH
412     semaphore_signal(wakeup_time_sem);
413     thread_abort(timer_thread);
414     thread_resume(timer_thread);
415     #endif
416 gbeauche 1.4 #if PRECISE_TIMING_POSIX
417 gbeauche 1.6 pthread_mutex_unlock(&wakeup_time_lock);
418 gbeauche 1.4 timer_thread_resume();
419     assert(suspend_count == 0);
420     #endif
421 cebix 1.1
422     // Free descriptor
423 asvitkine 1.13 free_desc(desc);
424 cebix 1.1 return 0;
425     }
426    
427    
428     /*
429     * Start timer task
430     */
431    
432     int16 PrimeTime(uint32 tm, int32 time)
433     {
434     D(bug("PrimeTime %08lx, time %ld\n", tm, time));
435    
436     // Find descriptor
437 asvitkine 1.13 TMDesc *desc = find_desc(tm);
438     if (!desc) {
439     printf("FATAL: PrimeTime(%08lx): Descriptor not found\n", tm);
440 cebix 1.1 return 0;
441     }
442    
443     // Convert delay time
444     tm_time_t delay;
445     timer_mac2host_time(delay, time);
446    
447     // Extended task?
448     if (ReadMacInt16(tm + qType) & 0x4000) {
449    
450     // Yes, tmWakeUp set?
451     if (ReadMacInt32(tm + tmWakeUp)) {
452    
453 asvitkine 1.9 // PrimeTime(0) can either mean (a) "the task runs as soon as interrupts are enabled"
454     // or (b) "continue previous delay" if an expired task was stopped via RmvTime() and
455 asvitkine 1.10 // then re-installed using InsXTime(). Since tmWakeUp was set, this is case (b).
456     // The remaining time was saved in tmCount by RmvTime().
457 asvitkine 1.11 if (time == 0) {
458     timer_mac2host_time(delay, ReadMacInt16(tm + tmCount));
459     }
460 cebix 1.1
461     // Yes, calculate wakeup time relative to last scheduled time
462     tm_time_t wakeup;
463 asvitkine 1.13 timer_add_time(wakeup, desc->wakeup, delay);
464     desc->wakeup = wakeup;
465 cebix 1.1
466     } else {
467    
468     // No, calculate wakeup time relative to current time
469     tm_time_t now;
470     timer_current_time(now);
471 asvitkine 1.13 timer_add_time(desc->wakeup, now, delay);
472 cebix 1.1 }
473    
474     // Set tmWakeUp to indicate that task was scheduled
475     WriteMacInt32(tm + tmWakeUp, 0x12345678);
476    
477     } else {
478    
479     // Not extended task, calculate wakeup time relative to current time
480     tm_time_t now;
481     timer_current_time(now);
482 asvitkine 1.13 timer_add_time(desc->wakeup, now, delay);
483 cebix 1.1 }
484    
485     // Make task active and enqueue it in the Time Manager queue
486 gbeauche 1.4 #if PRECISE_TIMING_BEOS
487 cebix 1.1 while (acquire_sem(wakeup_time_sem) == B_INTERRUPTED) ;
488     suspend_thread(timer_thread);
489     #endif
490 asvitkine 1.12 #ifdef PRECISE_TIMING_MACH
491     semaphore_wait(wakeup_time_sem);
492     thread_suspend(timer_thread);
493     #endif
494 gbeauche 1.4 #if PRECISE_TIMING_POSIX
495     timer_thread_suspend();
496 gbeauche 1.6 pthread_mutex_lock(&wakeup_time_lock);
497 gbeauche 1.4 #endif
498 cebix 1.1 WriteMacInt16(tm + qType, ReadMacInt16(tm + qType) | 0x8000);
499     enqueue_tm(tm);
500     #if PRECISE_TIMING
501     // Look for next task to be called and set wakeup_time
502 gbeauche 1.4 wakeup_time = wakeup_time_max;
503 asvitkine 1.13 for (TMDesc *d = tmDescList; d; d = d->next)
504     if ((ReadMacInt16(d->task + qType) & 0x8000))
505     if (timer_cmp_time(d->wakeup, wakeup_time) < 0)
506     wakeup_time = d->wakeup;
507 gbeauche 1.4 #ifdef PRECISE_TIMING_BEOS
508 cebix 1.1 release_sem(wakeup_time_sem);
509     thread_info info;
510     do {
511     resume_thread(timer_thread); // This will unblock the thread
512     get_thread_info(timer_thread, &info);
513     } while (info.state == B_THREAD_SUSPENDED); // Sometimes, resume_thread() doesn't work (BeOS bug?)
514     #endif
515 asvitkine 1.12 #ifdef PRECISE_TIMING_MACH
516     semaphore_signal(wakeup_time_sem);
517     thread_abort(timer_thread);
518     thread_resume(timer_thread);
519     #endif
520 gbeauche 1.4 #ifdef PRECISE_TIMING_POSIX
521 gbeauche 1.6 pthread_mutex_unlock(&wakeup_time_lock);
522 gbeauche 1.4 timer_thread_resume();
523     assert(suspend_count == 0);
524     #endif
525     #endif
526 cebix 1.1 return 0;
527     }
528    
529    
530     /*
531     * Time Manager thread
532     */
533    
534 gbeauche 1.4 #ifdef PRECISE_TIMING_BEOS
535 cebix 1.1 static int32 timer_func(void *arg)
536     {
537     while (thread_active) {
538    
539     // Wait until time specified by wakeup_time
540     snooze_until(wakeup_time, B_SYSTEM_TIMEBASE);
541    
542     while (acquire_sem(wakeup_time_sem) == B_INTERRUPTED) ;
543     if (wakeup_time < system_time()) {
544    
545     // Timer expired, trigger interrupt
546     wakeup_time = 0x7fffffffffffffff;
547     SetInterruptFlag(INTFLAG_TIMER);
548     TriggerInterrupt();
549     }
550     release_sem(wakeup_time_sem);
551     }
552     return 0;
553     }
554     #endif
555    
556 asvitkine 1.12 #ifdef PRECISE_TIMING_MACH
557     static void *timer_func(void *arg)
558     {
559     timer_thread = mach_thread_self();
560     timer_thread_active = true;
561    
562     while (timer_thread_active) {
563     clock_sleep(system_clock, TIME_ABSOLUTE, wakeup_time, NULL);
564     semaphore_wait(wakeup_time_sem);
565    
566     tm_time_t system_time;
567    
568     timer_current_time(system_time);
569     if (timer_cmp_time(wakeup_time, system_time) < 0) {
570     wakeup_time = wakeup_time_max;
571     SetInterruptFlag(INTFLAG_TIMER);
572     TriggerInterrupt();
573     }
574     semaphore_signal(wakeup_time_sem);
575     }
576 asvitkine 1.14 return NULL;
577 asvitkine 1.12 }
578     #endif
579    
580 gbeauche 1.4 #ifdef PRECISE_TIMING_POSIX
581     static void *timer_func(void *arg)
582     {
583 gbeauche 1.5 while (!timer_thread_cancel) {
584 gbeauche 1.4 // Wait until time specified by wakeup_time
585     clock_nanosleep(CLOCK_REALTIME, TIMER_ABSTIME, &wakeup_time, NULL);
586    
587     tm_time_t system_time;
588     timer_current_time(system_time);
589     if (timer_cmp_time(wakeup_time, system_time) < 0) {
590    
591     // Timer expired, trigger interrupt
592 gbeauche 1.7 pthread_mutex_lock(&wakeup_time_lock);
593 gbeauche 1.4 wakeup_time = wakeup_time_max;
594 gbeauche 1.7 pthread_mutex_unlock(&wakeup_time_lock);
595 gbeauche 1.4 SetInterruptFlag(INTFLAG_TIMER);
596     TriggerInterrupt();
597     }
598     }
599     return NULL;
600     }
601     #endif
602    
603 cebix 1.1
604     /*
605     * Timer interrupt function (executed as part of 60Hz interrupt)
606     */
607    
608     void TimerInterrupt(void)
609     {
610     // D(bug("TimerIRQ\n"));
611    
612     // Look for active TMTasks that have expired
613     tm_time_t now;
614     timer_current_time(now);
615 asvitkine 1.13 TMDesc *desc = tmDescList;
616     while (desc) {
617     TMDesc *next = desc->next;
618     uint32 tm = desc->task;
619     if ((ReadMacInt16(tm + qType) & 0x8000) && timer_cmp_time(desc->wakeup, now) <= 0) {
620    
621     // Found one, mark as inactive and remove it from the Time Manager queue
622     WriteMacInt16(tm + qType, ReadMacInt16(tm + qType) & 0x7fff);
623     dequeue_tm(tm);
624    
625     // Call timer function
626     uint32 addr = ReadMacInt32(tm + tmAddr);
627     if (addr) {
628     D(bug("Calling TimeTask %08lx, addr %08lx\n", tm, addr));
629     M68kRegisters r;
630     r.a[0] = addr;
631     r.a[1] = tm;
632     Execute68k(r.a[0], &r);
633     D(bug(" returned from TimeTask\n"));
634 cebix 1.1 }
635     }
636 asvitkine 1.13 desc = next;
637     }
638 cebix 1.1
639     #if PRECISE_TIMING
640     // Look for next task to be called and set wakeup_time
641 gbeauche 1.4 #if PRECISE_TIMING_BEOS
642 cebix 1.1 while (acquire_sem(wakeup_time_sem) == B_INTERRUPTED) ;
643     suspend_thread(timer_thread);
644 gbeauche 1.4 #endif
645 asvitkine 1.12 #if PRECISE_TIMING_MACH
646     semaphore_wait(wakeup_time_sem);
647     thread_suspend(timer_thread);
648     #endif
649 gbeauche 1.4 #if PRECISE_TIMING_POSIX
650     timer_thread_suspend();
651 gbeauche 1.6 pthread_mutex_lock(&wakeup_time_lock);
652 gbeauche 1.4 #endif
653     wakeup_time = wakeup_time_max;
654 asvitkine 1.13 for (TMDesc *d = tmDescList; d; d = d->next)
655     if ((ReadMacInt16(d->task + qType) & 0x8000))
656     if (timer_cmp_time(d->wakeup, wakeup_time) < 0)
657     wakeup_time = d->wakeup;
658 gbeauche 1.4 #if PRECISE_TIMING_BEOS
659 cebix 1.1 release_sem(wakeup_time_sem);
660     thread_info info;
661     do {
662     resume_thread(timer_thread); // This will unblock the thread
663     get_thread_info(timer_thread, &info);
664     } while (info.state == B_THREAD_SUSPENDED); // Sometimes, resume_thread() doesn't work (BeOS bug?)
665     #endif
666 asvitkine 1.12 #if PRECISE_TIMING_MACH
667     semaphore_signal(wakeup_time_sem);
668     thread_abort(timer_thread);
669     thread_resume(timer_thread);
670     #endif
671 gbeauche 1.4 #if PRECISE_TIMING_POSIX
672 gbeauche 1.6 pthread_mutex_unlock(&wakeup_time_lock);
673 gbeauche 1.4 timer_thread_resume();
674     assert(suspend_count == 0);
675     #endif
676     #endif
677 cebix 1.1 }