aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--include/gos/posix.h77
-rw-r--r--src/gos/posix.c151
2 files changed, 227 insertions, 1 deletions
diff --git a/include/gos/posix.h b/include/gos/posix.h
index f81fb26b..732a7de3 100644
--- a/include/gos/posix.h
+++ b/include/gos/posix.h
@@ -14,6 +14,83 @@
#define _GOS_POSIX_H
#if GFX_USE_OS_POSIX
+
+#include <sys/types.h>
+#include <stdint.h>
+#include <pthread.h>
+
+/* Already defined int8_t, uint8_t, int16_t, uint16_t, int32_t, uint32_t, size_t */
+
+typedef int8_t bool_t;
+typedef unsigned long systemticks_t;
+typedef void * threadreturn_t;
+typedef unsigned long delaytime_t;
+typedef pthread_t gfxThreadHandle;
+typedef int threadpriority_t;
+typedef uint32_t semcount_t;
+typedef pthread_mutex_t gfxMutex;
+
+#define DECLARE_THREAD_FUNCTION(fnName, param) threadreturn_t fnName(void *param)
+#define DECLARE_THREAD_STACK(name, sz) uint8_t name[0];
+
+#define gfxExit() exit(0)
+#define gfxAlloc(sz) malloc(sz)
+#define gfxRealloc(p,osz,nsz) realloc(p, nsz)
+#define gfxFree(ptr) free(ptr)
+#define gfxMillisecondsToTicks(ms) (ms)
+#define gfxYield() pthread_yield()
+#define gfxThreadMe() pthread_self()
+#define gfxThreadClose(th) {}
+#define gfxMutexInit(pmtx) pthread_mutex_init(pmtx, 0)
+#define gfxMutexDestroy(pmtx) pthread_mutex_destroy(pmtx)
+#define gfxMutexEnter(pmtx) pthread_mutex_lock(pmtx)
+#define gfxMutexExit(pmtx) pthread_mutex_unlock(pmtx)
+#define gfxSemSignalI(psem) gfxSemSignal(psem)
+#define gfxSemCounterI(pSem) ((pSem)->cnt)
+
+
+#define FALSE 0
+#define TRUE 1
+#define TIME_IMMEDIATE 0
+#define TIME_INFINITE ((delaytime_t)-1)
+#define MAX_SEMAPHORE_COUNT ((semcount_t)-1)
+#define LOW_PRIORITY 10
+#define NORMAL_PRIORITY 0
+#define HIGH_PRIORITY -10
+
+typedef struct gfxSem {
+ pthread_mutex_t mtx;
+ pthread_cond_t cond;
+ semcount_t cnt;
+ semcount_t max;
+ } gfxSem;
+
+/*===========================================================================*/
+/* Function declarations. */
+/*===========================================================================*/
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+void gfxHalt(const char *msg);
+void gfxSleepMilliseconds(delaytime_t ms);
+void gfxSleepMicroseconds(delaytime_t ms);
+systemticks_t gfxSystemTicks(void);
+void gfxSystemLock(void);
+void gfxSystemUnlock(void);
+void gfxSemInit(gfxSem *psem, semcount_t val, semcount_t limit);
+void gfxSemDestroy(gfxSem *psem);
+bool_t gfxSemWait(gfxSem *psem, delaytime_t ms);
+void gfxSemSignal(gfxSem *psem);
+semcount_t gfxSemCounter(gfxSem *pSem);
+gfxThreadHandle gfxThreadCreate(void *stackarea, size_t stacksz, threadpriority_t prio, DECLARE_THREAD_FUNCTION((*fn),p), void *param);
+threadreturn_t gfxThreadWait(gfxThreadHandle thread);
+
+#ifdef __cplusplus
+}
+#endif
+
#endif /* GFX_USE_OS_POSIX */
#endif /* _GOS_POSIX_H */
diff --git a/src/gos/posix.c b/src/gos/posix.c
index 19a02560..f48a4caa 100644
--- a/src/gos/posix.c
+++ b/src/gos/posix.c
@@ -13,7 +13,156 @@
#if GFX_USE_OS_POSIX
-#error "GOS: POSIX not supported yet"
+#include <stdio.h>
+#include <unistd.h>
+#include <time.h>
+
+static gfxMutex SystemMutex;
+
+void _gosInit(void) {
+ gfxMutexInit(&SystemMutex);
+}
+
+void gfxSystemLock(void) {
+ gfxMutexEnter(&SystemMutex);
+}
+
+void gfxSystemUnlock(void) {
+ gfxMutexLeave(&SystemMutex);
+}
+
+void gfxHalt(const char *msg) {
+ if (msg)
+ fprintf(stderr, "%s\n", msg);
+ exit(1);
+}
+
+void gfxSleepMilliseconds(delaytime_t ms) {
+ struct timespec ts;
+
+ switch(ms) {
+ case TIME_IMMEDIATE: pthread_yield(); return;
+ case TIME_INFINITE: while(1) sleep(60); return;
+ default:
+ ts.tv_sec = ms / 1000;
+ ts.tv_nsec = (ms % 1000) * 1000;
+ nanosleep(&ts, 0);
+ return;
+ }
+}
+
+void gfxSleepMicroseconds(delaytime_t ms) {
+ struct timespec ts;
+
+ switch(ms) {
+ case TIME_IMMEDIATE: pthread_yield(); return;
+ case TIME_INFINITE: while(1) sleep(60); return;
+ default:
+ ts.tv_sec = ms / 1000000;
+ ts.tv_nsec = ms % 1000000;
+ nanosleep(&ts, 0);
+ return;
+ }
+}
+
+systemticks_t gfxSystemTicks(void) {
+ struct timespec ts;
+
+ clock_gettime(CLOCK_MONOTONIC, &ts);
+ return ts.tv_sec * 1000UL + ts.tv_nsec / 1000UL;
+}
+
+gfxThreadHandle gfxThreadCreate(void *stackarea, size_t stacksz, threadpriority_t prio, DECLARE_THREAD_FUNCTION((*fn),p), void *param) {
+ gfxThreadHandle th;
+
+ // Implementing priority with pthreads is a rats nest that is also pthreads implementation dependent.
+ // Only some pthreads schedulers support it, some implementations use the operating system process priority mechanisms.
+ // Even those that do support it can have different ranges of priority and "normal" priority is an undefined concept.
+ // Across different UNIX style operating systems things can be very different (let alone OS's such as Windows).
+ // Even just Linux changes the way priority works with different kernel schedulers and across kernel versions.
+ // For these reasons we ignore the priority.
+
+ if (pthread_create(&th, 0, fn, param))
+ return 0;
+ return th;
+}
+
+threadreturn_t gfxThreadWait(gfxThreadHandle thread) {
+ threadreturn_t retval;
+
+ if (pthread_join(thread, &retval))
+ return 0;
+ return retval;
+}
+
+void gfxSemInit(gfxSem *psem, semcount_t val, semcount_t limit) {
+ pthread_mutex_init(&psem->mtx, 0);
+ pthread_cond_init(&psem->cond, 0);
+ pthread_mutex_lock(&psem->mtx);
+ psem->cnt = val;
+ psem->max = limit;
+ pthread_mutex_unlock(&psem->mtx);
+}
+
+void gfxSemDestroy(gfxSem *psem) {
+ pthread_mutex_destroy(&psem->mtx);
+ pthread_cond_destroy(&psem->cond);
+}
+
+bool_t gfxSemWait(gfxSem *psem, delaytime_t ms) {
+ pthread_mutex_lock(&psem->mtx);
+ switch (ms) {
+ case TIME_INFINITE:
+ while (!psem->val)
+ pthread_cond_wait(&psem->cond, &psem->mtx);
+ break;
+ case TIME_IMMEDIATE:
+ if (!psem->val) {
+ pthread_mutex_unlock(&psem->mtx);
+ return FALSE;
+ }
+ break;
+ default:
+ {
+ struct timeval now;
+ struct timespec tm;
+
+ gettimeofday(&now);
+ tm.tv_sec = now.tv_sec + ms / 1000;
+ tm.tv_nsec = (now.tv_usec + ms % 1000) * 1000;
+ while (!psem->val) {
+ if (pthread_cond_timedwait(&psem->cond, &psem->mtx, &tm) == ETIMEDOUT) {
+ pthread_mutex_unlock(&psem->mtx);
+ return FALSE;
+ }
+ }
+ }
+ break;
+ }
+ psem->val--;
+ pthread_mutex_unlock(&psem->mtx);
+ return TRUE;
+}
+
+void gfxSemSignal(gfxSem *psem) {
+ pthread_mutex_lock(&psem->mtx);
+ if (psem->val < psem->limit) {
+ psem->val++;
+ pthread_cond_signal(&psem->cond);
+ }
+ pthread_mutex_unlock(&psem->mtx);
+}
+
+semcount_t gfxSemCounter(gfxSem *pSem) {
+ semcount_t res;
+
+ // The locking is really only required if obtaining the count is a divisible operation
+ // which it might be on a 8/16 bit processor with a 32 bit semaphore count.
+ pthread_mutex_lock(&psem->mtx);
+ res = psem->cnt;
+ pthread_mutex_unlock(&psem->mtx);
+ return res;
+}
#endif /* GFX_USE_OS_POSIX */
/** @} */