µGFX  2.9
version 2.9
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.io/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 gMutex 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(gDelay ms) {
57  struct timespec ts;
58 
59  switch(ms) {
60  case gDelayNone: gfxYield(); return;
61  case gDelayForever: 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(gDelay us) {
71  struct timespec ts;
72 
73  switch(us) {
74  case gDelayNone: gfxYield(); return;
75  case gDelayForever: 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 gTicks 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 gThread gfxThreadCreate(void *stackarea, gMemSize stacksz, gThreadpriority prio, GFX_THREAD_FUNCTION((*fn),p), void *param) {
96  gThread 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 gThreadreturn gfxThreadWait(gThread thread) {
114  gThreadreturn retval;
115 
116  if (pthread_join(thread, &retval))
117  return 0;
118  return retval;
119 }
120 
121 void gfxSemInit(gSem *pSem, gSemcount val, gSemcount 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(gSem *pSem) {
131  pthread_mutex_destroy(&pSem->mtx);
132  pthread_cond_destroy(&pSem->cond);
133 }
134 
135 gBool gfxSemWait(gSem *pSem, gDelay ms) {
136  pthread_mutex_lock(&pSem->mtx);
137  switch (ms) {
138  case gDelayForever:
139  while (!pSem->cnt)
140  pthread_cond_wait(&pSem->cond, &pSem->mtx);
141  break;
142  case gDelayNone:
143  if (!pSem->cnt) {
144  pthread_mutex_unlock(&pSem->mtx);
145  return gFalse;
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 gFalse 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 gFalse;
164  }
165  }
166  }
167  break;
168  }
169  pSem->cnt--;
170  pthread_mutex_unlock(&pSem->mtx);
171  return gTrue;
172 }
173 
174 void gfxSemSignal(gSem *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 */
gThreadreturn gfxThreadWait(gThread thread)
Wait for a thread to finish.
void gfxSemSignal(gSem *psem)
Signal a semaphore.
void * gThread
A thread handle.
Definition: gos.h:116
gTicks gfxSystemTicks(void)
Get the current operating system tick time.
void gfxYield(void)
Yield the current thread.
#define GFX_THREAD_FUNCTION(fnName, param)
Declare a thread function.
Definition: gos.h:73
void gfxMutexExit(gMutex *pmutex)
Exit the critical code region protected by the mutex.
gBool gfxSemWait(gSem *psem, gDelay ms)
Wait on a semaphore.
void gfxSystemUnlock(void)
Unlock the operating system previous locked by gfxSystemLock()
void gfxSleepMicroseconds(gDelay us)
Put the current thread to sleep for the specified period in microseconds.
void gfxMutexEnter(gMutex *pmutex)
Enter the critical code region protected by the mutex.
void gfxSystemLock(void)
Lock the operating system to protect a sequence of code.
void gfxMutexInit(gMutex *pmutex)
Initialise a mutex to protect a region of code from other threads.
gThread gfxThreadCreate(void *stackarea, gMemSize stacksz, gThreadpriority prio, GFX_THREAD_FUNCTION((*fn), p), void *param)
Start a new thread.
void gfxHalt(const char *msg)
Halt the GFX application due to an error.
void gfxSemDestroy(gSem *psem)
Destroy a Counted Semaphore.
void gfxSemInit(gSem *psem, gSemcount val, gSemcount limit)
Initialise a Counted Semaphore.
void gfxSleepMilliseconds(gDelay ms)
Put the current thread to sleep for the specified period in milliseconds.
A mutex.
Definition: gos.h:110
A semaphore.
Definition: gos.h:104