ViewVC Help
View File | Revision Log | Show Annotations | Revision Graph | Root Listing
root/cebix/BasiliskII/src/Windows/timer_windows.cpp
Revision: 1.6
Committed: 2006-05-01T06:12:50Z (18 years, 7 months ago) by gbeauche
Branch: MAIN
Changes since 1.5: +57 -0 lines
Log Message:
Implement better Windows suspend/resume routines so that we don't oversleep.
i.e. really wake up the thread on next TriggerInterrupt().

File Contents

# User Rev Content
1 gbeauche 1.1 /*
2     * timer_windows.cpp - Time Manager emulation, Windows specific stuff
3     *
4 gbeauche 1.4 * Basilisk II (C) 1997-2005 Christian Bauer
5 gbeauche 1.1 *
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
8     * the Free Software Foundation; either version 2 of the License, or
9     * (at your option) any later version.
10     *
11     * This program is distributed in the hope that it will be useful,
12     * but WITHOUT ANY WARRANTY; without even the implied warranty of
13     * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14     * GNU General Public License for more details.
15     *
16     * You should have received a copy of the GNU General Public License
17     * along with this program; if not, write to the Free Software
18     * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
19     */
20    
21     #include "sysdeps.h"
22    
23     #define WIN32_LEAN_AND_MEAN
24     #include <windows.h>
25    
26     #include "main.h"
27     #include "macos_util.h"
28     #include "timer.h"
29    
30     #define DEBUG 0
31     #include "debug.h"
32    
33    
34     // Helper time functions
35     #define MSECS2TICKS(MSECS) (((uint64)(MSECS) * frequency) / 1000)
36     #define USECS2TICKS(USECS) (((uint64)(USECS) * frequency) / 1000000)
37     #define TICKS2USECS(TICKS) (((uint64)(TICKS) * 1000000) / frequency)
38    
39 gbeauche 1.6 // From main_windows.cpp
40     extern HANDLE emul_thread;
41    
42 gbeauche 1.1 // Global variables
43     static uint32 frequency; // CPU frequency in Hz (< 4 GHz)
44     static tm_time_t mac_boot_ticks;
45     static tm_time_t mac_1904_ticks;
46     static tm_time_t mac_now_diff;
47    
48    
49     /*
50     * Initialize native Windows timers
51     */
52    
53 gbeauche 1.3 void timer_init(void)
54 gbeauche 1.1 {
55     D(bug("SysTimerInit\n"));
56    
57     LARGE_INTEGER tt;
58     if (!QueryPerformanceFrequency(&tt)) {
59     ErrorAlert("No high resolution timers available\n");
60     QuitEmulator();
61     }
62     frequency = tt.LowPart;
63     D(bug(" frequency %d\n", frequency));
64    
65     // mac_boot_ticks is 1.18 us since Basilisk II was started
66     QueryPerformanceCounter(&tt);
67     mac_boot_ticks = tt.QuadPart;
68    
69     // mac_1904_ticks is 1.18 us since Mac time started 1904
70     mac_1904_ticks = time(NULL) * frequency;
71     mac_now_diff = mac_1904_ticks - mac_boot_ticks;
72     }
73    
74    
75     /*
76     * Return microseconds since boot (64 bit)
77     */
78    
79     void Microseconds(uint32 &hi, uint32 &lo)
80     {
81     D(bug("Microseconds\n"));
82     LARGE_INTEGER tt;
83     QueryPerformanceCounter(&tt);
84     tt.QuadPart = TICKS2USECS(tt.QuadPart - mac_boot_ticks);
85     hi = tt.HighPart;
86     lo = tt.LowPart;
87     }
88    
89    
90     /*
91     * Return local date/time in Mac format (seconds since 1.1.1904)
92     */
93    
94     uint32 TimerDateTime(void)
95     {
96     return TimeToMacTime(time(NULL));
97     }
98    
99    
100     /*
101     * Get current time
102     */
103    
104     void timer_current_time(tm_time_t &t)
105     {
106     LARGE_INTEGER tt;
107     QueryPerformanceCounter(&tt);
108     t = tt.QuadPart + mac_now_diff;
109     }
110    
111    
112     /*
113     * Add times
114     */
115    
116     void timer_add_time(tm_time_t &res, tm_time_t a, tm_time_t b)
117     {
118     res = a + b;
119     }
120    
121    
122     /*
123     * Subtract times
124     */
125    
126     void timer_sub_time(tm_time_t &res, tm_time_t a, tm_time_t b)
127     {
128     res = a - b;
129     }
130    
131    
132     /*
133     * Compare times (<0: a < b, =0: a = b, >0: a > b)
134     */
135    
136     int timer_cmp_time(tm_time_t a, tm_time_t b)
137     {
138     tm_time_t r = a - b;
139     return r < 0 ? -1 : (r > 0 ? 1 : 0);
140     }
141    
142    
143     /*
144     * Convert Mac time value (>0: microseconds, <0: microseconds) to tm_time_t
145     */
146    
147     void timer_mac2host_time(tm_time_t &res, int32 mactime)
148     {
149     if (mactime > 0) {
150     // Time in milliseconds
151     res = MSECS2TICKS(mactime);
152     } else {
153     // Time in negative microseconds
154     res = USECS2TICKS(-mactime);
155     }
156     }
157    
158    
159     /*
160     * Convert positive tm_time_t to Mac time value (>0: microseconds, <0: microseconds)
161     * A negative input value for hosttime results in a zero return value
162     * As long as the microseconds value fits in 32 bit, it must not be converted to milliseconds!
163     */
164    
165     int32 timer_host2mac_time(tm_time_t hosttime)
166     {
167     if (hosttime < 0)
168     return 0;
169     else {
170 gbeauche 1.2 uint64 t = TICKS2USECS(hosttime);
171 gbeauche 1.1 if (t > 0x7fffffff)
172     return t / 1000; // Time in milliseconds
173     else
174     return -t; // Time in negative microseconds
175     }
176     }
177    
178    
179     /*
180     * Get current value of microsecond timer
181     */
182    
183     uint64 GetTicks_usec(void)
184     {
185     LARGE_INTEGER tt;
186     QueryPerformanceCounter(&tt);
187     return TICKS2USECS(tt.QuadPart - mac_boot_ticks);
188     }
189    
190    
191     /*
192     * Delay by specified number of microseconds (<1 second)
193     */
194    
195     void Delay_usec(uint32 usec)
196     {
197     // FIXME: fortunately, Delay_usec() is generally used with
198     // millisecond resolution anyway
199     Sleep(usec / 1000);
200     }
201 gbeauche 1.5
202    
203     /*
204     * Suspend emulator thread, virtual CPU in idle mode
205     */
206    
207 gbeauche 1.6 struct idle_sentinel {
208     idle_sentinel();
209     ~idle_sentinel();
210     };
211     static idle_sentinel idle_sentinel;
212    
213     static int idle_sem_ok = -1;
214     static HANDLE idle_sem = NULL;
215    
216     static HANDLE idle_lock = NULL;
217     #define LOCK_IDLE WaitForSingleObject(idle_lock, INFINITE)
218     #define UNLOCK_IDLE ReleaseMutex(idle_lock)
219    
220     idle_sentinel::idle_sentinel()
221     {
222     LOCK_IDLE;
223     idle_sem_ok = 1;
224     if ((idle_sem = CreateSemaphore(0, 0, 1, NULL)) == NULL)
225     idle_sem_ok = 0;
226     if ((idle_lock = CreateMutex(NULL, FALSE, NULL)) == NULL)
227     idle_sem_ok = 0;
228     UNLOCK_IDLE;
229     }
230    
231     idle_sentinel::~idle_sentinel()
232     {
233     if (idle_lock) {
234     ReleaseMutex(idle_lock);
235     CloseHandle(idle_lock);
236     }
237     if (idle_sem) {
238     ReleaseSemaphore(idle_sem, 1, NULL);
239     CloseHandle(idle_sem);
240     }
241     }
242    
243 gbeauche 1.5 void idle_wait(void)
244     {
245 gbeauche 1.6 LOCK_IDLE;
246     if (idle_sem_ok > 0) {
247     idle_sem_ok++;
248     UNLOCK_IDLE;
249     WaitForSingleObject(idle_sem, INFINITE);
250     return;
251     }
252     UNLOCK_IDLE;
253    
254     // Fallback: sleep 10 ms (this should not happen though)
255 gbeauche 1.5 Delay_usec(10000);
256     }
257    
258    
259     /*
260     * Resume execution of emulator thread, events just arrived
261     */
262    
263     void idle_resume(void)
264     {
265 gbeauche 1.6 LOCK_IDLE;
266     if (idle_sem_ok > 1) {
267     idle_sem_ok--;
268     UNLOCK_IDLE;
269     ReleaseSemaphore(idle_sem, 1, NULL);
270     return;
271     }
272     UNLOCK_IDLE;
273 gbeauche 1.5 }