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.3 by gbeauche, 2005-01-30T21:48:19Z vs.
Revision 1.4 by gbeauche, 2005-03-05T19:07:35Z

# 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 volatile bool thread_active = false;
74 + static tm_time_t wakeup_time_max = { 0x7fffffff, 999999999 };
75 + static tm_time_t wakeup_time = wakeup_time_max;
76 + static sem_t wakeup_time_sem;
77 + static void *timer_func(void *arg);
78 + #endif
79 + #endif
80  
81  
82   /*
# Line 143 | Line 153 | static void dequeue_tm(uint32 tm)
153  
154  
155   /*
156 + *  Timer thread operations
157 + */
158 +
159 + #ifdef PRECISE_TIMING_POSIX
160 + const int SIGSUSPEND = SIGRTMIN + 6;
161 + const int SIGRESUME  = SIGRTMIN + 7;
162 + static struct sigaction sigsuspend_action;
163 + static struct sigaction sigresume_action;
164 +
165 + static int suspend_count = 0;
166 + static pthread_mutex_t suspend_count_lock = PTHREAD_MUTEX_INITIALIZER;
167 + static sem_t suspend_ack_sem;
168 +
169 + // Signal handler for suspended thread
170 + static void sigsuspend_handler(int sig)
171 + {
172 +        sem_post(&suspend_ack_sem);
173 +
174 +        sigset_t mask;
175 +        sigfillset(&mask);
176 +        sigdelset(&mask, SIGRESUME);
177 +        sigsuspend(&mask);
178 + }
179 +
180 + // Signal handler for resumed thread
181 + static void sigresume_handler(int sig)
182 + {
183 +        /* simply trigger a signal to stop clock_nanosleep() */
184 + }
185 +
186 + // Initialize timer thread
187 + static bool timer_thread_init(void)
188 + {
189 +        // Install suspend signal handler
190 +        sigfillset(&sigsuspend_action.sa_mask);
191 +        sigsuspend_action.sa_handler = sigsuspend_handler;
192 +        sigsuspend_action.sa_flags = SA_RESTART;
193 + #ifdef HAVE_SIGNAL_SA_RESTORER
194 +        sigsuspend_action.sa_restorer = NULL;
195 + #endif
196 +        if (sigaction(SIGSUSPEND, &sigsuspend_action, NULL) < 0)
197 +                return false;
198 +
199 +        // Install resume signal handler
200 +        sigfillset(&sigresume_action.sa_mask);
201 +        sigresume_action.sa_handler = sigresume_handler;
202 +        sigresume_action.sa_flags = SA_RESTART;
203 + #ifdef HAVE_SIGNAL_SA_RESTORER
204 +        sigresume_action.sa_restorer = NULL;
205 + #endif
206 +        if (sigaction(SIGRESUME, &sigresume_action, NULL) < 0)
207 +                return false;
208 +
209 +        // Initialize semaphore
210 +        if (sem_init(&suspend_ack_sem, 0, 0) < 0)
211 +                return false;
212 +
213 +        // Create thread in running state
214 +        suspend_count = 0;
215 +        return (pthread_create(&timer_thread, NULL, timer_func, NULL) == 0);
216 + }
217 +
218 + // Kill timer thread
219 + static void timer_thread_kill(void)
220 + {
221 + #ifdef HAVE_PTHREAD_CANCEL
222 +        pthread_cancel(timer_thread);
223 + #endif
224 +        pthread_join(timer_thread, NULL);
225 + }
226 +
227 + // Suspend timer thread
228 + static void timer_thread_suspend(void)
229 + {
230 +        pthread_mutex_lock(&suspend_count_lock);
231 +        if (suspend_count == 0) {
232 +                suspend_count ++;
233 +                if (pthread_kill(timer_thread, SIGSUSPEND) == 0)
234 +                        sem_wait(&suspend_ack_sem);
235 +        }
236 +        pthread_mutex_unlock(&suspend_count_lock);
237 + }
238 +
239 + // Resume timer thread
240 + static void timer_thread_resume(void)
241 + {
242 +        pthread_mutex_lock(&suspend_count_lock);
243 +        assert(suspend_count > 0);
244 +        if (suspend_count == 1) {
245 +                suspend_count = 0;
246 +                pthread_kill(timer_thread, SIGRESUME);
247 +        }
248 +        pthread_mutex_unlock(&suspend_count_lock);
249 + }
250 + #endif
251 +
252 +
253 + /*
254   *  Initialize Time Manager
255   */
256  
# Line 154 | Line 262 | void TimerInit(void)
262  
263   #if PRECISE_TIMING
264          // Start timer thread
265 + #ifdef PRECISE_TIMING_BEOS
266          wakeup_time_sem = create_sem(1, "Wakeup Time");
267          timer_thread = spawn_thread(timer_func, "Time Manager", B_REAL_TIME_PRIORITY, NULL);
268          resume_thread(timer_thread);
269   #endif
270 + #ifdef PRECISE_TIMING_POSIX
271 +        sem_init(&wakeup_time_sem, 0, 1);
272 +        thread_active = timer_thread_init();
273 + #endif
274 + #endif
275   }
276  
277  
# Line 170 | Line 284 | void TimerExit(void)
284   #if PRECISE_TIMING
285          // Quit timer thread
286          if (timer_thread > 0) {
287 + #ifdef PRECISE_TIMING_BEOS
288                  status_t l;
289                  thread_active = false;
290                  suspend_thread(timer_thread);
291                  resume_thread(timer_thread);
292                  wait_for_thread(timer_thread, &l);
293                  delete_sem(wakeup_time_sem);
294 + #endif
295 + #ifdef PRECISE_TIMING_POSIX
296 +                thread_active = false;
297 +                timer_thread_kill();
298 +                sem_destroy(&wakeup_time_sem);
299 + #endif
300          }
301   #endif
302   }
# Line 228 | Line 349 | int16 RmvTime(uint32 tm)
349          }
350  
351          // Task active?
352 < #if PRECISE_TIMING
352 > #if PRECISE_TIMING_BEOS
353          while (acquire_sem(wakeup_time_sem) == B_INTERRUPTED) ;
354          suspend_thread(timer_thread);
355   #endif
356 + #if PRECISE_TIMING_POSIX
357 +        sem_wait(&wakeup_time_sem);
358 +        timer_thread_suspend();
359 + #endif
360          if (ReadMacInt16(tm + qType) & 0x8000) {
361  
362                  // Yes, make task inactive and remove it from the Time Manager queue
# Line 239 | Line 364 | int16 RmvTime(uint32 tm)
364                  dequeue_tm(tm);
365   #if PRECISE_TIMING
366                  // Look for next task to be called and set wakeup_time
367 <                wakeup_time = 0x7fffffffffffffff;
367 >                wakeup_time = wakeup_time_max;
368                  for (int j=0; j<NUM_DESCS; j++) {
369                          if (desc[j].in_use && (ReadMacInt16(desc[j].task + qType) & 0x8000))
370 <                                if (desc[j].wakeup < wakeup_time)
370 >                                if (timer_cmp_time(desc[j].wakeup, wakeup_time) < 0)
371                                          wakeup_time = desc[j].wakeup;
372                  }
373   #endif
# Line 255 | Line 380 | int16 RmvTime(uint32 tm)
380          } else
381                  WriteMacInt32(tm + tmCount, 0);
382          D(bug(" tmCount %ld\n", ReadMacInt32(tm + tmCount)));
383 < #if PRECISE_TIMING
383 > #if PRECISE_TIMING_BEOS
384          release_sem(wakeup_time_sem);
385          thread_info info;
386          do {
# Line 263 | Line 388 | int16 RmvTime(uint32 tm)
388                  get_thread_info(timer_thread, &info);
389          } while (info.state == B_THREAD_SUSPENDED);     // Sometimes, resume_thread() doesn't work (BeOS bug?)
390   #endif
391 + #if PRECISE_TIMING_POSIX
392 +        sem_post(&wakeup_time_sem);
393 +        timer_thread_resume();
394 +        assert(suspend_count == 0);
395 + #endif
396  
397          // Free descriptor
398          free_desc(i);
# Line 327 | Line 457 | int16 PrimeTime(uint32 tm, int32 time)
457          }
458  
459          // Make task active and enqueue it in the Time Manager queue
460 < #if PRECISE_TIMING
460 > #if PRECISE_TIMING_BEOS
461          while (acquire_sem(wakeup_time_sem) == B_INTERRUPTED) ;
462          suspend_thread(timer_thread);
463   #endif
464 + #if PRECISE_TIMING_POSIX
465 +        sem_wait(&wakeup_time_sem);
466 +        timer_thread_suspend();
467 + #endif
468          WriteMacInt16(tm + qType, ReadMacInt16(tm + qType) | 0x8000);
469          enqueue_tm(tm);
470   #if PRECISE_TIMING
471          // Look for next task to be called and set wakeup_time
472 <        wakeup_time = 0x7fffffffffffffff;
472 >        wakeup_time = wakeup_time_max;
473          for (int j=0; j<NUM_DESCS; j++) {
474                  if (desc[j].in_use && (ReadMacInt16(desc[j].task + qType) & 0x8000))
475 <                        if (desc[j].wakeup < wakeup_time)
475 >                        if (timer_cmp_time(desc[j].wakeup, wakeup_time) < 0)
476                                  wakeup_time = desc[j].wakeup;
477          }
478 + #ifdef PRECISE_TIMING_BEOS
479          release_sem(wakeup_time_sem);
480          thread_info info;
481          do {
# Line 348 | Line 483 | int16 PrimeTime(uint32 tm, int32 time)
483                  get_thread_info(timer_thread, &info);
484          } while (info.state == B_THREAD_SUSPENDED);     // Sometimes, resume_thread() doesn't work (BeOS bug?)
485   #endif
486 + #ifdef PRECISE_TIMING_POSIX
487 +        sem_post(&wakeup_time_sem);
488 +        timer_thread_resume();
489 +        assert(suspend_count == 0);
490 + #endif
491 + #endif
492          return 0;
493   }
494  
495  
355 #if PRECISE_TIMING
496   /*
497   *  Time Manager thread
498   */
499  
500 + #ifdef PRECISE_TIMING_BEOS
501   static int32 timer_func(void *arg)
502   {
503          while (thread_active) {
# Line 378 | Line 519 | static int32 timer_func(void *arg)
519   }
520   #endif
521  
522 + #ifdef PRECISE_TIMING_POSIX
523 + static void *timer_func(void *arg)
524 + {
525 +        while (thread_active) {
526 +
527 +                // Wait until time specified by wakeup_time
528 +                clock_nanosleep(CLOCK_REALTIME, TIMER_ABSTIME, &wakeup_time, NULL);
529 +
530 +                sem_wait(&wakeup_time_sem);
531 +                tm_time_t system_time;
532 +                timer_current_time(system_time);
533 +                if (timer_cmp_time(wakeup_time, system_time) < 0) {
534 +
535 +                        // Timer expired, trigger interrupt
536 +                        wakeup_time = wakeup_time_max;
537 +                        SetInterruptFlag(INTFLAG_TIMER);
538 +                        TriggerInterrupt();
539 +                }
540 +                sem_post(&wakeup_time_sem);
541 +        }
542 +        return NULL;
543 + }
544 + #endif
545 +
546  
547   /*
548   *  Timer interrupt function (executed as part of 60Hz interrupt)
# Line 414 | Line 579 | void TimerInterrupt(void)
579  
580   #if PRECISE_TIMING
581          // Look for next task to be called and set wakeup_time
582 + #if PRECISE_TIMING_BEOS
583          while (acquire_sem(wakeup_time_sem) == B_INTERRUPTED) ;
584          suspend_thread(timer_thread);
585 <        wakeup_time = 0x7fffffffffffffff;
585 > #endif
586 > #if PRECISE_TIMING_POSIX
587 >        sem_wait(&wakeup_time_sem);
588 >        timer_thread_suspend();
589 > #endif
590 >        wakeup_time = wakeup_time_max;
591          for (int j=0; j<NUM_DESCS; j++) {
592                  if (desc[j].in_use && (ReadMacInt16(desc[j].task + qType) & 0x8000))
593 <                        if (desc[j].wakeup < wakeup_time)
593 >                        if (timer_cmp_time(desc[j].wakeup, wakeup_time) < 0)
594                                  wakeup_time = desc[j].wakeup;
595          }
596 + #if PRECISE_TIMING_BEOS
597          release_sem(wakeup_time_sem);
598          thread_info info;
599          do {
# Line 429 | Line 601 | void TimerInterrupt(void)
601                  get_thread_info(timer_thread, &info);
602          } while (info.state == B_THREAD_SUSPENDED);     // Sometimes, resume_thread() doesn't work (BeOS bug?)
603   #endif
604 + #if PRECISE_TIMING_POSIX
605 +        sem_post(&wakeup_time_sem);
606 +        timer_thread_resume();
607 +        assert(suspend_count == 0);
608 + #endif
609 + #endif
610   }

Diff Legend

Removed lines
+ Added lines
< Changed lines
> Changed lines