/* * timer.cpp - Time Manager emulation * * SheepShaver (C) 1997-2008 Christian Bauer and Marc Hellwig * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ /* * TODO: Prime(0) */ #include "sysdeps.h" #include "timer.h" #include "macos_util.h" #include "main.h" #include "cpu_emulation.h" #ifdef PRECISE_TIMING_POSIX #include #include #endif #define DEBUG 0 #include "debug.h" #define TM_QUEUE 0 // Enable TMQueue management (doesn't work) // Definitions for Time Manager enum { // TMTask struct tmAddr = 6, tmCount = 10, tmWakeUp = 14, tmReserved = 18 }; // Array of additional info for each installed TMTask struct TMDesc { uint32 task; // Mac address of associated TMTask tm_time_t wakeup; // Time this task is scheduled for execution bool in_use; // Flag: descriptor in use }; const int NUM_DESCS = 64; // Maximum number of descriptors static TMDesc desc[NUM_DESCS]; #if PRECISE_TIMING #ifdef PRECISE_TIMING_BEOS static thread_id timer_thread = -1; static bool thread_active = true; static const tm_time_t wakeup_time_max = 0x7fffffffffffffff; static volatile tm_time_t wakeup_time = wakeup_time_max; static sem_id wakeup_time_sem = -1; static int32 timer_func(void *arg); #endif #ifdef PRECISE_TIMING_POSIX static pthread_t timer_thread; static bool timer_thread_active = false; static volatile bool timer_thread_cancel = false; static tm_time_t wakeup_time_max = { 0x7fffffff, 999999999 }; static tm_time_t wakeup_time = wakeup_time_max; static pthread_mutex_t wakeup_time_lock = PTHREAD_MUTEX_INITIALIZER; static void *timer_func(void *arg); #endif #endif /* * Allocate descriptor for given TMTask in list */ static int alloc_desc(uint32 tm) { // Search for first free descriptor for (int i=0; i 0); if (suspend_count == 1) { suspend_count = 0; pthread_kill(timer_thread, SIGRESUME); } pthread_mutex_unlock(&suspend_count_lock); } #endif /* * Initialize Time Manager */ void TimerInit(void) { // Mark all descriptors as inactive for (int i=0; i 0) { #ifdef PRECISE_TIMING_BEOS status_t l; thread_active = false; suspend_thread(timer_thread); resume_thread(timer_thread); wait_for_thread(timer_thread, &l); delete_sem(wakeup_time_sem); #endif #ifdef PRECISE_TIMING_POSIX timer_thread_kill(); #endif } #endif } /* * Emulator reset, remove all timer tasks */ void TimerReset(void) { // Mark all descriptors as inactive for (int i=0; i= 0) printf("WARNING: InsTime(): Task re-inserted\n"); else { int i = alloc_desc(tm); if (i < 0) printf("FATAL: InsTime(): No free Time Manager descriptor\n"); } return 0; } /* * Remove timer task */ int16 RmvTime(uint32 tm) { D(bug("RmvTime %08lx\n", tm)); // Find descriptor int i = find_desc(tm); if (i < 0) { printf("WARNING: RmvTime(%08lx): Descriptor not found\n", tm); return 0; } // Task active? #if PRECISE_TIMING_BEOS while (acquire_sem(wakeup_time_sem) == B_INTERRUPTED) ; suspend_thread(timer_thread); #endif #if PRECISE_TIMING_POSIX timer_thread_suspend(); pthread_mutex_lock(&wakeup_time_lock); #endif if (ReadMacInt16(tm + qType) & 0x8000) { // Yes, make task inactive and remove it from the Time Manager queue WriteMacInt16(tm + qType, ReadMacInt16(tm + qType) & 0x7fff); dequeue_tm(tm); #if PRECISE_TIMING // Look for next task to be called and set wakeup_time wakeup_time = wakeup_time_max; for (int j=0; j