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.6 by cebix, 2000-02-21T20:04:18Z vs.
Revision 1.22 by asvitkine, 2009-08-21T17:39:58Z

# Line 1 | Line 1
1   /*
2   *  timer_unix.cpp - Time Manager emulation, Unix specific stuff
3   *
4 < *  Basilisk II (C) 1997-1999 Christian Bauer
4 > *  Basilisk II (C) 1997-2008 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  
30 + // For NetBSD with broken pthreads headers
31 + #ifndef CLOCK_REALTIME
32 + #define CLOCK_REALTIME 0
33 + #endif
34 +
35 + #if defined(__MACH__)
36 + #include <mach/mach.h>
37 + #include <mach/clock.h>
38 +
39 + static clock_serv_t host_clock;
40 + static bool host_clock_inited = false;
41 +
42 + static inline void mach_current_time(tm_time_t &t) {
43 +        if(!host_clock_inited) {
44 +                host_get_clock_service(mach_host_self(), SYSTEM_CLOCK, &host_clock);
45 +                host_clock_inited = true;
46 +        }
47 +        
48 +        clock_get_time(host_clock, &t);
49 + }
50 + #endif
51 +
52  
53   /*
54   *  Return microseconds since boot (64 bit)
# Line 32 | Line 57
57   void Microseconds(uint32 &hi, uint32 &lo)
58   {
59          D(bug("Microseconds\n"));
60 < #ifdef HAVE_CLOCK_GETTIME
60 > #if defined(HAVE_CLOCK_GETTIME)
61          struct timespec t;
62          clock_gettime(CLOCK_REALTIME, &t);
63          uint64 tl = (uint64)t.tv_sec * 1000000 + t.tv_nsec / 1000;
64 + #elif defined(__MACH__)
65 +        tm_time_t t;
66 +        mach_current_time(t);
67 +        uint64 tl = (uint64)t.tv_sec * 1000000 + t.tv_nsec / 1000;
68   #else
69          struct timeval t;
70          gettimeofday(&t, NULL);
# Line 52 | Line 81 | void Microseconds(uint32 &hi, uint32 &lo
81  
82   uint32 TimerDateTime(void)
83   {
84 <        time_t utc_now = time(NULL);
56 < #if defined(__linux__) || defined(__SVR4)
57 <        time_t local_now = utc_now - timezone;
58 < #elif defined(__FreeBSD__) || defined(__NetBSD__)
59 <        time_t local_now = utc_now + localtime(&utc_now)->tm_gmtoff;
60 < #else
61 <        time_t local_now = utc_now;
62 < #endif
63 <        return (uint32)local_now + TIME_OFFSET;
84 >        return TimeToMacTime(time(NULL));
85   }
86  
87  
# Line 72 | Line 93 | void timer_current_time(tm_time_t &t)
93   {
94   #ifdef HAVE_CLOCK_GETTIME
95          clock_gettime(CLOCK_REALTIME, &t);
96 + #elif defined(__MACH__)
97 +        mach_current_time(t);
98   #else
99          gettimeofday(&t, NULL);
100   #endif
# Line 84 | Line 107 | void timer_current_time(tm_time_t &t)
107  
108   void timer_add_time(tm_time_t &res, tm_time_t a, tm_time_t b)
109   {
110 < #ifdef HAVE_CLOCK_GETTIME
110 > #if defined(HAVE_CLOCK_GETTIME) || defined(__MACH__)
111          res.tv_sec = a.tv_sec + b.tv_sec;
112          res.tv_nsec = a.tv_nsec + b.tv_nsec;
113          if (res.tv_nsec >= 1000000000) {
# Line 108 | Line 131 | void timer_add_time(tm_time_t &res, tm_t
131  
132   void timer_sub_time(tm_time_t &res, tm_time_t a, tm_time_t b)
133   {
134 < #ifdef HAVE_CLOCK_GETTIME
134 > #if defined(HAVE_CLOCK_GETTIME) || defined(__MACH__)
135          res.tv_sec = a.tv_sec - b.tv_sec;
136          res.tv_nsec = a.tv_nsec - b.tv_nsec;
137          if (res.tv_nsec < 0) {
# Line 132 | Line 155 | void timer_sub_time(tm_time_t &res, tm_t
155  
156   int timer_cmp_time(tm_time_t a, tm_time_t b)
157   {
158 < #ifdef HAVE_CLOCK_GETTIME
158 > #if defined(HAVE_CLOCK_GETTIME) || defined(__MACH__)
159          if (a.tv_sec == b.tv_sec)
160                  return a.tv_nsec - b.tv_nsec;
161          else
# Line 152 | Line 175 | int timer_cmp_time(tm_time_t a, tm_time_
175  
176   void timer_mac2host_time(tm_time_t &res, int32 mactime)
177   {
178 < #ifdef HAVE_CLOCK_GETTIME
178 > #if defined(HAVE_CLOCK_GETTIME) || defined(__MACH__)
179          if (mactime > 0) {
180                  // Time in milliseconds
181                  res.tv_sec = mactime / 1000;
# Line 187 | Line 210 | int32 timer_host2mac_time(tm_time_t host
210          if (hosttime.tv_sec < 0)
211                  return 0;
212          else {
213 < #ifdef HAVE_CLOCK_GETTIME
213 > #if defined(HAVE_CLOCK_GETTIME) || defined(__MACH__)
214                  uint64 t = (uint64)hosttime.tv_sec * 1000000 + hosttime.tv_nsec / 1000;
215   #else
216                  uint64 t = (uint64)hosttime.tv_sec * 1000000 + hosttime.tv_usec;
# Line 198 | Line 221 | int32 timer_host2mac_time(tm_time_t host
221                          return -t;                      // Time in negative microseconds
222          }
223   }
224 +
225 +
226 + /*
227 + *  Get current value of microsecond timer
228 + */
229 +
230 + uint64 GetTicks_usec(void)
231 + {
232 + #ifdef HAVE_CLOCK_GETTIME
233 +        struct timespec t;
234 +        clock_gettime(CLOCK_REALTIME, &t);
235 +        return (uint64)t.tv_sec * 1000000 + t.tv_nsec / 1000;
236 + #elif defined(__MACH__)
237 +        tm_time_t t;
238 +        mach_current_time(t);
239 +        return (uint64)t.tv_sec * 1000000 + t.tv_nsec / 1000;
240 + #else
241 +        struct timeval t;
242 +        gettimeofday(&t, NULL);
243 +        return (uint64)t.tv_sec * 1000000 + t.tv_usec;
244 + #endif
245 + }
246 +
247 +
248 + /*
249 + *  Delay by specified number of microseconds (<1 second)
250 + *  (adapted from SDL_Delay() source; this function is designed to provide
251 + *  the highest accuracy possible)
252 + */
253 +
254 + #if defined(linux)
255 + // Linux select() changes its timeout parameter upon return to contain
256 + // the remaining time. Most other unixen leave it unchanged or undefined.
257 + #define SELECT_SETS_REMAINING
258 + #elif defined(__FreeBSD__) || defined(__sun__) || (defined(__MACH__) && defined(__APPLE__))
259 + #define USE_NANOSLEEP
260 + #elif defined(HAVE_PTHREADS) && defined(sgi)
261 + // SGI pthreads has a bug when using pthreads+signals+nanosleep,
262 + // so instead of using nanosleep, wait on a CV which is never signalled.
263 + #include <pthread.h>
264 + #define USE_COND_TIMEDWAIT
265 + #endif
266 +
267 + void Delay_usec(uint32 usec)
268 + {
269 +        int was_error;
270 +
271 + #if defined(USE_NANOSLEEP)
272 +        struct timespec elapsed, tv;
273 + #elif defined(USE_COND_TIMEDWAIT)
274 +        // Use a local mutex and cv, so threads remain independent
275 +        pthread_cond_t delay_cond = PTHREAD_COND_INITIALIZER;
276 +        pthread_mutex_t delay_mutex = PTHREAD_MUTEX_INITIALIZER;
277 +        struct timespec elapsed;
278 +        uint64 future;
279 + #else
280 +        struct timeval tv;
281 + #ifndef SELECT_SETS_REMAINING
282 +        uint64 then, now, elapsed;
283 + #endif
284 + #endif
285 +
286 +        // Set the timeout interval - Linux only needs to do this once
287 + #if defined(SELECT_SETS_REMAINING)
288 +    tv.tv_sec = 0;
289 +    tv.tv_usec = usec;
290 + #elif defined(USE_NANOSLEEP)
291 +    elapsed.tv_sec = 0;
292 +    elapsed.tv_nsec = usec * 1000;
293 + #elif defined(USE_COND_TIMEDWAIT)
294 +        future = GetTicks_usec() + usec;
295 +        elapsed.tv_sec = future / 1000000;
296 +        elapsed.tv_nsec = (future % 1000000) * 1000;
297 + #else
298 +    then = GetTicks_usec();
299 + #endif
300 +
301 +        do {
302 +                errno = 0;
303 + #if defined(USE_NANOSLEEP)
304 +                tv.tv_sec = elapsed.tv_sec;
305 +                tv.tv_nsec = elapsed.tv_nsec;
306 +                was_error = nanosleep(&tv, &elapsed);
307 + #elif defined(USE_COND_TIMEDWAIT)
308 +                was_error = pthread_mutex_lock(&delay_mutex);
309 +                was_error = pthread_cond_timedwait(&delay_cond, &delay_mutex, &elapsed);
310 +                was_error = pthread_mutex_unlock(&delay_mutex);
311 + #else
312 + #ifndef SELECT_SETS_REMAINING
313 +                // Calculate the time interval left (in case of interrupt)
314 +                now = GetTicks_usec();
315 +                elapsed = now - then;
316 +                then = now;
317 +                if (elapsed >= usec)
318 +                        break;
319 +                usec -= elapsed;
320 +                tv.tv_sec = 0;
321 +                tv.tv_usec = usec;
322 + #endif
323 +                was_error = select(0, NULL, NULL, NULL, &tv);
324 + #endif
325 +        } while (was_error && (errno == EINTR));
326 + }
327 +
328 +
329 + /*
330 + *  Suspend emulator thread, virtual CPU in idle mode
331 + */
332 +
333 + #ifdef HAVE_PTHREADS
334 + #if defined(HAVE_PTHREAD_COND_INIT)
335 + #define IDLE_USES_COND_WAIT 1
336 + static pthread_mutex_t idle_lock = PTHREAD_MUTEX_INITIALIZER;
337 + static pthread_cond_t idle_cond = PTHREAD_COND_INITIALIZER;
338 + #elif defined(HAVE_SEM_INIT)
339 + #define IDLE_USES_SEMAPHORE 1
340 + #include <semaphore.h>
341 + #ifdef HAVE_SPINLOCKS
342 + static spinlock_t idle_lock = SPIN_LOCK_UNLOCKED;
343 + #define LOCK_IDLE spin_lock(&idle_lock)
344 + #define UNLOCK_IDLE spin_unlock(&idle_lock)
345 + #else
346 + static pthread_mutex_t idle_lock = PTHREAD_MUTEX_INITIALIZER;
347 + #define LOCK_IDLE pthread_mutex_lock(&idle_lock)
348 + #define UNLOCK_IDLE pthread_mutex_unlock(&idle_lock)
349 + #endif
350 + static sem_t idle_sem;
351 + static int idle_sem_ok = -1;
352 + #endif
353 + #endif
354 +
355 + void idle_wait(void)
356 + {
357 + #ifdef IDLE_USES_COND_WAIT
358 +        pthread_mutex_lock(&idle_lock);
359 +        pthread_cond_wait(&idle_cond, &idle_lock);
360 +        pthread_mutex_unlock(&idle_lock);
361 + #else
362 + #ifdef IDLE_USES_SEMAPHORE
363 +        LOCK_IDLE;
364 +        if (idle_sem_ok < 0)
365 +                idle_sem_ok = (sem_init(&idle_sem, 0, 0) == 0);
366 +        if (idle_sem_ok > 0) {
367 +                idle_sem_ok++;
368 +                UNLOCK_IDLE;
369 +                sem_wait(&idle_sem);
370 +                return;
371 +        }
372 +        UNLOCK_IDLE;
373 + #endif
374 +
375 +        // Fallback: sleep 10 ms
376 +        Delay_usec(10000);
377 + #endif
378 + }
379 +
380 +
381 + /*
382 + *  Resume execution of emulator thread, events just arrived
383 + */
384 +
385 + void idle_resume(void)
386 + {
387 + #ifdef IDLE_USES_COND_WAIT
388 +        pthread_cond_signal(&idle_cond);
389 + #else
390 + #ifdef IDLE_USES_SEMAPHORE
391 +        LOCK_IDLE;
392 +        if (idle_sem_ok > 1) {
393 +                idle_sem_ok--;
394 +                UNLOCK_IDLE;
395 +                sem_post(&idle_sem);
396 +                return;
397 +        }
398 +        UNLOCK_IDLE;
399 + #endif
400 + #endif
401 + }

Diff Legend

Removed lines
+ Added lines
< Changed lines
> Changed lines