version 2.8
gos_osx.c
1 /*
2  * This file is subject to the terms of the GFX License. If a copy of
3  * the license was not distributed with this file, you can obtain one at:
4  *
5  * http://ugfx.org/license.html
6  */
7 
8 // We need to include stdio.h below. Turn off GFILE_NEED_STDIO just for this file to prevent conflicts
9 #define GFILE_NEED_STDIO_MUST_BE_OFF
10 
11 #include "../../gfx.h"
12 
13 #if GFX_USE_OS_OSX
14 
15 #include <stdio.h>
16 #include <stdlib.h>
17 #include <unistd.h>
18 #include <errno.h>
19 #include <time.h>
20 #include <sys/time.h>
21 #include <sched.h>
22 #include <mach/clock.h>
23 #include <mach/mach.h>
24 
25 static gfxMutex SystemMutex;
26 
27 void _gosInit(void)
28 {
29  /* No initialization of the operating system itself is needed */
30  gfxMutexInit(&SystemMutex);
31 }
32 
33 void _gosPostInit(void)
34 {
35 }
36 
37 void _gosDeinit(void)
38 {
39  /* ToDo */
40 }
41 
42 void gfxSystemLock(void) {
43  gfxMutexEnter(&SystemMutex);
44 }
45 
46 void gfxSystemUnlock(void) {
47  gfxMutexExit(&SystemMutex);
48 }
49 
50 void gfxHalt(const char *msg) {
51  if (msg)
52  fprintf(stderr, "%s\n", msg);
53  exit(1);
54 }
55 
56 void gfxSleepMilliseconds(delaytime_t ms) {
57  struct timespec ts;
58 
59  switch(ms) {
60  case TIME_IMMEDIATE: gfxYield(); return;
61  case TIME_INFINITE: while(1) sleep(60); return;
62  default:
63  ts.tv_sec = ms / 1000;
64  ts.tv_nsec = (ms % 1000) * 1000000;
65  nanosleep(&ts, 0);
66  return;
67  }
68 }
69 
70 void gfxSleepMicroseconds(delaytime_t us) {
71  struct timespec ts;
72 
73  switch(us) {
74  case TIME_IMMEDIATE: gfxYield(); return;
75  case TIME_INFINITE: while(1) sleep(60); return;
76  default:
77  ts.tv_sec = us / 1000000;
78  ts.tv_nsec = (us % 1000000) * 1000;
79  nanosleep(&ts, 0);
80  return;
81  }
82 }
83 
84 systemticks_t gfxSystemTicks(void) {
85  mach_timespec_t ts;
86  clock_serv_t cclock;
87 
88  host_get_clock_service(mach_host_self(), SYSTEM_CLOCK, &cclock);
89  clock_get_time(cclock, &ts);
90  mach_port_deallocate(mach_task_self(), cclock);
91 
92  return ts.tv_sec * 1000UL + ts.tv_nsec / 1000000;
93 }
94 
95 gfxThreadHandle gfxThreadCreate(void *stackarea, size_t stacksz, threadpriority_t prio, DECLARE_THREAD_FUNCTION((*fn),p), void *param) {
96  gfxThreadHandle th;
97  (void) stackarea;
98  (void) stacksz;
99  (void) prio;
100 
101  // Implementing priority with pthreads is a rats nest that is also pthreads implementation dependent.
102  // Only some pthreads schedulers support it, some implementations use the operating system process priority mechanisms.
103  // Even those that do support it can have different ranges of priority and "normal" priority is an undefined concept.
104  // Across different UNIX style operating systems things can be very different (let alone OS's such as Windows).
105  // Even just Linux changes the way priority works with different kernel schedulers and across kernel versions.
106  // For these reasons we ignore the priority.
107 
108  if (pthread_create(&th, 0, fn, param))
109  return 0;
110  return th;
111 }
112 
113 threadreturn_t gfxThreadWait(gfxThreadHandle thread) {
114  threadreturn_t retval;
115 
116  if (pthread_join(thread, &retval))
117  return 0;
118  return retval;
119 }
120 
121 void gfxSemInit(gfxSem *pSem, semcount_t val, semcount_t limit) {
122  pthread_mutex_init(&pSem->mtx, 0);
123  pthread_cond_init(&pSem->cond, 0);
124  pthread_mutex_lock(&pSem->mtx);
125  pSem->cnt = val;
126  pSem->max = limit;
127  pthread_mutex_unlock(&pSem->mtx);
128 }
129 
130 void gfxSemDestroy(gfxSem *pSem) {
131  pthread_mutex_destroy(&pSem->mtx);
132  pthread_cond_destroy(&pSem->cond);
133 }
134 
135 bool_t gfxSemWait(gfxSem *pSem, delaytime_t ms) {
136  pthread_mutex_lock(&pSem->mtx);
137  switch (ms) {
138  case TIME_INFINITE:
139  while (!pSem->cnt)
140  pthread_cond_wait(&pSem->cond, &pSem->mtx);
141  break;
142  case TIME_IMMEDIATE:
143  if (!pSem->cnt) {
144  pthread_mutex_unlock(&pSem->mtx);
145  return FALSE;
146  }
147  break;
148  default:
149  {
150  struct timeval now;
151  struct timespec tm;
152 
153  gettimeofday(&now, 0);
154  tm.tv_sec = now.tv_sec + ms / 1000;
155  tm.tv_nsec = now.tv_usec * 1000 + (ms % 1000) * 1000000;
156  while (!pSem->cnt) {
157  // We used to test the return value for ETIMEDOUT. This doesn't
158  // work in some current pthread libraries which return -1 instead
159  // and set errno to ETIMEDOUT. So, we will return FALSE on any error
160  // including a ETIMEDOUT.
161  if (pthread_cond_timedwait(&pSem->cond, &pSem->mtx, &tm)) {
162  pthread_mutex_unlock(&pSem->mtx);
163  return FALSE;
164  }
165  }
166  }
167  break;
168  }
169  pSem->cnt--;
170  pthread_mutex_unlock(&pSem->mtx);
171  return TRUE;
172 }
173 
174 void gfxSemSignal(gfxSem *pSem) {
175  pthread_mutex_lock(&pSem->mtx);
176  if (pSem->cnt < pSem->max) {
177  pSem->cnt++;
178  pthread_cond_signal(&pSem->cond);
179  }
180  pthread_mutex_unlock(&pSem->mtx);
181 }
182 
183 #endif /* GFX_USE_OS_OSX */
void * gfxThreadHandle
A thread handle.
Definition: gos.h:117
void gfxSemInit(gfxSem *psem, semcount_t val, semcount_t limit)
Initialise a Counted Semaphore.
systemticks_t gfxSystemTicks(void)
Get the current operating system tick time.
#define FALSE
Generic &#39;false&#39; boolean constant.
Definition: gfx.h:31
void gfxSemDestroy(gfxSem *psem)
Destroy a Counted Semaphore.
bool_t gfxSemWait(gfxSem *psem, delaytime_t ms)
Wait on a semaphore.
A semaphore.
Definition: gos.h:105
void gfxMutexExit(gfxMutex *pmutex)
Exit the critical code region protected by the mutex.
void gfxSystemLock(void)
Lock the operating system to protect a sequence of code.
#define DECLARE_THREAD_FUNCTION(fnName, param)
Declare a thread function.
Definition: gos.h:62
void gfxHalt(const char *msg)
Halt the GFX application due to an error.
void gfxMutexEnter(gfxMutex *pmutex)
Enter the critical code region protected by the mutex.
void gfxSemSignal(gfxSem *psem)
Signal a semaphore.
void gfxSleepMicroseconds(delaytime_t us)
Put the current thread to sleep for the specified period in microseconds.
gfxThreadHandle gfxThreadCreate(void *stackarea, size_t stacksz, threadpriority_t prio, DECLARE_THREAD_FUNCTION((*fn), p), void *param)
Start a new thread.
A mutex.
Definition: gos.h:111
threadreturn_t gfxThreadWait(gfxThreadHandle thread)
Wait for a thread to finish.
void gfxMutexInit(gfxMutex *pmutex)
Initialise a mutex to protect a region of code from other threads.
void gfxYield(void)
Yield the current thread.
#define TRUE
Generic &#39;true&#39; boolean constant.
Definition: gfx.h:38
void gfxSleepMilliseconds(delaytime_t ms)
Put the current thread to sleep for the specified period in milliseconds.
void gfxSystemUnlock(void)
Unlock the operating system previous locked by gfxSystemLock()