The official µGFX library repository.

gos_osx.c 4.6KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191
  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. // We need to include stdio.h below. Turn off GFILE_NEED_STDIO just for this file to prevent conflicts
  8. #define GFILE_NEED_STDIO_MUST_BE_OFF
  9. #include "../../gfx.h"
  10. #if GFX_USE_OS_OSX
  11. #include <stdio.h>
  12. #include <stdlib.h>
  13. #include <unistd.h>
  14. #include <errno.h>
  15. #include <time.h>
  16. #include <sys/time.h>
  17. #include <sched.h>
  18. #include <mach/clock.h>
  19. #include <mach/mach.h>
  20. static gfxMutex SystemMutex;
  21. void _gosInit(void)
  22. {
  23. /* No initialization of the operating system itself is needed */
  24. gfxMutexInit(&SystemMutex);
  25. }
  26. void _gosDeinit(void)
  27. {
  28. /* ToDo */
  29. }
  30. void gfxSystemLock(void) {
  31. gfxMutexEnter(&SystemMutex);
  32. }
  33. void gfxSystemUnlock(void) {
  34. gfxMutexExit(&SystemMutex);
  35. }
  36. void gfxHalt(const char *msg) {
  37. if (msg)
  38. fprintf(stderr, "%s\n", msg);
  39. exit(1);
  40. }
  41. void gfxSleepMilliseconds(delaytime_t ms) {
  42. struct timespec ts;
  43. switch(ms) {
  44. case TIME_IMMEDIATE: gfxYield(); return;
  45. case TIME_INFINITE: while(1) sleep(60); return;
  46. default:
  47. ts.tv_sec = ms / 1000;
  48. ts.tv_nsec = (ms % 1000) * 1000000;
  49. nanosleep(&ts, 0);
  50. return;
  51. }
  52. }
  53. void gfxSleepMicroseconds(delaytime_t us) {
  54. struct timespec ts;
  55. switch(us) {
  56. case TIME_IMMEDIATE: gfxYield(); return;
  57. case TIME_INFINITE: while(1) sleep(60); return;
  58. default:
  59. ts.tv_sec = us / 1000000;
  60. ts.tv_nsec = (us % 1000000) * 1000;
  61. nanosleep(&ts, 0);
  62. return;
  63. }
  64. }
  65. systemticks_t gfxSystemTicks(void) {
  66. mach_timespec_t ts;
  67. clock_serv_t cclock;
  68. host_get_clock_service(mach_host_self(), SYSTEM_CLOCK, &cclock);
  69. clock_get_time(cclock, &ts);
  70. mach_port_deallocate(mach_task_self(), cclock);
  71. return ts.tv_sec * 1000UL + ts.tv_nsec / 1000000;
  72. }
  73. gfxThreadHandle gfxThreadCreate(void *stackarea, size_t stacksz, threadpriority_t prio, DECLARE_THREAD_FUNCTION((*fn),p), void *param) {
  74. gfxThreadHandle th;
  75. (void) stackarea;
  76. (void) stacksz;
  77. (void) prio;
  78. // Implementing priority with pthreads is a rats nest that is also pthreads implementation dependent.
  79. // Only some pthreads schedulers support it, some implementations use the operating system process priority mechanisms.
  80. // Even those that do support it can have different ranges of priority and "normal" priority is an undefined concept.
  81. // Across different UNIX style operating systems things can be very different (let alone OS's such as Windows).
  82. // Even just Linux changes the way priority works with different kernel schedulers and across kernel versions.
  83. // For these reasons we ignore the priority.
  84. if (pthread_create(&th, 0, fn, param))
  85. return 0;
  86. return th;
  87. }
  88. threadreturn_t gfxThreadWait(gfxThreadHandle thread) {
  89. threadreturn_t retval;
  90. if (pthread_join(thread, &retval))
  91. return 0;
  92. return retval;
  93. }
  94. void gfxSemInit(gfxSem *pSem, semcount_t val, semcount_t limit) {
  95. pthread_mutex_init(&pSem->mtx, 0);
  96. pthread_cond_init(&pSem->cond, 0);
  97. pthread_mutex_lock(&pSem->mtx);
  98. pSem->cnt = val;
  99. pSem->max = limit;
  100. pthread_mutex_unlock(&pSem->mtx);
  101. }
  102. void gfxSemDestroy(gfxSem *pSem) {
  103. pthread_mutex_destroy(&pSem->mtx);
  104. pthread_cond_destroy(&pSem->cond);
  105. }
  106. bool_t gfxSemWait(gfxSem *pSem, delaytime_t ms) {
  107. pthread_mutex_lock(&pSem->mtx);
  108. switch (ms) {
  109. case TIME_INFINITE:
  110. while (!pSem->cnt)
  111. pthread_cond_wait(&pSem->cond, &pSem->mtx);
  112. break;
  113. case TIME_IMMEDIATE:
  114. if (!pSem->cnt) {
  115. pthread_mutex_unlock(&pSem->mtx);
  116. return FALSE;
  117. }
  118. break;
  119. default:
  120. {
  121. struct timeval now;
  122. struct timespec tm;
  123. gettimeofday(&now, 0);
  124. tm.tv_sec = now.tv_sec + ms / 1000;
  125. tm.tv_nsec = now.tv_usec * 1000 + (ms % 1000) * 1000000;
  126. while (!pSem->cnt) {
  127. // We used to test the return value for ETIMEDOUT. This doesn't
  128. // work in some current pthread libraries which return -1 instead
  129. // and set errno to ETIMEDOUT. So, we will return FALSE on any error
  130. // including a ETIMEDOUT.
  131. if (pthread_cond_timedwait(&pSem->cond, &pSem->mtx, &tm)) {
  132. pthread_mutex_unlock(&pSem->mtx);
  133. return FALSE;
  134. }
  135. }
  136. }
  137. break;
  138. }
  139. pSem->cnt--;
  140. pthread_mutex_unlock(&pSem->mtx);
  141. return TRUE;
  142. }
  143. void gfxSemSignal(gfxSem *pSem) {
  144. pthread_mutex_lock(&pSem->mtx);
  145. if (pSem->cnt < pSem->max) {
  146. pSem->cnt++;
  147. pthread_cond_signal(&pSem->cond);
  148. }
  149. pthread_mutex_unlock(&pSem->mtx);
  150. }
  151. semcount_t gfxSemCounter(gfxSem *pSem) {
  152. semcount_t res;
  153. // The locking is really only required if obtaining the count is a divisible operation
  154. // which it might be on a 8/16 bit processor with a 32 bit semaphore count.
  155. pthread_mutex_lock(&pSem->mtx);
  156. res = pSem->cnt;
  157. pthread_mutex_unlock(&pSem->mtx);
  158. return res;
  159. }
  160. #endif /* GFX_USE_OS_OSX */