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.9 by asvitkine, 2009-07-31T19:41:50Z vs.
Revision 1.15 by asvitkine, 2011-12-28T18:14:58Z

# Line 18 | Line 18
18   *  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
19   */
20  
21 /*
22 * TODO: Prime(0)
23 */
24
21   #include "sysdeps.h"
22   #include "timer.h"
23   #include "macos_util.h"
# Line 33 | Line 29
29   #include <semaphore.h>
30   #endif
31  
32 + #ifdef PRECISE_TIMING_MACH
33 + #include <mach/mach.h>
34 + #endif
35 +
36   #define DEBUG 0
37   #include "debug.h"
38  
# Line 53 | Line 53 | enum { // TMTask struct
53   struct TMDesc {
54          uint32 task;            // Mac address of associated TMTask
55          tm_time_t wakeup;       // Time this task is scheduled for execution
56 <        bool in_use;            // Flag: descriptor in use
56 >        TMDesc *next;
57   };
58  
59 < const int NUM_DESCS = 64;               // Maximum number of descriptors
60 < static TMDesc desc[NUM_DESCS];
59 > static TMDesc *tmDescList;
60  
61   #if PRECISE_TIMING
62   #ifdef PRECISE_TIMING_BEOS
# Line 77 | Line 76 | static tm_time_t wakeup_time = wakeup_ti
76   static pthread_mutex_t wakeup_time_lock = PTHREAD_MUTEX_INITIALIZER;
77   static void *timer_func(void *arg);
78   #endif
79 + #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   #endif
89  
90  
91 < /*
84 < *  Allocate descriptor for given TMTask in list
85 < */
86 <
87 < static int alloc_desc(uint32 tm)
91 > inline static void free_desc(TMDesc *desc)
92   {
93 <        // Search for first free descriptor
94 <        for (int i=0; i<NUM_DESCS; i++)
95 <                if (!desc[i].in_use) {
96 <                        desc[i].task = tm;
97 <                        desc[i].in_use = true;
98 <                        return i;
93 >        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                  }
102 <        return -1;
103 < }
98 <
99 <
100 < /*
101 < *  Free descriptor in list
102 < */
103 <
104 < inline static void free_desc(int i)
105 < {
106 <        desc[i].in_use = false;
102 >        }
103 >        delete desc;
104   }
105  
109
106   /*
107   *  Find descriptor associated with given TMTask
108   */
109  
110 < inline static int find_desc(uint32 tm)
110 > inline static TMDesc *find_desc(uint32 tm)
111   {
112 <        for (int i=0; i<NUM_DESCS; i++)
113 <                if (desc[i].in_use && desc[i].task == tm)
114 <                        return i;
115 <        return -1;
112 >        TMDesc *desc = tmDescList;
113 >        while (desc) {
114 >                if (desc->task == tm) {
115 >                        return desc;
116 >                }
117 >                desc = desc->next;
118 >        }
119 >        return NULL;
120   }
121  
122  
# Line 262 | Line 262 | static void timer_thread_resume(void)
262  
263   void TimerInit(void)
264   {
265 <        // Mark all descriptors as inactive
266 <        for (int i=0; i<NUM_DESCS; i++)
267 <                free_desc(i);
265 >        TimerReset();
266  
267   #if PRECISE_TIMING
268          // Start timer thread
# Line 272 | Line 270 | void TimerInit(void)
270          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 + #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   #endif
281   #ifdef PRECISE_TIMING_POSIX
282          timer_thread_active = timer_thread_init();
# Line 297 | Line 302 | void TimerExit(void)
302                  wait_for_thread(timer_thread, &l);
303                  delete_sem(wakeup_time_sem);
304   #endif
305 + #ifdef PRECISE_TIMING_MACH
306 +                timer_thread_active = false;
307 +                semaphore_destroy(mach_task_self(), wakeup_time_sem);
308 + #endif
309   #ifdef PRECISE_TIMING_POSIX
310                  timer_thread_kill();
311   #endif
# Line 311 | Line 320 | void TimerExit(void)
320  
321   void TimerReset(void)
322   {
323 <        // Mark all descriptors as inactive
324 <        for (int i=0; i<NUM_DESCS; i++)
325 <                free_desc(i);
323 >        TMDesc *desc = tmDescList;
324 >        while (desc) {
325 >                TMDesc *next = desc->next;
326 >                delete desc;
327 >                desc = next;
328 >        }
329 >        tmDescList = NULL;
330   }
331  
332  
# Line 325 | Line 338 | 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 <        if (find_desc(tm) >= 0)
342 <                printf("WARNING: InsTime(): Task re-inserted\n");
341 >        if (find_desc(tm))
342 >                printf("WARNING: InsTime(%08lx): Task re-inserted\n", tm);
343          else {
344 <                int i = alloc_desc(tm);
345 <                if (i < 0)
346 <                        printf("FATAL: InsTime(): No free Time Manager descriptor\n");
344 >                TMDesc *desc = new TMDesc;
345 >                desc->task = tm;
346 >                desc->next = tmDescList;
347 >                tmDescList = desc;
348          }
349          return 0;
350   }
# Line 345 | Line 359 | int16 RmvTime(uint32 tm)
359          D(bug("RmvTime %08lx\n", tm));
360  
361          // Find descriptor
362 <        int i = find_desc(tm);
363 <        if (i < 0) {
362 >        TMDesc *desc = find_desc(tm);
363 >        if (!desc) {
364                  printf("WARNING: RmvTime(%08lx): Descriptor not found\n", tm);
365                  return 0;
366          }
# Line 356 | Line 370 | int16 RmvTime(uint32 tm)
370          while (acquire_sem(wakeup_time_sem) == B_INTERRUPTED) ;
371          suspend_thread(timer_thread);
372   #endif
373 + #ifdef PRECISE_TIMING_MACH
374 +        semaphore_wait(wakeup_time_sem);
375 +        thread_suspend(timer_thread);
376 + #endif
377   #if PRECISE_TIMING_POSIX
378          timer_thread_suspend();
379          pthread_mutex_lock(&wakeup_time_lock);
# Line 368 | Line 386 | int16 RmvTime(uint32 tm)
386   #if PRECISE_TIMING
387                  // Look for next task to be called and set wakeup_time
388                  wakeup_time = wakeup_time_max;
389 <                for (int j=0; j<NUM_DESCS; j++) {
390 <                        if (desc[j].in_use && (ReadMacInt16(desc[j].task + qType) & 0x8000))
391 <                                if (timer_cmp_time(desc[j].wakeup, wakeup_time) < 0)
392 <                                        wakeup_time = desc[j].wakeup;
375 <                }
389 >                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   #endif
394  
395                  // Compute remaining time
396                  tm_time_t remaining, current;
397                  timer_current_time(current);
398 <                timer_sub_time(remaining, desc[i].wakeup, current);
398 >                timer_sub_time(remaining, desc->wakeup, current);
399                  WriteMacInt32(tm + tmCount, timer_host2mac_time(remaining));
400          } else
401                  WriteMacInt32(tm + tmCount, 0);
# Line 391 | Line 408 | int16 RmvTime(uint32 tm)
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 + #ifdef PRECISE_TIMING_MACH
412 +        semaphore_signal(wakeup_time_sem);
413 +        thread_abort(timer_thread);
414 +        thread_resume(timer_thread);
415 + #endif
416   #if PRECISE_TIMING_POSIX
417          pthread_mutex_unlock(&wakeup_time_lock);
418          timer_thread_resume();
# Line 398 | Line 420 | int16 RmvTime(uint32 tm)
420   #endif
421  
422          // Free descriptor
423 <        free_desc(i);
423 >        free_desc(desc);
424          return 0;
425   }
426  
# Line 412 | Line 434 | int16 PrimeTime(uint32 tm, int32 time)
434          D(bug("PrimeTime %08lx, time %ld\n", tm, time));
435  
436          // Find descriptor
437 <        int i = find_desc(tm);
438 <        if (i < 0) {
439 <                printf("FATAL: PrimeTime(): Descriptor not found\n");
437 >        TMDesc *desc = find_desc(tm);
438 >        if (!desc) {
439 >                printf("FATAL: PrimeTime(%08lx): Descriptor not found\n", tm);
440                  return 0;
441          }
442  
# Line 430 | Line 452 | int16 PrimeTime(uint32 tm, int32 time)
452  
453                          // 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 <                        // then re-installed using InsXTime(). This currently only handles (a).
456 <                        //
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?)
455 >                        // then re-installed using InsXTime(). Since tmWakeUp was set, this is case (b).
456 >                        // The remaining time was saved in tmCount by RmvTime().
457                          if (time == 0) {
458 <                                printf("FATAL: Unsupported PrimeTime(0)\n");
442 <                                return 0;
458 >                                timer_mac2host_time(delay, ReadMacInt16(tm + tmCount));
459                          }
444 #endif
460  
461                          // Yes, calculate wakeup time relative to last scheduled time
462                          tm_time_t wakeup;
463 <                        timer_add_time(wakeup, desc[i].wakeup, delay);
464 <                        desc[i].wakeup = wakeup;
463 >                        timer_add_time(wakeup, desc->wakeup, delay);
464 >                        desc->wakeup = wakeup;
465  
466                  } else {
467  
468                          // No, calculate wakeup time relative to current time
469                          tm_time_t now;
470                          timer_current_time(now);
471 <                        timer_add_time(desc[i].wakeup, now, delay);
471 >                        timer_add_time(desc->wakeup, now, delay);
472                  }
473  
474                  // Set tmWakeUp to indicate that task was scheduled
# Line 464 | Line 479 | int16 PrimeTime(uint32 tm, int32 time)
479                  // Not extended task, calculate wakeup time relative to current time
480                  tm_time_t now;
481                  timer_current_time(now);
482 <                timer_add_time(desc[i].wakeup, now, delay);
482 >                timer_add_time(desc->wakeup, now, delay);
483          }
484  
485          // Make task active and enqueue it in the Time Manager queue
# Line 472 | Line 487 | int16 PrimeTime(uint32 tm, int32 time)
487          while (acquire_sem(wakeup_time_sem) == B_INTERRUPTED) ;
488          suspend_thread(timer_thread);
489   #endif
490 + #ifdef PRECISE_TIMING_MACH
491 +        semaphore_wait(wakeup_time_sem);
492 +        thread_suspend(timer_thread);
493 + #endif
494   #if PRECISE_TIMING_POSIX
495          timer_thread_suspend();
496          pthread_mutex_lock(&wakeup_time_lock);
# Line 481 | Line 500 | int16 PrimeTime(uint32 tm, int32 time)
500   #if PRECISE_TIMING
501          // Look for next task to be called and set wakeup_time
502          wakeup_time = wakeup_time_max;
503 <        for (int j=0; j<NUM_DESCS; j++) {
504 <                if (desc[j].in_use && (ReadMacInt16(desc[j].task + qType) & 0x8000))
505 <                        if (timer_cmp_time(desc[j].wakeup, wakeup_time) < 0)
506 <                                wakeup_time = desc[j].wakeup;
488 <        }
503 >        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   #ifdef PRECISE_TIMING_BEOS
508          release_sem(wakeup_time_sem);
509          thread_info info;
# Line 494 | Line 512 | int16 PrimeTime(uint32 tm, int32 time)
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 + #ifdef PRECISE_TIMING_MACH
516 +        semaphore_signal(wakeup_time_sem);
517 +        thread_abort(timer_thread);
518 +        thread_resume(timer_thread);
519 + #endif
520   #ifdef PRECISE_TIMING_POSIX
521          pthread_mutex_unlock(&wakeup_time_lock);
522          timer_thread_resume();
# Line 530 | Line 553 | static int32 timer_func(void *arg)
553   }
554   #endif
555  
556 + #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 +        return NULL;
577 + }
578 + #endif
579 +
580   #ifdef PRECISE_TIMING_POSIX
581   static void *timer_func(void *arg)
582   {
583          while (!timer_thread_cancel) {
537
584                  // Wait until time specified by wakeup_time
585                  clock_nanosleep(CLOCK_REALTIME, TIMER_ABSTIME, &wakeup_time, NULL);
586  
# Line 566 | Line 612 | void TimerInterrupt(void)
612          // Look for active TMTasks that have expired
613          tm_time_t now;
614          timer_current_time(now);
615 <        for (int i=0; i<NUM_DESCS; i++)
616 <                if (desc[i].in_use) {
617 <                        uint32 tm = desc[i].task;
618 <                        if ((ReadMacInt16(tm + qType) & 0x8000) && timer_cmp_time(desc[i].wakeup, now) <= 0) {
619 <
620 <                                // Found one, mark as inactive and remove it from the Time Manager queue
621 <                                WriteMacInt16(tm + qType, ReadMacInt16(tm + qType) & 0x7fff);
622 <                                dequeue_tm(tm);
623 <
624 <                                // Call timer function
625 <                                uint32 addr = ReadMacInt32(tm + tmAddr);
626 <                                if (addr) {
627 <                                        D(bug("Calling TimeTask %08lx, addr %08lx\n", tm, addr));
628 <                                        M68kRegisters r;
629 <                                        r.a[0] = addr;
630 <                                        r.a[1] = tm;
631 <                                        Execute68k(r.a[0], &r);
632 <                                        D(bug(" returned from TimeTask\n"));
633 <                                }
615 >        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                          }
635                  }
636 +                desc = next;
637 +        }
638  
639   #if PRECISE_TIMING
640          // Look for next task to be called and set wakeup_time
# Line 594 | Line 642 | void TimerInterrupt(void)
642          while (acquire_sem(wakeup_time_sem) == B_INTERRUPTED) ;
643          suspend_thread(timer_thread);
644   #endif
645 + #if PRECISE_TIMING_MACH
646 +        semaphore_wait(wakeup_time_sem);
647 +        thread_suspend(timer_thread);
648 + #endif
649   #if PRECISE_TIMING_POSIX
650          timer_thread_suspend();
651          pthread_mutex_lock(&wakeup_time_lock);
652   #endif
653          wakeup_time = wakeup_time_max;
654 <        for (int j=0; j<NUM_DESCS; j++) {
655 <                if (desc[j].in_use && (ReadMacInt16(desc[j].task + qType) & 0x8000))
656 <                        if (timer_cmp_time(desc[j].wakeup, wakeup_time) < 0)
657 <                                wakeup_time = desc[j].wakeup;
606 <        }
654 >        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   #if PRECISE_TIMING_BEOS
659          release_sem(wakeup_time_sem);
660          thread_info info;
# Line 612 | Line 663 | void TimerInterrupt(void)
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 + #if PRECISE_TIMING_MACH
667 +        semaphore_signal(wakeup_time_sem);
668 +        thread_abort(timer_thread);
669 +        thread_resume(timer_thread);
670 + #endif
671   #if PRECISE_TIMING_POSIX
672          pthread_mutex_unlock(&wakeup_time_lock);
673          timer_thread_resume();

Diff Legend

Removed lines
+ Added lines
< Changed lines
> Changed lines