ViewVC Help
View File | Revision Log | Show Annotations | Revision Graph | Root Listing
root/cebix/BasiliskII/src/Unix/timer_unix.cpp
(Generate patch)

Comparing BasiliskII/src/Unix/timer_unix.cpp (file contents):
Revision 1.9 by cebix, 2001-02-02T20:52:58Z vs.
Revision 1.19 by gbeauche, 2006-05-01T13:13:18Z

# Line 1 | Line 1
1   /*
2   *  timer_unix.cpp - Time Manager emulation, Unix specific stuff
3   *
4 < *  Basilisk II (C) 1997-2001 Christian Bauer
4 > *  Basilisk II (C) 1997-2005 Christian Bauer
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 19 | Line 19
19   */
20  
21   #include "sysdeps.h"
22 + #include "macos_util.h"
23   #include "timer.h"
24  
25 + #include <errno.h>
26 +
27   #define DEBUG 0
28   #include "debug.h"
29  
# Line 57 | Line 60 | void Microseconds(uint32 &hi, uint32 &lo
60  
61   uint32 TimerDateTime(void)
62   {
63 <        time_t utc_now = time(NULL);
61 < #if defined(__linux__) || defined(__SVR4)
62 <        time_t local_now = utc_now - timezone;
63 < #elif defined(__FreeBSD__) || defined(__NetBSD__)
64 <        time_t local_now = utc_now + localtime(&utc_now)->tm_gmtoff;
65 < #else
66 <        time_t local_now = utc_now;
67 < #endif
68 <        return (uint32)local_now + TIME_OFFSET;
63 >        return TimeToMacTime(time(NULL));
64   }
65  
66  
# Line 203 | Line 198 | int32 timer_host2mac_time(tm_time_t host
198                          return -t;                      // Time in negative microseconds
199          }
200   }
201 +
202 +
203 + /*
204 + *  Get current value of microsecond timer
205 + */
206 +
207 + uint64 GetTicks_usec(void)
208 + {
209 + #ifdef HAVE_CLOCK_GETTIME
210 +        struct timespec t;
211 +        clock_gettime(CLOCK_REALTIME, &t);
212 +        return (uint64)t.tv_sec * 1000000 + t.tv_nsec / 1000;
213 + #else
214 +        struct timeval t;
215 +        gettimeofday(&t, NULL);
216 +        return (uint64)t.tv_sec * 1000000 + t.tv_usec;
217 + #endif
218 + }
219 +
220 +
221 + /*
222 + *  Delay by specified number of microseconds (<1 second)
223 + *  (adapted from SDL_Delay() source; this function is designed to provide
224 + *  the highest accuracy possible)
225 + */
226 +
227 + #if defined(linux)
228 + // Linux select() changes its timeout parameter upon return to contain
229 + // the remaining time. Most other unixen leave it unchanged or undefined.
230 + #define SELECT_SETS_REMAINING
231 + #elif defined(__FreeBSD__) || defined(__sun__) || (defined(__MACH__) && defined(__APPLE__))
232 + #define USE_NANOSLEEP
233 + #elif defined(HAVE_PTHREADS) && defined(sgi)
234 + // SGI pthreads has a bug when using pthreads+signals+nanosleep,
235 + // so instead of using nanosleep, wait on a CV which is never signalled.
236 + #include <pthread.h>
237 + #define USE_COND_TIMEDWAIT
238 + #endif
239 +
240 + void Delay_usec(uint32 usec)
241 + {
242 +        int was_error;
243 +
244 + #if defined(USE_NANOSLEEP)
245 +        struct timespec elapsed, tv;
246 + #elif defined(USE_COND_TIMEDWAIT)
247 +        // Use a local mutex and cv, so threads remain independent
248 +        pthread_cond_t delay_cond = PTHREAD_COND_INITIALIZER;
249 +        pthread_mutex_t delay_mutex = PTHREAD_MUTEX_INITIALIZER;
250 +        struct timespec elapsed;
251 +        uint64 future;
252 + #else
253 +        struct timeval tv;
254 + #ifndef SELECT_SETS_REMAINING
255 +        uint64 then, now, elapsed;
256 + #endif
257 + #endif
258 +
259 +        // Set the timeout interval - Linux only needs to do this once
260 + #if defined(SELECT_SETS_REMAINING)
261 +    tv.tv_sec = 0;
262 +    tv.tv_usec = usec;
263 + #elif defined(USE_NANOSLEEP)
264 +    elapsed.tv_sec = 0;
265 +    elapsed.tv_nsec = usec * 1000;
266 + #elif defined(USE_COND_TIMEDWAIT)
267 +        future = GetTicks_usec() + usec;
268 +        elapsed.tv_sec = future / 1000000;
269 +        elapsed.tv_nsec = (future % 1000000) * 1000;
270 + #else
271 +    then = GetTicks_usec();
272 + #endif
273 +
274 +        do {
275 +                errno = 0;
276 + #if defined(USE_NANOSLEEP)
277 +                tv.tv_sec = elapsed.tv_sec;
278 +                tv.tv_nsec = elapsed.tv_nsec;
279 +                was_error = nanosleep(&tv, &elapsed);
280 + #elif defined(USE_COND_TIMEDWAIT)
281 +                was_error = pthread_mutex_lock(&delay_mutex);
282 +                was_error = pthread_cond_timedwait(&delay_cond, &delay_mutex, &elapsed);
283 +                was_error = pthread_mutex_unlock(&delay_mutex);
284 + #else
285 + #ifndef SELECT_SETS_REMAINING
286 +                // Calculate the time interval left (in case of interrupt)
287 +                now = GetTicks_usec();
288 +                elapsed = now - then;
289 +                then = now;
290 +                if (elapsed >= usec)
291 +                        break;
292 +                usec -= elapsed;
293 +                tv.tv_sec = 0;
294 +                tv.tv_usec = usec;
295 + #endif
296 +                was_error = select(0, NULL, NULL, NULL, &tv);
297 + #endif
298 +        } while (was_error && (errno == EINTR));
299 + }
300 +
301 +
302 + /*
303 + *  Suspend emulator thread, virtual CPU in idle mode
304 + */
305 +
306 + #ifdef HAVE_PTHREADS
307 + #if defined(HAVE_PTHREAD_COND_INIT)
308 + #define IDLE_USES_COND_WAIT 1
309 + static pthread_mutex_t idle_lock = PTHREAD_MUTEX_INITIALIZER;
310 + static pthread_cond_t idle_cond = PTHREAD_COND_INITIALIZER;
311 + #elif defined(HAVE_SEM_INIT)
312 + #define IDLE_USES_SEMAPHORE 1
313 + #include <semaphore.h>
314 + #ifdef HAVE_SPINLOCKS
315 + static spinlock_t idle_lock = SPIN_LOCK_UNLOCKED;
316 + #define LOCK_IDLE spin_lock(&idle_lock)
317 + #define UNLOCK_IDLE spin_unlock(&idle_lock)
318 + #else
319 + static pthread_mutex_t idle_lock = PTHREAD_MUTEX_INITIALIZER;
320 + #define LOCK_IDLE pthread_mutex_lock(&idle_lock)
321 + #define UNLOCK_IDLE pthread_mutex_unlock(&idle_lock)
322 + #endif
323 + static sem_t idle_sem;
324 + static int idle_sem_ok = -1;
325 + #endif
326 + #endif
327 +
328 + void idle_wait(void)
329 + {
330 + #ifdef IDLE_USES_COND_WAIT
331 +        pthread_mutex_lock(&idle_lock);
332 +        pthread_cond_wait(&idle_cond, &idle_lock);
333 +        pthread_mutex_unlock(&idle_lock);
334 + #else
335 + #ifdef IDLE_USES_SEMAPHORE
336 +        LOCK_IDLE;
337 +        if (idle_sem_ok < 0)
338 +                idle_sem_ok = (sem_init(&idle_sem, 0, 0) == 0);
339 +        if (idle_sem_ok > 0) {
340 +                idle_sem_ok++;
341 +                UNLOCK_IDLE;
342 +                sem_wait(&idle_sem);
343 +                return;
344 +        }
345 +        UNLOCK_IDLE;
346 + #endif
347 +
348 +        // Fallback: sleep 10 ms
349 +        Delay_usec(10000);
350 + #endif
351 + }
352 +
353 +
354 + /*
355 + *  Resume execution of emulator thread, events just arrived
356 + */
357 +
358 + void idle_resume(void)
359 + {
360 + #ifdef IDLE_USES_COND_WAIT
361 +        pthread_cond_signal(&idle_cond);
362 + #else
363 + #ifdef IDLE_USES_SEMAPHORE
364 +        LOCK_IDLE;
365 +        if (idle_sem_ok > 1) {
366 +                idle_sem_ok--;
367 +                UNLOCK_IDLE;
368 +                sem_post(&idle_sem);
369 +                return;
370 +        }
371 +        UNLOCK_IDLE;
372 + #endif
373 + #endif
374 + }

Diff Legend

Removed lines
+ Added lines
< Changed lines
> Changed lines