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.5 by gbeauche, 2005-03-15T20:46:50Z

# 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 sem_t wakeup_time_sem;
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 +        sigfillset(&sigsuspend_action.sa_mask);
189 +        sigsuspend_action.sa_handler = sigsuspend_handler;
190 +        sigsuspend_action.sa_flags = SA_RESTART;
191 + #ifdef HAVE_SIGNAL_SA_RESTORER
192 +        sigsuspend_action.sa_restorer = NULL;
193 + #endif
194 +        if (sigaction(SIGSUSPEND, &sigsuspend_action, NULL) < 0)
195 +                return false;
196 +
197 +        // Install resume signal handler
198 +        sigfillset(&sigresume_action.sa_mask);
199 +        sigresume_action.sa_handler = sigresume_handler;
200 +        sigresume_action.sa_flags = SA_RESTART;
201 + #ifdef HAVE_SIGNAL_SA_RESTORER
202 +        sigresume_action.sa_restorer = NULL;
203 + #endif
204 +        if (sigaction(SIGRESUME, &sigresume_action, NULL) < 0)
205 +                return false;
206 +
207 +        // Initialize semaphore
208 +        if (sem_init(&suspend_ack_sem, 0, 0) < 0)
209 +                return false;
210 +
211 +        // Initialize suspend_handler_mask, it excludes SIGRESUME
212 +        if (sigfillset(&suspend_handler_mask) != 0)
213 +                return false;
214 +        if (sigdelset(&suspend_handler_mask, SIGRESUME) != 0)
215 +                return false;
216 +
217 +        // Create thread in running state
218 +        suspend_count = 0;
219 +        return (pthread_create(&timer_thread, NULL, timer_func, NULL) == 0);
220 + }
221 +
222 + // Kill timer thread
223 + static void timer_thread_kill(void)
224 + {
225 +        timer_thread_cancel = true;
226 + #ifdef HAVE_PTHREAD_CANCEL
227 +        pthread_cancel(timer_thread);
228 + #endif
229 +        pthread_join(timer_thread, NULL);
230 + }
231 +
232 + // Suspend timer thread
233 + static void timer_thread_suspend(void)
234 + {
235 +        pthread_mutex_lock(&suspend_count_lock);
236 +        if (suspend_count == 0) {
237 +                suspend_count ++;
238 +                if (pthread_kill(timer_thread, SIGSUSPEND) == 0)
239 +                        sem_wait(&suspend_ack_sem);
240 +        }
241 +        pthread_mutex_unlock(&suspend_count_lock);
242 + }
243 +
244 + // Resume timer thread
245 + static void timer_thread_resume(void)
246 + {
247 +        pthread_mutex_lock(&suspend_count_lock);
248 +        assert(suspend_count > 0);
249 +        if (suspend_count == 1) {
250 +                suspend_count = 0;
251 +                pthread_kill(timer_thread, SIGRESUME);
252 +        }
253 +        pthread_mutex_unlock(&suspend_count_lock);
254 + }
255 + #endif
256 +
257 +
258 + /*
259   *  Initialize Time Manager
260   */
261  
# Line 154 | Line 267 | void TimerInit(void)
267  
268   #if PRECISE_TIMING
269          // Start timer thread
270 + #ifdef PRECISE_TIMING_BEOS
271          wakeup_time_sem = create_sem(1, "Wakeup Time");
272          timer_thread = spawn_thread(timer_func, "Time Manager", B_REAL_TIME_PRIORITY, NULL);
273          resume_thread(timer_thread);
274   #endif
275 + #ifdef PRECISE_TIMING_POSIX
276 +        sem_init(&wakeup_time_sem, 0, 1);
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 +                sem_destroy(&wakeup_time_sem);
303 + #endif
304          }
305   #endif
306   }
# Line 228 | Line 353 | int16 RmvTime(uint32 tm)
353          }
354  
355          // Task active?
356 < #if PRECISE_TIMING
356 > #if PRECISE_TIMING_BEOS
357          while (acquire_sem(wakeup_time_sem) == B_INTERRUPTED) ;
358          suspend_thread(timer_thread);
359   #endif
360 + #if PRECISE_TIMING_POSIX
361 +        sem_wait(&wakeup_time_sem);
362 +        timer_thread_suspend();
363 + #endif
364          if (ReadMacInt16(tm + qType) & 0x8000) {
365  
366                  // Yes, make task inactive and remove it from the Time Manager queue
# Line 239 | Line 368 | int16 RmvTime(uint32 tm)
368                  dequeue_tm(tm);
369   #if PRECISE_TIMING
370                  // Look for next task to be called and set wakeup_time
371 <                wakeup_time = 0x7fffffffffffffff;
371 >                wakeup_time = wakeup_time_max;
372                  for (int j=0; j<NUM_DESCS; j++) {
373                          if (desc[j].in_use && (ReadMacInt16(desc[j].task + qType) & 0x8000))
374 <                                if (desc[j].wakeup < wakeup_time)
374 >                                if (timer_cmp_time(desc[j].wakeup, wakeup_time) < 0)
375                                          wakeup_time = desc[j].wakeup;
376                  }
377   #endif
# Line 255 | Line 384 | int16 RmvTime(uint32 tm)
384          } else
385                  WriteMacInt32(tm + tmCount, 0);
386          D(bug(" tmCount %ld\n", ReadMacInt32(tm + tmCount)));
387 < #if PRECISE_TIMING
387 > #if PRECISE_TIMING_BEOS
388          release_sem(wakeup_time_sem);
389          thread_info info;
390          do {
# Line 263 | Line 392 | int16 RmvTime(uint32 tm)
392                  get_thread_info(timer_thread, &info);
393          } while (info.state == B_THREAD_SUSPENDED);     // Sometimes, resume_thread() doesn't work (BeOS bug?)
394   #endif
395 + #if PRECISE_TIMING_POSIX
396 +        sem_post(&wakeup_time_sem);
397 +        timer_thread_resume();
398 +        assert(suspend_count == 0);
399 + #endif
400  
401          // Free descriptor
402          free_desc(i);
# Line 327 | Line 461 | int16 PrimeTime(uint32 tm, int32 time)
461          }
462  
463          // Make task active and enqueue it in the Time Manager queue
464 < #if PRECISE_TIMING
464 > #if PRECISE_TIMING_BEOS
465          while (acquire_sem(wakeup_time_sem) == B_INTERRUPTED) ;
466          suspend_thread(timer_thread);
467   #endif
468 + #if PRECISE_TIMING_POSIX
469 +        sem_wait(&wakeup_time_sem);
470 +        timer_thread_suspend();
471 + #endif
472          WriteMacInt16(tm + qType, ReadMacInt16(tm + qType) | 0x8000);
473          enqueue_tm(tm);
474   #if PRECISE_TIMING
475          // Look for next task to be called and set wakeup_time
476 <        wakeup_time = 0x7fffffffffffffff;
476 >        wakeup_time = wakeup_time_max;
477          for (int j=0; j<NUM_DESCS; j++) {
478                  if (desc[j].in_use && (ReadMacInt16(desc[j].task + qType) & 0x8000))
479 <                        if (desc[j].wakeup < wakeup_time)
479 >                        if (timer_cmp_time(desc[j].wakeup, wakeup_time) < 0)
480                                  wakeup_time = desc[j].wakeup;
481          }
482 + #ifdef PRECISE_TIMING_BEOS
483          release_sem(wakeup_time_sem);
484          thread_info info;
485          do {
# Line 348 | Line 487 | int16 PrimeTime(uint32 tm, int32 time)
487                  get_thread_info(timer_thread, &info);
488          } while (info.state == B_THREAD_SUSPENDED);     // Sometimes, resume_thread() doesn't work (BeOS bug?)
489   #endif
490 + #ifdef PRECISE_TIMING_POSIX
491 +        sem_post(&wakeup_time_sem);
492 +        timer_thread_resume();
493 +        assert(suspend_count == 0);
494 + #endif
495 + #endif
496          return 0;
497   }
498  
499  
355 #if PRECISE_TIMING
500   /*
501   *  Time Manager thread
502   */
503  
504 + #ifdef PRECISE_TIMING_BEOS
505   static int32 timer_func(void *arg)
506   {
507          while (thread_active) {
# Line 378 | Line 523 | static int32 timer_func(void *arg)
523   }
524   #endif
525  
526 + #ifdef PRECISE_TIMING_POSIX
527 + static void *timer_func(void *arg)
528 + {
529 +        while (!timer_thread_cancel) {
530 +
531 +                // Wait until time specified by wakeup_time
532 +                clock_nanosleep(CLOCK_REALTIME, TIMER_ABSTIME, &wakeup_time, NULL);
533 +
534 +                sem_wait(&wakeup_time_sem);
535 +                tm_time_t system_time;
536 +                timer_current_time(system_time);
537 +                if (timer_cmp_time(wakeup_time, system_time) < 0) {
538 +
539 +                        // Timer expired, trigger interrupt
540 +                        wakeup_time = wakeup_time_max;
541 +                        SetInterruptFlag(INTFLAG_TIMER);
542 +                        TriggerInterrupt();
543 +                }
544 +                sem_post(&wakeup_time_sem);
545 +        }
546 +        return NULL;
547 + }
548 + #endif
549 +
550  
551   /*
552   *  Timer interrupt function (executed as part of 60Hz interrupt)
# Line 414 | Line 583 | void TimerInterrupt(void)
583  
584   #if PRECISE_TIMING
585          // Look for next task to be called and set wakeup_time
586 + #if PRECISE_TIMING_BEOS
587          while (acquire_sem(wakeup_time_sem) == B_INTERRUPTED) ;
588          suspend_thread(timer_thread);
589 <        wakeup_time = 0x7fffffffffffffff;
589 > #endif
590 > #if PRECISE_TIMING_POSIX
591 >        sem_wait(&wakeup_time_sem);
592 >        timer_thread_suspend();
593 > #endif
594 >        wakeup_time = wakeup_time_max;
595          for (int j=0; j<NUM_DESCS; j++) {
596                  if (desc[j].in_use && (ReadMacInt16(desc[j].task + qType) & 0x8000))
597 <                        if (desc[j].wakeup < wakeup_time)
597 >                        if (timer_cmp_time(desc[j].wakeup, wakeup_time) < 0)
598                                  wakeup_time = desc[j].wakeup;
599          }
600 + #if PRECISE_TIMING_BEOS
601          release_sem(wakeup_time_sem);
602          thread_info info;
603          do {
# Line 429 | Line 605 | void TimerInterrupt(void)
605                  get_thread_info(timer_thread, &info);
606          } while (info.state == B_THREAD_SUSPENDED);     // Sometimes, resume_thread() doesn't work (BeOS bug?)
607   #endif
608 + #if PRECISE_TIMING_POSIX
609 +        sem_post(&wakeup_time_sem);
610 +        timer_thread_resume();
611 +        assert(suspend_count == 0);
612 + #endif
613 + #endif
614   }

Diff Legend

Removed lines
+ Added lines
< Changed lines
> Changed lines