ViewVC Help
View File | Revision Log | Show Annotations | Revision Graph | Root Listing
root/cebix/SheepShaver/src/timer.cpp
(Generate patch)

Comparing SheepShaver/src/timer.cpp (file contents):
Revision 1.1 by cebix, 2002-02-04T16:58:13Z vs.
Revision 1.6 by gbeauche, 2005-03-16T00:35:51Z

# Line 1 | Line 1
1   /*
2   *  timer.cpp - Time Manager emulation
3   *
4 < *  SheepShaver (C) 1997-2002 Christian Bauer and Marc Hellwig
4 > *  SheepShaver (C) 1997-2005 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
# Line 28 | Line 28
28   #include "main.h"
29   #include "cpu_emulation.h"
30  
31 + #ifdef PRECISE_TIMING_POSIX
32 + #include <pthread.h>
33 + #include <semaphore.h>
34 + #endif
35 +
36   #define DEBUG 0
37   #include "debug.h"
38  
39  
35 #if __BEOS__
36 #define PRECISE_TIMING 1
37 #else
38 #define PRECISE_TIMING 0
39 #endif
40
40   #define TM_QUEUE 0                      // Enable TMQueue management (doesn't work)
41  
42  
# Line 61 | Line 60 | const int NUM_DESCS = 64;              // Maximum nu
60   static TMDesc desc[NUM_DESCS];
61  
62   #if PRECISE_TIMING
63 + #ifdef PRECISE_TIMING_BEOS
64   static thread_id timer_thread = -1;
65   static bool thread_active = true;
66 < static volatile tm_time_t wakeup_time = 0x7fffffffffffffff;
66 > static const tm_time_t wakeup_time_max = 0x7fffffffffffffff;
67 > static volatile tm_time_t wakeup_time = wakeup_time_max;
68   static sem_id wakeup_time_sem = -1;
69   static int32 timer_func(void *arg);
70   #endif
71 + #ifdef PRECISE_TIMING_POSIX
72 + static pthread_t timer_thread;
73 + static bool timer_thread_active = false;
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 pthread_mutex_t wakeup_time_lock = PTHREAD_MUTEX_INITIALIZER;
78 + static void *timer_func(void *arg);
79 + #endif
80 + #endif
81  
82  
83   /*
# Line 143 | Line 154 | static void dequeue_tm(uint32 tm)
154  
155  
156   /*
157 + *  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 + static sigset_t suspend_handler_mask;
170 +
171 + // Signal handler for suspended thread
172 + static void sigsuspend_handler(int sig)
173 + {
174 +        sem_post(&suspend_ack_sem);
175 +        sigsuspend(&suspend_handler_mask);
176 + }
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 +        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
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 +        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
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 +        // 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 +        // 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 +        timer_thread_cancel = true;
227 + #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   *  Initialize Time Manager
261   */
262  
# Line 154 | Line 268 | void TimerInit(void)
268  
269   #if PRECISE_TIMING
270          // Start timer thread
271 + #ifdef PRECISE_TIMING_BEOS
272          wakeup_time_sem = create_sem(1, "Wakeup Time");
273          timer_thread = spawn_thread(timer_func, "Time Manager", B_REAL_TIME_PRIORITY, NULL);
274          resume_thread(timer_thread);
275   #endif
276 + #ifdef PRECISE_TIMING_POSIX
277 +        timer_thread_active = timer_thread_init();
278 + #endif
279 + #endif
280   }
281  
282  
# Line 170 | Line 289 | void TimerExit(void)
289   #if PRECISE_TIMING
290          // Quit timer thread
291          if (timer_thread > 0) {
292 + #ifdef PRECISE_TIMING_BEOS
293                  status_t l;
294                  thread_active = false;
295                  suspend_thread(timer_thread);
296                  resume_thread(timer_thread);
297                  wait_for_thread(timer_thread, &l);
298                  delete_sem(wakeup_time_sem);
299 + #endif
300 + #ifdef PRECISE_TIMING_POSIX
301 +                timer_thread_kill();
302 + #endif
303          }
304   #endif
305   }
# Line 228 | Line 352 | int16 RmvTime(uint32 tm)
352          }
353  
354          // Task active?
355 < #if PRECISE_TIMING
355 > #if PRECISE_TIMING_BEOS
356          while (acquire_sem(wakeup_time_sem) == B_INTERRUPTED) ;
357          suspend_thread(timer_thread);
358   #endif
359 + #if PRECISE_TIMING_POSIX
360 +        timer_thread_suspend();
361 +        pthread_mutex_lock(&wakeup_time_lock);
362 + #endif
363          if (ReadMacInt16(tm + qType) & 0x8000) {
364  
365                  // Yes, make task inactive and remove it from the Time Manager queue
# Line 239 | Line 367 | int16 RmvTime(uint32 tm)
367                  dequeue_tm(tm);
368   #if PRECISE_TIMING
369                  // Look for next task to be called and set wakeup_time
370 <                wakeup_time = 0x7fffffffffffffff;
370 >                wakeup_time = wakeup_time_max;
371                  for (int j=0; j<NUM_DESCS; j++) {
372                          if (desc[j].in_use && (ReadMacInt16(desc[j].task + qType) & 0x8000))
373 <                                if (desc[j].wakeup < wakeup_time)
373 >                                if (timer_cmp_time(desc[j].wakeup, wakeup_time) < 0)
374                                          wakeup_time = desc[j].wakeup;
375                  }
376   #endif
# Line 255 | Line 383 | int16 RmvTime(uint32 tm)
383          } else
384                  WriteMacInt32(tm + tmCount, 0);
385          D(bug(" tmCount %ld\n", ReadMacInt32(tm + tmCount)));
386 < #if PRECISE_TIMING
386 > #if PRECISE_TIMING_BEOS
387          release_sem(wakeup_time_sem);
388          thread_info info;
389          do {
# Line 263 | Line 391 | int16 RmvTime(uint32 tm)
391                  get_thread_info(timer_thread, &info);
392          } while (info.state == B_THREAD_SUSPENDED);     // Sometimes, resume_thread() doesn't work (BeOS bug?)
393   #endif
394 + #if PRECISE_TIMING_POSIX
395 +        pthread_mutex_unlock(&wakeup_time_lock);
396 +        timer_thread_resume();
397 +        assert(suspend_count == 0);
398 + #endif
399  
400          // Free descriptor
401          free_desc(i);
# Line 327 | Line 460 | int16 PrimeTime(uint32 tm, int32 time)
460          }
461  
462          // Make task active and enqueue it in the Time Manager queue
463 < #if PRECISE_TIMING
463 > #if PRECISE_TIMING_BEOS
464          while (acquire_sem(wakeup_time_sem) == B_INTERRUPTED) ;
465          suspend_thread(timer_thread);
466   #endif
467 + #if PRECISE_TIMING_POSIX
468 +        timer_thread_suspend();
469 +        pthread_mutex_lock(&wakeup_time_lock);
470 + #endif
471          WriteMacInt16(tm + qType, ReadMacInt16(tm + qType) | 0x8000);
472          enqueue_tm(tm);
473   #if PRECISE_TIMING
474          // Look for next task to be called and set wakeup_time
475 <        wakeup_time = 0x7fffffffffffffff;
475 >        wakeup_time = wakeup_time_max;
476          for (int j=0; j<NUM_DESCS; j++) {
477                  if (desc[j].in_use && (ReadMacInt16(desc[j].task + qType) & 0x8000))
478 <                        if (desc[j].wakeup < wakeup_time)
478 >                        if (timer_cmp_time(desc[j].wakeup, wakeup_time) < 0)
479                                  wakeup_time = desc[j].wakeup;
480          }
481 + #ifdef PRECISE_TIMING_BEOS
482          release_sem(wakeup_time_sem);
483          thread_info info;
484          do {
# Line 348 | Line 486 | int16 PrimeTime(uint32 tm, int32 time)
486                  get_thread_info(timer_thread, &info);
487          } while (info.state == B_THREAD_SUSPENDED);     // Sometimes, resume_thread() doesn't work (BeOS bug?)
488   #endif
489 + #ifdef PRECISE_TIMING_POSIX
490 +        pthread_mutex_unlock(&wakeup_time_lock);
491 +        timer_thread_resume();
492 +        assert(suspend_count == 0);
493 + #endif
494 + #endif
495          return 0;
496   }
497  
498  
355 #if PRECISE_TIMING
499   /*
500   *  Time Manager thread
501   */
502  
503 + #ifdef PRECISE_TIMING_BEOS
504   static int32 timer_func(void *arg)
505   {
506          while (thread_active) {
# Line 378 | Line 522 | static int32 timer_func(void *arg)
522   }
523   #endif
524  
525 + #ifdef PRECISE_TIMING_POSIX
526 + static void *timer_func(void *arg)
527 + {
528 +        while (!timer_thread_cancel) {
529 +
530 +                // Wait until time specified by wakeup_time
531 +                clock_nanosleep(CLOCK_REALTIME, TIMER_ABSTIME, &wakeup_time, NULL);
532 +
533 +                tm_time_t system_time;
534 +                timer_current_time(system_time);
535 +                pthread_mutex_lock(&wakeup_time_lock);
536 +                if (timer_cmp_time(wakeup_time, system_time) < 0) {
537 +
538 +                        // Timer expired, trigger interrupt
539 +                        wakeup_time = wakeup_time_max;
540 +                        SetInterruptFlag(INTFLAG_TIMER);
541 +                        TriggerInterrupt();
542 +                }
543 +                pthread_mutex_unlock(&wakeup_time_lock);
544 +        }
545 +        return NULL;
546 + }
547 + #endif
548 +
549  
550   /*
551   *  Timer interrupt function (executed as part of 60Hz interrupt)
# Line 414 | Line 582 | void TimerInterrupt(void)
582  
583   #if PRECISE_TIMING
584          // Look for next task to be called and set wakeup_time
585 + #if PRECISE_TIMING_BEOS
586          while (acquire_sem(wakeup_time_sem) == B_INTERRUPTED) ;
587          suspend_thread(timer_thread);
588 <        wakeup_time = 0x7fffffffffffffff;
588 > #endif
589 > #if PRECISE_TIMING_POSIX
590 >        timer_thread_suspend();
591 >        pthread_mutex_lock(&wakeup_time_lock);
592 > #endif
593 >        wakeup_time = wakeup_time_max;
594          for (int j=0; j<NUM_DESCS; j++) {
595                  if (desc[j].in_use && (ReadMacInt16(desc[j].task + qType) & 0x8000))
596 <                        if (desc[j].wakeup < wakeup_time)
596 >                        if (timer_cmp_time(desc[j].wakeup, wakeup_time) < 0)
597                                  wakeup_time = desc[j].wakeup;
598          }
599 + #if PRECISE_TIMING_BEOS
600          release_sem(wakeup_time_sem);
601          thread_info info;
602          do {
# Line 429 | Line 604 | void TimerInterrupt(void)
604                  get_thread_info(timer_thread, &info);
605          } while (info.state == B_THREAD_SUSPENDED);     // Sometimes, resume_thread() doesn't work (BeOS bug?)
606   #endif
607 + #if PRECISE_TIMING_POSIX
608 +        pthread_mutex_unlock(&wakeup_time_lock);
609 +        timer_thread_resume();
610 +        assert(suspend_count == 0);
611 + #endif
612 + #endif
613   }

Diff Legend

Removed lines
+ Added lines
< Changed lines
> Changed lines