aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorinmarket <andrewh@inmarket.com.au>2015-07-16 19:02:59 +1000
committerinmarket <andrewh@inmarket.com.au>2015-07-16 19:02:59 +1000
commitc1d239bbdaef9ae08948ad2b61510ac1cd240947 (patch)
treee7fbe4bc48b618f1f54227ae9dc46d6172a384b1
parentb3028a78d15a325eee1ec9563047637908cab8f5 (diff)
downloaduGFX-c1d239bbdaef9ae08948ad2b61510ac1cd240947.tar.gz
uGFX-c1d239bbdaef9ae08948ad2b61510ac1cd240947.tar.bz2
uGFX-c1d239bbdaef9ae08948ad2b61510ac1cd240947.zip
Significant improvements in alternative scheduler.
Isolate the generic thread and heap code Tidyup's. Generic threading now working for x86, cortex-m0->m7.
-rw-r--r--boards/base/STM32F746-Discovery/board.mk2
-rw-r--r--boards/base/STM32F746-Discovery/example_raw32/Makefile2
-rw-r--r--boards/base/STM32F746-Discovery/stm32f746g_raw32_ugfx.c1
-rw-r--r--boards/base/Win32/board.mk4
-rw-r--r--gfxconf.example.h4
-rw-r--r--src/gos/gos.mk4
-rw-r--r--src/gos/gos_arduino.c492
-rw-r--r--src/gos/gos_arduino.h64
-rw-r--r--src/gos/gos_chibios.c2
-rw-r--r--src/gos/gos_ecos.c3
-rw-r--r--src/gos/gos_freertos.c3
-rw-r--r--src/gos/gos_mk.c2
-rw-r--r--src/gos/gos_options.h42
-rw-r--r--src/gos/gos_raw32.c789
-rw-r--r--src/gos/gos_raw32.h96
-rw-r--r--src/gos/gos_rawrtos.c3
-rw-r--r--src/gos/gos_x_heap.c195
-rw-r--r--src/gos/gos_x_heap.h62
-rw-r--r--src/gos/gos_x_threads.c672
-rw-r--r--src/gos/gos_x_threads.h103
20 files changed, 1130 insertions, 1415 deletions
diff --git a/boards/base/STM32F746-Discovery/board.mk b/boards/base/STM32F746-Discovery/board.mk
index dd1f8441..35e62757 100644
--- a/boards/base/STM32F746-Discovery/board.mk
+++ b/boards/base/STM32F746-Discovery/board.mk
@@ -19,7 +19,7 @@ ifeq ($(OPT_OS),raw32)
$(GFXLIB)/boards/base/STM32F746-Discovery/stm32f746g_raw32_ugfx.c \
$(GFXLIB)/boards/base/STM32F746-Discovery/stm32f746g_raw32_system.c \
$(GFXLIB)/boards/base/STM32F746-Discovery/stm32f746g_raw32_interrupts.c
- GFXDEFS += GFX_OS_EXTRA_INIT_FUNCTION=Raw32OSInit
+ GFXDEFS += GFX_OS_EXTRA_INIT_FUNCTION=Raw32OSInit GFX_OS_INIT_NO_WARNING=TRUE
SRCFLAGS+= -std=c99
GFXINC += $(CMSIS)/Device/ST/STM32F7xx/Include \
$(CMSIS)/Include \
diff --git a/boards/base/STM32F746-Discovery/example_raw32/Makefile b/boards/base/STM32F746-Discovery/example_raw32/Makefile
index 298d74bf..dee0f01a 100644
--- a/boards/base/STM32F746-Discovery/example_raw32/Makefile
+++ b/boards/base/STM32F746-Discovery/example_raw32/Makefile
@@ -55,7 +55,7 @@ LDFLAGS =
SRC =
OBJS =
-DEFS = GOS_RAW_HEAP_SIZE=40960
+DEFS = GFX_OS_HEAP_SIZE=40960
LIBS =
INCPATH =
diff --git a/boards/base/STM32F746-Discovery/stm32f746g_raw32_ugfx.c b/boards/base/STM32F746-Discovery/stm32f746g_raw32_ugfx.c
index 3d493e5c..5fde982e 100644
--- a/boards/base/STM32F746-Discovery/stm32f746g_raw32_ugfx.c
+++ b/boards/base/STM32F746-Discovery/stm32f746g_raw32_ugfx.c
@@ -13,7 +13,6 @@ systemticks_t gfxMillisecondsToTicks(delaytime_t ms)
static void SystemClock_Config(void);
static void CPU_CACHE_Enable(void);
-static void LCD_Config(void);
void Raw32OSInit(void) {
RCC_PeriphCLKInitTypeDef PeriphClkInitStruct;
diff --git a/boards/base/Win32/board.mk b/boards/base/Win32/board.mk
index adcbaeaf..b4577927 100644
--- a/boards/base/Win32/board.mk
+++ b/boards/base/Win32/board.mk
@@ -3,3 +3,7 @@ GFXSRC +=
GFXLIBS +=
include $(GFXLIB)/drivers/multiple/Win32/driver.mk
include $(GFXLIB)/drivers/gaudio/Win32/driver.mk
+
+ifeq ($(OPT_OS),win32.raw32)
+ GFXDEFS += GFX_OS_INIT_NO_WARNING=TRUE
+endif
diff --git a/gfxconf.example.h b/gfxconf.example.h
index 52c129ef..d46bbae2 100644
--- a/gfxconf.example.h
+++ b/gfxconf.example.h
@@ -35,13 +35,15 @@
//#define GFX_USE_OS_ECOS FALSE
//#define GFX_USE_OS_RAWRTOS FALSE
//#define GFX_USE_OS_RAW32 FALSE
-// #define GOS_RAW_HEAP_SIZE 0
// #define INTERRUPTS_OFF() optional_code
// #define INTERRUPTS_ON() optional_code
// Options that (should where relevant) apply to all operating systems
// #define GFX_COMPILER GFX_COMPILER_UNKNOWN
+// #define GFX_CPU GFX_CPU_UNKNOWN
+// #define GFX_OS_HEAP_SIZE 0
// #define GFX_NO_OS_INIT FALSE
+// #define GFX_OS_INIT_NO_WARNING FALSE
// #define GFX_OS_EXTRA_INIT_FUNCTION myOSInitRoutine
// #define GFX_OS_EXTRA_DEINIT_FUNCTION myOSDeInitRoutine
diff --git a/src/gos/gos.mk b/src/gos/gos.mk
index 7db246d2..1c3a86a5 100644
--- a/src/gos/gos.mk
+++ b/src/gos/gos.mk
@@ -11,5 +11,7 @@ GFXSRC += $(GFXLIB)/src/gos/gos_chibios.c \
$(GFXLIB)/src/gos/gos_raw32.c \
$(GFXLIB)/src/gos/gos_ecos.c \
$(GFXLIB)/src/gos/gos_rawrtos.c \
- $(GFXLIB)/src/gos/gos_arduino.c
+ $(GFXLIB)/src/gos/gos_arduino.c \
+ $(GFXLIB)/src/gos/gos_x_threads.c \
+ $(GFXLIB)/src/gos/gos_x_heap.c
diff --git a/src/gos/gos_arduino.c b/src/gos/gos_arduino.c
index 380d528a..c565abb9 100644
--- a/src/gos/gos_arduino.c
+++ b/src/gos/gos_arduino.c
@@ -11,7 +11,8 @@
#include <string.h> // Prototype for memcpy()
-static void _gosThreadsInit(void);
+void _gosHeapInit(void);
+void _gosThreadsInit(void);
/*********************************************************
* Initialise
@@ -23,7 +24,12 @@ void _gosInit(void)
* On the other hand the C runtime should still already be initialized before
* getting here!
*/
- #warning "GOS: Arduino - Make sure you initialize your hardware and the C runtime before calling gfxInit() in your application!"
+ #if !GFX_OS_INIT_NO_WARNING
+ #warning "GOS: Arduino - Make sure you initialize your hardware and the C runtime before calling gfxInit() in your application!"
+ #endif
+
+ // Start the heap allocator
+ _gosHeapInit();
// Start the scheduler
_gosThreadsInit();
@@ -53,488 +59,16 @@ void gfxExit(void) {
dummy++;
}
-/*********************************************************
- * Head allocation functions
- *********************************************************/
-
-#include <stdlib.h> // Prototype for malloc(), realloc() and free()
-
-void *gfxAlloc(size_t sz) {
- return malloc(sz);
-}
-
-void *gfxRealloc(void *ptr, size_t oldsz, size_t newsz) {
- (void) oldsz;
- return realloc(ptr, newsz);
-}
-
-void gfxFree(void *ptr) {
- free(ptr);
-}
-
-/*********************************************************
- * Semaphores and critical region functions
- *********************************************************/
-
-#if !defined(INTERRUPTS_OFF) || !defined(INTERRUPTS_ON)
- #define INTERRUPTS_OFF()
- #define INTERRUPTS_ON()
-#endif
-
-void gfxSystemLock(void) {
- INTERRUPTS_OFF();
-}
-
-void gfxSystemUnlock(void) {
- INTERRUPTS_ON();
-}
-
-void gfxMutexInit(gfxMutex *pmutex) {
- pmutex[0] = 0;
-}
-
-void gfxMutexEnter(gfxMutex *pmutex) {
- INTERRUPTS_OFF();
- while (pmutex[0]) {
- INTERRUPTS_ON();
- gfxYield();
- INTERRUPTS_OFF();
- }
- pmutex[0] = 1;
- INTERRUPTS_ON();
-}
-
-void gfxMutexExit(gfxMutex *pmutex) {
- pmutex[0] = 0;
-}
-
-void gfxSemInit(gfxSem *psem, semcount_t val, semcount_t limit) {
- psem->cnt = val;
- psem->limit = limit;
-}
-
-bool_t gfxSemWait(gfxSem *psem, delaytime_t ms) {
- systemticks_t starttm, delay;
-
- // Convert our delay to ticks
- switch (ms) {
- case TIME_IMMEDIATE:
- delay = TIME_IMMEDIATE;
- break;
- case TIME_INFINITE:
- delay = TIME_INFINITE;
- break;
- default:
- delay = gfxMillisecondsToTicks(ms);
- if (!delay) delay = 1;
- starttm = gfxSystemTicks();
- }
-
- INTERRUPTS_OFF();
- while (psem->cnt <= 0) {
- INTERRUPTS_ON();
- // Check if we have exceeded the defined delay
- switch (delay) {
- case TIME_IMMEDIATE:
- return FALSE;
- case TIME_INFINITE:
- break;
- default:
- if (gfxSystemTicks() - starttm >= delay)
- return FALSE;
- break;
- }
- gfxYield();
- INTERRUPTS_OFF();
- }
- psem->cnt--;
- INTERRUPTS_ON();
- return TRUE;
-}
-
-bool_t gfxSemWaitI(gfxSem *psem) {
- if (psem->cnt <= 0)
- return FALSE;
- psem->cnt--;
- return TRUE;
-}
-
-void gfxSemSignal(gfxSem *psem) {
- INTERRUPTS_OFF();
- gfxSemSignalI(psem);
- INTERRUPTS_ON();
-}
-
-void gfxSemSignalI(gfxSem *psem) {
- if (psem->cnt < psem->limit)
- psem->cnt++;
-}
/*********************************************************
* Sleep functions
*********************************************************/
-void gfxSleepMilliseconds(delaytime_t ms) {
- systemticks_t starttm, delay;
-
- // Safety first
- switch (ms) {
- case TIME_IMMEDIATE:
- return;
- case TIME_INFINITE:
- while(1)
- gfxYield();
- return;
- }
-
- // Convert our delay to ticks
- delay = gfxMillisecondsToTicks(ms);
- starttm = gfxSystemTicks();
-
- do {
- gfxYield();
- } while (gfxSystemTicks() - starttm < delay);
+systemticks_t gfxSystemTicks(void) {
+ return millis();
}
-
-void gfxSleepMicroseconds(delaytime_t ms) {
- systemticks_t starttm, delay;
-
- // Safety first
- switch (ms) {
- case TIME_IMMEDIATE:
- return;
- case TIME_INFINITE:
- while(1)
- gfxYield();
- return;
- }
-
- // Convert our delay to ticks
- delay = gfxMillisecondsToTicks(ms/1000);
- starttm = gfxSystemTicks();
-
- do {
- gfxYield();
- } while (gfxSystemTicks() - starttm < delay);
-}
-
-/*********************************************************
- * Threading functions
- *********************************************************/
-
-/**
- * There are some compilers we know how they store the jmpbuf. For those
- * we can use the constant macro definitions. For others we have to "auto-detect".
- * Auto-detection is hairy and there is no guarantee it will work on all architectures.
- * For those it doesn't - read the compiler manuals and the library source code to
- * work out the correct macro values.
- * You can use the debugger to work out the values for your compiler and put them here.
- * Defining these macros as constant values makes the system behavior guaranteed but also
- * makes your code compiler and cpu architecture dependent. It also saves a heap of code
- * and a few bytes of RAM.
- */
-#if GFX_COMPILER == GFX_COMPILER_MINGW32
- #define AUTO_DETECT_MASK FALSE
- #define STACK_DIR_UP FALSE
- #define MASK1 0x00000011
- #define MASK2 0x00000000
- #define STACK_BASE 12
-#else
- // Use auto-detection of the stack frame format
- // Assumes all the relevant stuff to be relocated is in the first 256 bytes of the jmpbuf.
- #define AUTO_DETECT_MASK TRUE
- #define STACK_DIR_UP stackdirup // TRUE if the stack grow up instead of down
- #define MASK1 jmpmask1 // The 1st mask of jmp_buf elements that need relocation
- #define MASK2 jmpmask2 // The 2nd mask of jmp_buf elements that need relocation
- #define STACK_BASE stackbase // The base of the stack frame relative to the local variables
- static bool_t stackdirup;
- static uint32_t jmpmask1;
- static uint32_t jmpmask2;
- static size_t stackbase;
-#endif
-
-#include <setjmp.h> /* jmp_buf, setjmp(), longjmp() */
-
-/**
- * Some compilers define a _setjmp() and a setjmp().
- * The difference between them is that setjmp() saves the signal masks.
- * That is of no use to us so prefer to use the _setjmp() methods.
- * If they don't exist compile them to be the standard setjmp() function.
- * Similarly for longjmp().
- */
-#if (!defined(setjmp) && !defined(_setjmp)) || defined(__KEIL__) || defined(__C51__)
- #define _setjmp setjmp
-#endif
-#if (!defined(longjmp) && !defined(_longjmp)) || defined(__KEIL__) || defined(__C51__)
- #define _longjmp longjmp
-#endif
-
-typedef struct thread {
- struct thread * next; // Next thread
- int flags; // Flags
- #define FLG_THD_ALLOC 0x0001
- #define FLG_THD_MAIN 0x0002
- #define FLG_THD_DEAD 0x0004
- #define FLG_THD_WAIT 0x0008
- size_t size; // Size of the thread stack (including this structure)
- threadreturn_t (*fn)(void *param); // Thread function
- void * param; // Parameter for the thread function
- jmp_buf cxt; // The current thread context.
-} thread;
-
-typedef struct threadQ {
- thread *head;
- thread *tail;
-} threadQ;
-
-static threadQ readyQ; // The list of ready threads
-static threadQ deadQ; // Where we put threads waiting to be deallocated
-static thread * current; // The current running thread
-static thread mainthread; // The main thread context
-
-static void Qinit(threadQ * q) {
- q->head = q->tail = 0;
-}
-
-static void Qadd(threadQ * q, thread *t) {
- t->next = 0;
- if (q->head) {
- q->tail->next = t;
- q->tail = t;
- } else
- q->head = q->tail = t;
-}
-
-static thread *Qpop(threadQ * q) {
- struct thread * t;
-
- if (!q->head)
- return 0;
- t = q->head;
- q->head = t->next;
- return t;
-}
-
-#if AUTO_DETECT_MASK
- // The structure for the saved stack frame information
- typedef struct saveloc {
- char * localptr;
- jmp_buf cxt;
- } saveloc;
-
- // A pointer to our auto-detection buffer.
- static saveloc *pframeinfo;
-
- /* These functions are not static to prevent the compiler removing them as functions */
-
- void get_stack_state(void) {
- char* c;
- pframeinfo->localptr = (char *)&c;
- _setjmp(pframeinfo->cxt);
- }
-
- void get_stack_state_in_fn(void) {
- pframeinfo++;
- get_stack_state();
- pframeinfo--;
- }
-#endif
-
-static void _gosThreadsInit(void) {
- Qinit(&readyQ);
- current = &mainthread;
- current->next = 0;
- current->size = sizeof(thread);
- current->flags = FLG_THD_MAIN;
- current->fn = 0;
- current->param = 0;
-
- #if AUTO_DETECT_MASK
- {
- uint32_t i;
- char ** pout;
- char ** pin;
- size_t diff;
- char * framebase;
-
- // Allocate a buffer to store our test data
- pframeinfo = gfxAlloc(sizeof(saveloc)*2);
-
- // Get details of the stack frame from within a function
- get_stack_state_in_fn();
-
- // Get details of the stack frame outside the function
- get_stack_state();
-
- /* Work out the frame entries to relocate by treating the jump buffer as an array of pointers */
- stackdirup = pframeinfo[1].localptr > pframeinfo[0].localptr;
- pout = (char **)pframeinfo[0].cxt;
- pin = (char **)pframeinfo[1].cxt;
- diff = pframeinfo[0].localptr - pframeinfo[1].localptr;
- framebase = pframeinfo[0].localptr;
- jmpmask1 = jmpmask2 = 0;
- for (i = 0; i < sizeof(jmp_buf)/sizeof(char *); i++, pout++, pin++) {
- if ((size_t)(*pout - *pin) == diff) {
- if (i < 32)
- jmpmask1 |= 1 << i;
- else
- jmpmask2 |= 1 << (i-32);
-
- if (stackdirup) {
- if (framebase > *pout)
- framebase = *pout;
- } else {
- if (framebase < *pout)
- framebase = *pout;
- }
- }
- }
- stackbase = stackdirup ? (pframeinfo[0].localptr - framebase) : (framebase - pframeinfo[0].localptr);
-
- // Clean up
- gfxFree(pframeinfo);
- }
- #endif
-}
-
-gfxThreadHandle gfxThreadMe(void) {
- return (gfxThreadHandle)current;
-}
-
-void gfxYield(void) {
- if (!_setjmp(current->cxt)) {
- // Add us back to the Queue
- Qadd(&readyQ, current);
-
- // Check if there are dead processes to deallocate
- while ((current = Qpop(&deadQ)))
- gfxFree(current);
-
- // Run the next process
- current = Qpop(&readyQ);
- _longjmp(current->cxt, 1);
- }
-}
-
-// This routine is not currently public - but it could be.
-void gfxThreadExit(threadreturn_t ret) {
- // Save the results
- current->param = (void *)ret;
- current->flags |= FLG_THD_DEAD;
-
- // Add us to the dead list if we need deallocation as we can't free ourselves.
- // If someone is waiting on the thread they will do the cleanup.
- if ((current->flags & (FLG_THD_ALLOC|FLG_THD_WAIT)) == FLG_THD_ALLOC)
- Qadd(&deadQ, current);
-
- // Switch to the next task
- current = Qpop(&readyQ);
- if (!current)
- gfxExit(); // Oops - this should never happen!
- _longjmp(current->cxt, 1);
-}
-
-gfxThreadHandle gfxThreadCreate(void *stackarea, size_t stacksz, threadpriority_t prio, DECLARE_THREAD_FUNCTION((*fn),p), void *param) {
- thread * t;
- (void) prio;
-
- // Ensure we have a minimum stack size
- if (stacksz < sizeof(thread)+64) {
- stacksz = sizeof(thread)+64;
- stackarea = 0;
- }
-
- if (stackarea) {
- t = (thread *)stackarea;
- t->flags = 0;
- } else {
- t = (thread *)gfxAlloc(stacksz);
- if (!t)
- return 0;
- t->flags = FLG_THD_ALLOC;
- }
- t->size = stacksz;
- t->fn = fn;
- t->param = param;
- if (_setjmp(t->cxt)) {
- // This is the new thread - call the function!
- gfxThreadExit(current->fn(current->param));
-
- // We never get here
- return 0;
- }
-
- // Move the stack frame and relocate the context data
- {
- char ** s;
- char * nf;
- int diff;
- uint32_t i;
-
- // Copy the stack frame
- #if AUTO_DETECT_MASK
- if (STACK_DIR_UP) { // Stack grows up
- nf = (char *)(t) + sizeof(thread) + stackbase;
- memcpy(t+1, (char *)&t - stackbase, stackbase+sizeof(char *));
- } else { // Stack grows down
- nf = (char *)(t) + stacksz - (stackbase + sizeof(char *));
- memcpy(nf, &t, stackbase+sizeof(char *));
- }
- #elif STACK_DIR_UP
- // Stack grows up
- nf = (char *)(t) + sizeof(thread) + stackbase;
- memcpy(t+1, (char *)&t - stackbase, stackbase+sizeof(char *));
- #else
- // Stack grows down
- nf = (char *)(t) + size - (stackbase + sizeof(char *));
- memcpy(nf, &t, stackbase+sizeof(char *));
- #endif
-
- // Relocate the context data
- s = (char **)(t->cxt);
- diff = nf - (char *)&t;
-
- // Relocate the elements we know need to be relocated
- for (i = 1; i && i < MASK1; i <<= 1, s++) {
- if ((MASK1 & i))
- *s += diff;
- }
- #ifdef MASK2
- for (i = 1; i && i < MASK2; i <<= 1, s++) {
- if ((MASK1 & i))
- *s += diff;
- }
- #endif
- }
-
- // Add this thread to the ready queue
- Qadd(&readyQ, t);
- return t;
-}
-
-threadreturn_t gfxThreadWait(gfxThreadHandle th) {
- thread * t;
-
- t = th;
- if (t == current)
- return -1;
-
- // Mark that we are waiting
- t->flags |= FLG_THD_WAIT;
-
- // Wait for the thread to die
- while(!(t->flags & FLG_THD_DEAD))
- gfxYield();
-
- // Unmark
- t->flags &= ~FLG_THD_WAIT;
-
- // Clean up resources if needed
- if (t->flags & FLG_THD_ALLOC)
- gfxFree(t);
-
- // Return the status left by the dead process
- return (threadreturn_t)t->param;
+systemticks_t gfxMillisecondsToTicks(delaytime_t ms) {
+ return ms;
}
-#endif /* GFX_USE_OS_RAW32 */
+#endif /* GFX_USE_OS_ARDUINO */
diff --git a/src/gos/gos_arduino.h b/src/gos/gos_arduino.h
index fc9e7073..6a18aaec 100644
--- a/src/gos/gos_arduino.h
+++ b/src/gos/gos_arduino.h
@@ -44,70 +44,26 @@ typedef bool bool_t;
typedef uint32_t size_t;
#endif
-typedef uint32_t delaytime_t;
-typedef uint32_t systemticks_t;
-typedef short semcount_t;
-typedef int threadreturn_t;
-typedef int threadpriority_t;
-
-#define DECLARE_THREAD_FUNCTION(fnName, param) threadreturn_t fnName(void *param)
-#define DECLARE_THREAD_STACK(name, sz) uint8_t name[sz];
-
-#define TIME_IMMEDIATE 0
-#define TIME_INFINITE ((delaytime_t)-1)
-#define MAX_SEMAPHORE_COUNT 0x7FFF
-#define LOW_PRIORITY 0
-#define NORMAL_PRIORITY 1
-#define HIGH_PRIORITY 2
-
-typedef struct {
- semcount_t cnt;
- semcount_t limit;
-} gfxSem;
-
-typedef uint32_t gfxMutex;
-typedef void * gfxThreadHandle;
-
-#define gfxThreadClose(thread)
-#define gfxMutexDestroy(pmutex)
-#define gfxSemDestroy(psem)
-#define gfxSemCounter(psem) ((psem)->cnt)
-#define gfxSemCounterI(psem) ((psem)->cnt)
-
-#define gfxSystemTicks() millis()
-#define gfxMillisecondsToTicks(ms) (ms)
-
#ifdef __cplusplus
extern "C" {
#endif
void gfxHalt(const char *msg);
void gfxExit(void);
- void *gfxAlloc(size_t sz);
- void *gfxRealloc(void *ptr, size_t oldsz, size_t newsz);
- void gfxFree(void *ptr);
- void gfxYield(void);
- void gfxSleepMilliseconds(delaytime_t ms);
- void gfxSleepMicroseconds(delaytime_t ms);
- //systemticks_t gfxSystemTicks(void);
- //systemticks_t gfxMillisecondsToTicks(delaytime_t ms);
- void gfxSystemLock(void);
- void gfxSystemUnlock(void);
- void gfxMutexInit(gfxMutex *pmutex);
- void gfxMutexEnter(gfxMutex *pmutex);
- void gfxMutexExit(gfxMutex *pmutex);
- void gfxSemInit(gfxSem *psem, semcount_t val, semcount_t limit);
- bool_t gfxSemWait(gfxSem *psem, delaytime_t ms);
- bool_t gfxSemWaitI(gfxSem *psem);
- void gfxSemSignal(gfxSem *psem);
- void gfxSemSignalI(gfxSem *psem);
- gfxThreadHandle gfxThreadCreate(void *stackarea, size_t stacksz, threadpriority_t prio, DECLARE_THREAD_FUNCTION((*fn),p), void *param);
- threadreturn_t gfxThreadWait(gfxThreadHandle thread);
- gfxThreadHandle gfxThreadMe(void);
#ifdef __cplusplus
}
#endif
+/*===========================================================================*/
+/* Use the generic thread handling and heap handling */
+/*===========================================================================*/
+
+#define GOS_NEED_X_THREADS TRUE
+#define GOS_NEED_X_HEAP TRUE
+
+#include "gos_x_threads.h"
+#include "gos_x_heap.h"
+
#endif /* GFX_USE_OS_ARDUINO */
#endif /* _GOS_ARDUINO_H */
diff --git a/src/gos/gos_chibios.c b/src/gos/gos_chibios.c
index 62f5d8ee..4c79bd3d 100644
--- a/src/gos/gos_chibios.c
+++ b/src/gos/gos_chibios.c
@@ -48,7 +48,7 @@ void _gosInit(void)
chSysInit();
}
#endif
- #else
+ #elif !GFX_OS_INIT_NO_WARNING
#warning "GOS: Operating System initialization has been turned off. Make sure you call halInit() and chSysInit() before gfxInit() in your application!"
#endif
}
diff --git a/src/gos/gos_ecos.c b/src/gos/gos_ecos.c
index 16ce821b..cdad86da 100644
--- a/src/gos/gos_ecos.c
+++ b/src/gos/gos_ecos.c
@@ -13,7 +13,8 @@ void _gosInit(void)
{
#if !GFX_NO_OS_INIT
#error "GOS: Operating System initialization for eCos is not yet implemented in uGFX. Please set GFX_NO_OS_INIT to TRUE in your gfxconf.h"
- #else
+ #endif
+ #if !GFX_OS_INIT_NO_WARNING
#warning "GOS: Operating System initialization has been turned off. Make sure you call cyg_scheduler_start() before gfxInit() in your application!"
#endif
}
diff --git a/src/gos/gos_freertos.c b/src/gos/gos_freertos.c
index dbdfd22e..7b978738 100644
--- a/src/gos/gos_freertos.c
+++ b/src/gos/gos_freertos.c
@@ -26,7 +26,8 @@ void _gosInit(void)
{
#if !GFX_NO_OS_INIT
#error "GOS: Operating System initialization for FreeRTOS is not yet implemented in uGFX. Please set GFX_NO_OS_INIT to TRUE in your gfxconf.h"
- #else
+ #endif
+ #if !GFX_OS_INIT_NO_WARNING
#warning "GOS: Operating System initialization has been turned off. Make sure you call vTaskStartScheduler() before gfxInit() in your application!"
#endif
}
diff --git a/src/gos/gos_mk.c b/src/gos/gos_mk.c
index 71267233..1b033206 100644
--- a/src/gos/gos_mk.c
+++ b/src/gos/gos_mk.c
@@ -14,3 +14,5 @@
#include "gos_raw32.c"
#include "gos_rawrtos.c"
#include "gos_win32.c"
+#include "gos_x_threads.c"
+#include "gos_x_heap.c"
diff --git a/src/gos/gos_options.h b/src/gos/gos_options.h
index 8fb4f51b..600c3085 100644
--- a/src/gos/gos_options.h
+++ b/src/gos/gos_options.h
@@ -74,7 +74,7 @@
* @details Defaults to FALSE
*/
#ifndef GFX_USE_OS_ARDUINO
- #define GFX_USE_OS_ARDUINO FALSE
+ #define GFX_USE_OS_ARDUINO FALSE
#endif
/**
* @}
@@ -88,12 +88,35 @@
* @note This is setting enables optimisations that are compiler specific. It does
* not need to be specified as reasonable defaults and various auto-detection
* will happen as required.
+ * @note Currently only used by ugfx generic thread handling (GOS_USE_OS_RAW32 and GOS_USE_OS_ARDUINO)
*/
#ifndef GFX_COMPILER
#define GFX_COMPILER GFX_COMPILER_UNKNOWN
#endif
#define GFX_COMPILER_UNKNOWN 0 // Unknown compiler
#define GFX_COMPILER_MINGW32 1 // MingW32 (x86) compiler for windows
+ /**
+ * @brief Enable cpu specific code
+ * @details Defaults to GFX_CPU_UNKNOWN
+ * @note This is setting enables optimisations that are cpu specific. It does
+ * not need to be specified as reasonable defaults and various auto-detection
+ * will happen as required.
+ * @note Currently only used by ugfx generic thread handling (GOS_USE_OS_RAW32 and GOS_USE_OS_ARDUINO)
+ * @{
+ */
+ #ifndef GFX_CPU
+ #define GFX_CPU GFX_CPU_UNKNOWN
+ #endif
+ #define GFX_CPU_UNKNOWN 0 //**< Unknown cpu
+ #define GFX_CPU_CORTEX_M0 1 //**< Cortex M0
+ #define GFX_CPU_CORTEX_M1 2 //**< Cortex M1
+ #define GFX_CPU_CORTEX_M2 3 //**< Cortex M2
+ #define GFX_CPU_CORTEX_M3 4 //**< Cortex M3
+ #define GFX_CPU_CORTEX_M4 5 //**< Cortex M4
+ #define GFX_CPU_CORTEX_M4_FP 6 //**< Cortex M4 with hardware floating point
+ #define GFX_CPU_CORTEX_M7 7 //**< Cortex M7
+ #define GFX_CPU_CORTEX_M7_FP 8 //**< Cortex M7 with hardware floating point
+ /** @} */
/**
* @brief Should uGFX avoid initializing the operating system
* @details Defaults to FALSE
@@ -109,6 +132,16 @@
#define GFX_NO_OS_INIT FALSE
#endif
/**
+ * @brief Turn off warnings about initializing the operating system
+ * @details Defaults to FALSE
+ * @note This is only relevant where GOS cannot initialise the operating
+ * system automatically or the operating system initialisation has been
+ * explicitly turned off.
+ */
+ #ifndef GFX_OS_INIT_NO_WARNING
+ #define GFX_OS_INIT_NO_WARNING FALSE
+ #endif
+ /**
* @brief Should uGFX stuff be added to the FreeRTOS+Tracer
* @details Defaults to FALSE
*/
@@ -117,7 +150,8 @@
#endif
/**
* @brief How much RAM should uGFX use for the heap
- * @details Defaults to 0. Only valid with GFX_USE_OS_RAW32
+ * @details Defaults to 0.
+ * @note Only used when the generic ugfx heap code is used (GFX_USE_OS_RAW32 and GFX_USE_OS_ARDUINO)
* @note If 0 then the standard C runtime malloc(), free() and realloc()
* are used.
* @note If it is non-zero then this is the number of bytes of RAM
@@ -125,8 +159,8 @@
* runtime routines will be used and a new routine @p gfxAddHeapBlock()
* is added allowing the user to add extra memory blocks to the heap.
*/
- #ifndef GOS_RAW_HEAP_SIZE
- #define GOS_RAW_HEAP_SIZE 0
+ #ifndef GFX_OS_HEAP_SIZE
+ #define GFX_OS_HEAP_SIZE 0
#endif
/** @} */
diff --git a/src/gos/gos_raw32.c b/src/gos/gos_raw32.c
index 7d19717d..4e61feb9 100644
--- a/src/gos/gos_raw32.c
+++ b/src/gos/gos_raw32.c
@@ -12,14 +12,8 @@
#if GFX_USE_OS_RAW32
-#include <string.h> // Prototype for memcpy()
-
-#if GOS_RAW_HEAP_SIZE != 0
- static void _gosHeapInit(void);
-#else
- #define _gosHeapInit()
-#endif
-static void _gosThreadsInit(void);
+void _gosHeapInit(void);
+void _gosThreadsInit(void);
/*********************************************************
* Initialise
@@ -31,7 +25,9 @@ void _gosInit(void)
* On the other hand the C runtime should still already be initialized before
* getting here!
*/
- #warning "GOS: Raw32 - Make sure you initialize your hardware and the C runtime before calling gfxInit() in your application!"
+ #if !GFX_OS_INIT_NO_WARNING
+ #warning "GOS: Raw32 - Make sure you initialize your hardware and the C runtime before calling gfxInit() in your application!"
+ #endif
// Set up the heap allocator
_gosHeapInit();
@@ -46,7 +42,7 @@ void _gosDeinit(void)
}
/*********************************************************
- * For WIn32 emulation - automatically add the tick functions
+ * For Win32 emulation - automatically add the tick functions
* the user would normally have to provide for bare metal.
*********************************************************/
@@ -98,777 +94,4 @@ void gfxExit(void) {
#endif
}
-/*********************************************************
- * Head allocation functions
- *********************************************************/
-
-#if GOS_RAW_HEAP_SIZE == 0
- #include <stdlib.h> // Prototype for malloc(), realloc() and free()
-
- void *gfxAlloc(size_t sz) {
- return malloc(sz);
- }
-
- void *gfxRealloc(void *ptr, size_t oldsz, size_t newsz) {
- (void) oldsz;
- return realloc(ptr, newsz);
- }
-
- void gfxFree(void *ptr) {
- free(ptr);
- }
-
-#else
-
- // Slot structure - user memory follows
- typedef struct memslot {
- struct memslot *next; // The next memslot
- size_t sz; // Includes the size of this memslot.
- } memslot;
-
- // Free Slot - immediately follows the memslot structure
- typedef struct freeslot {
- memslot *nextfree; // The next free slot
- } freeslot;
-
- #define GetSlotSize(sz) ((((sz) + (sizeof(freeslot) - 1)) & ~(sizeof(freeslot) - 1)) + sizeof(memslot))
- #define NextFree(pslot) ((freeslot *)Slot2Ptr(pslot))->nextfree
- #define Ptr2Slot(p) ((memslot *)(p) - 1)
- #define Slot2Ptr(pslot) ((pslot)+1)
-
- static memslot * firstSlot;
- static memslot * lastSlot;
- static memslot * freeSlots;
- static char heap[GOS_RAW_HEAP_SIZE];
-
- static void _gosHeapInit(void) {
- lastSlot = 0;
- gfxAddHeapBlock(heap, GOS_RAW_HEAP_SIZE);
- }
-
- void gfxAddHeapBlock(void *ptr, size_t sz) {
- if (sz < sizeof(memslot)+sizeof(freeslot))
- return;
-
- if (lastSlot)
- lastSlot->next = (memslot *)ptr;
- else
- firstSlot = lastSlot = freeSlots = (memslot *)ptr;
-
- lastSlot->next = 0;
- lastSlot->sz = sz;
- NextFree(lastSlot) = 0;
- }
-
- void *gfxAlloc(size_t sz) {
- register memslot *prev, *p, *new;
-
- if (!sz) return 0;
- sz = GetSlotSize(sz);
- for (prev = 0, p = freeSlots; p != 0; prev = p, p = NextFree(p)) {
- // Loop till we have a block big enough
- if (p->sz < sz)
- continue;
- // Can we save some memory by splitting this block?
- if (p->sz >= sz + sizeof(memslot)+sizeof(freeslot)) {
- new = (memslot *)((char *)p + sz);
- new->next = p->next;
- p->next = new;
- new->sz = p->sz - sz;
- p->sz = sz;
- if (lastSlot == p)
- lastSlot = new;
- NextFree(new) = NextFree(p);
- NextFree(p) = new;
- }
- // Remove it from the free list
- if (prev)
- NextFree(prev) = NextFree(p);
- else
- freeSlots = NextFree(p);
- // Return the result found
- return Slot2Ptr(p);
- }
- // No slots large enough
- return 0;
- }
-
- void *gfxRealloc(void *ptr, size_t oldsz, size_t sz) {
- register memslot *prev, *p, *new;
- (void) oldsz;
-
- if (!ptr)
- return gfxAlloc(sz);
- if (!sz) {
- gfxFree(ptr);
- return 0;
- }
-
- p = Ptr2Slot(ptr);
- sz = GetSlotSize(sz);
-
- // If the next slot is free (and contiguous) merge it into this one
- if ((char *)p + p->sz == (char *)p->next) {
- for (prev = 0, new = freeSlots; new != 0; prev = new, new = NextFree(new)) {
- if (new == p->next) {
- p->next = new->next;
- p->sz += new->sz;
- if (prev)
- NextFree(prev) = NextFree(new);
- else
- freeSlots = NextFree(new);
- if (lastSlot == new)
- lastSlot = p;
- break;
- }
- }
- }
-
- // If this block is large enough we are nearly done
- if (sz < p->sz) {
- // Can we save some memory by splitting this block?
- if (p->sz >= sz + sizeof(memslot)+sizeof(freeslot)) {
- new = (memslot *)((char *)p + sz);
- new->next = p->next;
- p->next = new;
- new->sz = p->sz - sz;
- p->sz = sz;
- if (lastSlot == p)
- lastSlot = new;
- NextFree(new) = freeSlots;
- freeSlots = new;
- }
- return Slot2Ptr(p);
- }
-
- // We need to do this the hard way
- if ((new = gfxAlloc(sz)))
- return 0;
- memcpy(new, ptr, p->sz - sizeof(memslot));
- gfxFree(ptr);
- return new;
- }
-
- void gfxFree(void *ptr) {
- register memslot *prev, *p, *new;
-
- if (!ptr)
- return;
-
- p = Ptr2Slot(ptr);
-
- // If the next slot is free (and contiguous) merge it into this one
- if ((char *)p + p->sz == (char *)p->next) {
- for (prev = 0, new = freeSlots; new != 0; prev = new, new = NextFree(new)) {
- if (new == p->next) {
- p->next = new->next;
- p->sz += new->sz;
- if (prev)
- NextFree(prev) = NextFree(new);
- else
- freeSlots = NextFree(new);
- if (lastSlot == new)
- lastSlot = p;
- break;
- }
- }
- }
-
- // Add it into the free chain
- NextFree(p) = freeSlots;
- freeSlots = p;
- }
-#endif
-
-/*********************************************************
- * Semaphores and critical region functions
- *********************************************************/
-
-#if !defined(INTERRUPTS_OFF) || !defined(INTERRUPTS_ON)
- #define INTERRUPTS_OFF()
- #define INTERRUPTS_ON()
-#endif
-
-void gfxSystemLock(void) {
- INTERRUPTS_OFF();
-}
-
-void gfxSystemUnlock(void) {
- INTERRUPTS_ON();
-}
-
-void gfxMutexInit(gfxMutex *pmutex) {
- pmutex[0] = 0;
-}
-
-void gfxMutexEnter(gfxMutex *pmutex) {
- INTERRUPTS_OFF();
- while (pmutex[0]) {
- INTERRUPTS_ON();
- gfxYield();
- INTERRUPTS_OFF();
- }
- pmutex[0] = 1;
- INTERRUPTS_ON();
-}
-
-void gfxMutexExit(gfxMutex *pmutex) {
- pmutex[0] = 0;
-}
-
-void gfxSemInit(gfxSem *psem, semcount_t val, semcount_t limit) {
- psem->cnt = val;
- psem->limit = limit;
-}
-
-bool_t gfxSemWait(gfxSem *psem, delaytime_t ms) {
- systemticks_t starttm, delay;
-
- // Convert our delay to ticks
- switch (ms) {
- case TIME_IMMEDIATE:
- delay = TIME_IMMEDIATE;
- break;
- case TIME_INFINITE:
- delay = TIME_INFINITE;
- break;
- default:
- delay = gfxMillisecondsToTicks(ms);
- if (!delay) delay = 1;
- starttm = gfxSystemTicks();
- }
-
- INTERRUPTS_OFF();
- while (psem->cnt <= 0) {
- INTERRUPTS_ON();
- // Check if we have exceeded the defined delay
- switch (delay) {
- case TIME_IMMEDIATE:
- return FALSE;
- case TIME_INFINITE:
- break;
- default:
- if (gfxSystemTicks() - starttm >= delay)
- return FALSE;
- break;
- }
- gfxYield();
- INTERRUPTS_OFF();
- }
- psem->cnt--;
- INTERRUPTS_ON();
- return TRUE;
-}
-
-bool_t gfxSemWaitI(gfxSem *psem) {
- if (psem->cnt <= 0)
- return FALSE;
- psem->cnt--;
- return TRUE;
-}
-
-void gfxSemSignal(gfxSem *psem) {
- INTERRUPTS_OFF();
- gfxSemSignalI(psem);
- INTERRUPTS_ON();
-}
-
-void gfxSemSignalI(gfxSem *psem) {
- if (psem->cnt < psem->limit)
- psem->cnt++;
-}
-
-/*********************************************************
- * Sleep functions
- *********************************************************/
-
-void gfxSleepMilliseconds(delaytime_t ms) {
- systemticks_t starttm, delay;
-
- // Safety first
- switch (ms) {
- case TIME_IMMEDIATE:
- return;
- case TIME_INFINITE:
- while(1)
- gfxYield();
- return;
- }
-
- // Convert our delay to ticks
- delay = gfxMillisecondsToTicks(ms);
- starttm = gfxSystemTicks();
-
- do {
- gfxYield();
- } while (gfxSystemTicks() - starttm < delay);
-}
-
-void gfxSleepMicroseconds(delaytime_t ms) {
- systemticks_t starttm, delay;
-
- // Safety first
- switch (ms) {
- case TIME_IMMEDIATE:
- return;
- case TIME_INFINITE:
- while(1)
- gfxYield();
- return;
- }
-
- // Convert our delay to ticks
- delay = gfxMillisecondsToTicks(ms/1000);
- starttm = gfxSystemTicks();
-
- do {
- gfxYield();
- } while (gfxSystemTicks() - starttm < delay);
-}
-
-/*********************************************************
- * Threading functions
- *********************************************************/
-
-#if GOS_RAW_SCHEDULER == SCHED_USE_SETJMP
-
- /**
- * There are some compilers we know how they store the jmpbuf. For those
- * we can use the constant macro definitions. For others we have to "auto-detect".
- * Auto-detection is hairy and there is no guarantee it will work on all architectures.
- * For those it doesn't - read the compiler manuals and the library source code to
- * work out the correct macro values.
- * You can use the debugger to work out the values for your compiler and put them here.
- * Defining these macros as constant values makes the system behavior guaranteed but also
- * makes your code compiler and cpu architecture dependent. It also saves a heap of code
- * and a few bytes of RAM.
- */
- #if GFX_COMPILER == GFX_COMPILER_MINGW32
- #define AUTO_DETECT_MASK FALSE
- #define STACK_DIR_UP FALSE
- #define MASK1 0x00000011
- #define MASK2 0x00000000
- #define STACK_BASE 12
- #else
- // Use auto-detection of the stack frame format
- // Assumes all the relevant stuff to be relocated is in the first 256 bytes of the jmpbuf.
- #define AUTO_DETECT_MASK TRUE
- #define STACK_DIR_UP stackdirup // TRUE if the stack grow up instead of down
- #define MASK1 jmpmask1 // The 1st mask of jmp_buf elements that need relocation
- #define MASK2 jmpmask2 // The 2nd mask of jmp_buf elements that need relocation
- #define STACK_BASE stackbase // The base of the stack frame relative to the local variables
- static bool_t stackdirup;
- static uint32_t jmpmask1;
- static uint32_t jmpmask2;
- static size_t stackbase;
- #endif
-
- #include <setjmp.h> /* jmp_buf, setjmp(), longjmp() */
-
- /**
- * Some compilers define a _setjmp() and a setjmp().
- * The difference between them is that setjmp() saves the signal masks.
- * That is of no use to us so prefer to use the _setjmp() methods.
- * If they don't exist compile them to be the standard setjmp() function.
- * Similarly for longjmp().
- */
- #if (!defined(setjmp) && !defined(_setjmp)) || defined(__KEIL__) || defined(__C51__)
- #define _setjmp setjmp
- #endif
- #if (!defined(longjmp) && !defined(_longjmp)) || defined(__KEIL__) || defined(__C51__)
- #define _longjmp longjmp
- #endif
-
- typedef jmp_buf threadcxt;
-
-#elif GOS_RAW_SCHEDULER == SCHED_USE_CORTEX_M0 || GOS_RAW_SCHEDULER == SCHED_USE_CORTEX_M1
- typedef void * threadcxt;
-#elif GOS_RAW_SCHEDULER == SCHED_USE_CORTEX_M3 || GOS_RAW_SCHEDULER == SCHED_USE_CORTEX_M4
- typedef void * threadcxt;
-#else
- #error "GOS RAW32: Unsupported Scheduler. Try setting GOS_RAW_SCHEDULER = SCHED_USE_SETJMP"
-#endif
-
-typedef struct thread {
- struct thread * next; // Next thread
- int flags; // Flags
- #define FLG_THD_ALLOC 0x0001
- #define FLG_THD_MAIN 0x0002
- #define FLG_THD_DEAD 0x0004
- #define FLG_THD_WAIT 0x0008
- size_t size; // Size of the thread stack (including this structure)
- threadreturn_t (*fn)(void *param); // Thread function
- void * param; // Parameter for the thread function
- threadcxt cxt; // The current thread context.
-} thread;
-
-typedef struct threadQ {
- thread *head;
- thread *tail;
-} threadQ;
-
-static threadQ readyQ; // The list of ready threads
-static threadQ deadQ; // Where we put threads waiting to be deallocated
-static thread * current; // The current running thread
-static thread mainthread; // The main thread context
-
-static void Qinit(threadQ * q) {
- q->head = q->tail = 0;
-}
-
-static void Qadd(threadQ * q, thread *t) {
- t->next = 0;
- if (q->head) {
- q->tail->next = t;
- q->tail = t;
- } else
- q->head = q->tail = t;
-}
-
-static thread *Qpop(threadQ * q) {
- struct thread * t;
-
- if (!q->head)
- return 0;
- t = q->head;
- q->head = t->next;
- return t;
-}
-
-#if GOS_RAW_SCHEDULER == SCHED_USE_SETJMP && AUTO_DETECT_MASK
-
- // The structure for the saved stack frame information
- typedef struct saveloc {
- char * localptr;
- jmp_buf cxt;
- } saveloc;
-
- // A pointer to our auto-detection buffer.
- static saveloc *pframeinfo;
-
- /* These functions are not static to prevent the compiler removing them as functions */
-
- void get_stack_state(void) {
- char *c;
- pframeinfo->localptr = (char *)&c;
- _setjmp(pframeinfo->cxt);
- }
-
- void get_stack_state_in_fn(void) {
- pframeinfo++;
- get_stack_state();
- pframeinfo--;
- }
-#endif
-
-static void _gosThreadsInit(void) {
- Qinit(&readyQ);
- current = &mainthread;
- current->next = 0;
- current->size = sizeof(thread);
- current->flags = FLG_THD_MAIN;
- current->fn = 0;
- current->param = 0;
-
- #if GOS_RAW_SCHEDULER == SCHED_USE_SETJMP && AUTO_DETECT_MASK
- {
- uint32_t i;
- char ** pout;
- char ** pin;
- size_t diff;
- char * framebase;
-
- // Allocate a buffer to store our test data
- pframeinfo = gfxAlloc(sizeof(saveloc)*2);
-
- // Get details of the stack frame from within a function
- get_stack_state_in_fn();
-
- // Get details of the stack frame outside the function
- get_stack_state();
-
- /* Work out the frame entries to relocate by treating the jump buffer as an array of pointers */
- stackdirup = pframeinfo[1].localptr > pframeinfo[0].localptr;
- pout = (char **)pframeinfo[0].cxt;
- pin = (char **)pframeinfo[1].cxt;
- diff = pframeinfo[0].localptr - pframeinfo[1].localptr;
- framebase = pframeinfo[0].localptr;
- jmpmask1 = jmpmask2 = 0;
- for (i = 0; i < sizeof(jmp_buf)/sizeof(char *); i++, pout++, pin++) {
- if ((size_t)(*pout - *pin) == diff) {
- if (i < 32)
- jmpmask1 |= 1 << i;
- else
- jmpmask2 |= 1 << (i-32);
-
- if (stackdirup) {
- if (framebase > *pout)
- framebase = *pout;
- } else {
- if (framebase < *pout)
- framebase = *pout;
- }
- }
- }
- stackbase = stackdirup ? (pframeinfo[0].localptr - framebase) : (framebase - pframeinfo[0].localptr);
-
- // Clean up
- gfxFree(pframeinfo);
- }
- #endif
-}
-
-gfxThreadHandle gfxThreadMe(void) {
- return (gfxThreadHandle)current;
-}
-
-// Check if there are dead processes to deallocate
-static void cleanUpDeadThreads(void) {
- thread *p;
-
- while ((p = Qpop(&deadQ)))
- gfxFree(p);
-}
-
-#if GOS_RAW_SCHEDULER == SCHED_USE_SETJMP
- // Move the stack frame and relocate the context data
- void _gfxAdjustCxt(thread *t) {
- char ** s;
- char * nf;
- int diff;
- uint32_t i;
-
- // Copy the stack frame
- #if AUTO_DETECT_MASK
- if (STACK_DIR_UP) { // Stack grows up
- nf = (char *)(t) + sizeof(thread) + stackbase;
- memcpy(t+1, (char *)&s - stackbase, stackbase+sizeof(char *));
- } else { // Stack grows down
- nf = (char *)(t) + t->size - (stackbase + sizeof(char *));
- memcpy(nf, &s, stackbase+sizeof(char *));
- }
- #elif STACK_DIR_UP
- // Stack grows up
- nf = (char *)(t) + sizeof(thread) + stackbase;
- memcpy(t+1, (char *)&s - stackbase, stackbase+sizeof(char *));
- #else
- // Stack grows down
- nf = (char *)(t) + t->size - (stackbase + sizeof(char *));
- memcpy(nf, &s, stackbase+sizeof(char *));
- #endif
-
- // Relocate the context data
- s = (char **)(t->cxt);
- diff = nf - (char *)&s;
-
- // Relocate the elements we know need to be relocated
- for (i = 1; i && i < MASK1; i <<= 1, s++) {
- if ((MASK1 & i))
- *s += diff;
- }
- #ifdef MASK2
- for (i = 1; i && i < MASK2; i <<= 1, s++) {
- if ((MASK1 & i))
- *s += diff;
- }
- #endif
- }
- #define CXT_SET(t) { \
- if (!_setjmp(t->cxt)) { \
- _gfxAdjustCxt(t); \
- current = t; \
- _longjmp(current->cxt, 1); \
- } \
- }
- #define CXT_SAVE() if (_setjmp(current->cxt)) return
- #define CXT_RESTORE() _longjmp(current->cxt, 1)
-
-#elif GOS_RAW_SCHEDULER == SCHED_USE_CORTEX_M0 || GOS_RAW_SCHEDULER == SCHED_USE_CORTEX_M1
-
- // Use the EABI calling standard (ARM's AAPCS) - Save r4 - r11
-
- #define CXT_SET(t) { \
- register void* r13 __asm__("r13"); \
- current = t; \
- r13 = (char*)current + current->size; \
- }
-
- /**
- * Save the current thread context.
- *
- * Automatically returns the calling function when this thread gets restarted
- * with the thread handle as the return value
- */
- //
- #define CXT_SAVE() { \
- register void* r13 __asm__("r13"); \
- __asm__ volatile ( "push {r4, r5, r6, r7, lr} \n\t" \
- "mov r4, r8 \n\t" \
- "mov r5, r9 \n\t" \
- "mov r6, r10 \n\t" \
- "mov r7, r11 \n\t" \
- "push {r4, r5, r6, r7}" : : : "memory"); \
- current->cxt = r13; \
- }
- #define CXT_RESTORE() { \
- register void* r13 __asm__ ("r13"); \
- r13 = current->cxt; \
- __asm__ volatile ( "pop {r4, r5, r6, r7} \n\t" \
- "mov r8, r4 \n\t" \
- "mov r9, r5 \n\t" \
- "mov r10, r6 \n\t" \
- "mov r11, r7 \n\t" \
- "pop {r4, r5, r6, r7, pc}" : : "r" (r13) : "memory"); \
- }
-
-#elif GOS_RAW_SCHEDULER == SCHED_USE_CORTEX_M3 || GOS_RAW_SCHEDULER == SCHED_USE_CORTEX_M4
-
- // Use the EABI calling standard (ARM's AAPCS) - Save r4 - r11 and floating point if needed
-
- #define CXT_SET(t) { \
- register void* r13 __asm__("r13"); \
- current = t; \
- r13 = (char *)current + current->size; \
- }
-
- #if CORTEX_USE_FPU
- #define CXT_SAVE() { \
- register void* r13 __asm__("r13"); \
- __asm__ volatile ("push {r4, r5, r6, r7, r8, r9, r10, r11, lr}" : : : "memory");\
- __asm__ volatile ("vpush {s16-s31}" : : : "memory"); \
- current->cxt = r13; \
- }
- #define CXT_RESTORE() { \
- register void* r13 __asm__("r13"); \
- r13 = current->cxt; \
- __asm__ volatile ("vpop {s16-s31}" : : : "memory"); \
- __asm__ volatile ("pop {r4, r5, r6, r7, r8, r9, r10, r11, pc}" : : : "memory"); \
- }
- #else
- #define CXT_SAVE() { \
- register void* r13 __asm__("r13"); \
- __asm__ volatile ("push {r4, r5, r6, r7, r8, r9, r10, r11, lr}" : : : "memory");\
- current->cxt = r13; \
- }
- #define CXT_RESTORE() { \
- register void* r13 __asm__("r13"); \
- r13 = current->cxt; \
- __asm__ volatile ("pop {r4, r5, r6, r7, r8, r9, r10, r11, pc}" : : : "memory"); \
- }
- #endif
-#endif
-
-void gfxYield(void) {
-
- // Clean up zombies
- cleanUpDeadThreads();
-
- // Is there another thread to run?
- if (!readyQ.head)
- return;
-
- // Save the current thread (automatically returns when this thread gets re-executed)
- CXT_SAVE();
-
- // Add us back to the Queue
- Qadd(&readyQ, current);
-
- // Run the next process
- current = Qpop(&readyQ);
- CXT_RESTORE();
-}
-
-// This routine is not currently public - but it could be.
-void gfxThreadExit(threadreturn_t ret) {
- // Save the results in case someone is waiting
- current->param = (void *)ret;
- current->flags |= FLG_THD_DEAD;
-
- // Add us to the dead list if we need deallocation as we can't free ourselves.
- // If someone is waiting on the thread they will do the cleanup.
- if ((current->flags & (FLG_THD_ALLOC|FLG_THD_WAIT)) == FLG_THD_ALLOC)
- Qadd(&deadQ, current);
-
- // Set the next thread
- current = Qpop(&readyQ);
-
- // Was that the last thread? If so exit
- if (!current)
- gfxExit();
-
- // Switch to the new thread
- CXT_RESTORE();
-}
-
-void _gfxStartThread(thread *t) {
-
- // Save the current thread (automatically returns when this thread gets re-executed)
- CXT_SAVE();
-
- // Add the current thread to the queue because we are starting a new thread.
- Qadd(&readyQ, current);
-
- // Change to the new thread and the new stack
- CXT_SET(t);
-
- // Run the users function
- gfxThreadExit(current->fn(current->param));
-
- // We never get here!
-}
-
-gfxThreadHandle gfxThreadCreate(void *stackarea, size_t stacksz, threadpriority_t prio, DECLARE_THREAD_FUNCTION((*fn),p), void *param) {
- thread * t;
- (void) prio;
-
- // Ensure we have a minimum stack size
- if (stacksz < sizeof(thread)+64) {
- stacksz = sizeof(thread)+64;
- stackarea = 0;
- }
-
- if (stackarea) {
- t = (thread *)stackarea;
- t->flags = 0;
- } else {
- t = (thread *)gfxAlloc(stacksz);
- if (!t)
- return 0;
- t->flags = FLG_THD_ALLOC;
- }
- t->size = stacksz;
- t->fn = fn;
- t->param = param;
-
- _gfxStartThread(t);
-
- // Return the new thread handle
- return t;
-}
-
-threadreturn_t gfxThreadWait(gfxThreadHandle th) {
- thread * t;
-
- t = th;
- if (t == current)
- return -1;
-
- // Mark that we are waiting
- t->flags |= FLG_THD_WAIT;
-
- // Wait for the thread to die
- while(!(t->flags & FLG_THD_DEAD))
- gfxYield();
-
- // Unmark
- t->flags &= ~FLG_THD_WAIT;
-
- // Clean up resources if needed
- if (t->flags & FLG_THD_ALLOC)
- gfxFree(t);
-
- // Return the status left by the dead process
- return (threadreturn_t)t->param;
-}
-
#endif /* GFX_USE_OS_RAW32 */
diff --git a/src/gos/gos_raw32.h b/src/gos/gos_raw32.h
index 0661bd37..0fca9223 100644
--- a/src/gos/gos_raw32.h
+++ b/src/gos/gos_raw32.h
@@ -26,37 +26,6 @@
#if GFX_USE_OS_RAW32
/*===========================================================================*/
-/* Special Macros just for a Raw implementation */
-/*===========================================================================*/
-
-/**
- * @brief Set the maximum size of the heap.
- * @note If set to 0 then the C runtime library malloc() and free() are used.
- */
-#ifndef GOS_RAW_HEAP_SIZE
- #define GOS_RAW_HEAP_SIZE 0
-#endif
-
-/**
- * @brief Scheduler cpu support
- */
-#define SCHED_USE_SETJMP 0
-#define SCHED_USE_CORTEX_M0 1
-#define SCHED_USE_CORTEX_M1 2
-#define SCHED_USE_CORTEX_M2 3
-#define SCHED_USE_CORTEX_M3 4
-#define SCHED_USE_CORTEX_M4 5
-
-/**
- * @brief Set the preferred scheduler method
- * @note If not defined the SCHED_USE_SETJMP is used which should work for most platforms.
- */
-#ifndef GOS_RAW_SCHEDULER
- #define GOS_RAW_SCHEDULER SCHED_USE_SETJMP
-#endif
-
-
-/*===========================================================================*/
/* Type definitions */
/*===========================================================================*/
@@ -79,71 +48,26 @@ typedef unsigned char bool_t;
typedef uint32_t size_t;
#endif
-typedef uint32_t delaytime_t;
-typedef uint32_t systemticks_t;
-typedef short semcount_t;
-typedef int threadreturn_t;
-typedef int threadpriority_t;
-
-#define DECLARE_THREAD_FUNCTION(fnName, param) threadreturn_t fnName(void *param)
-#define DECLARE_THREAD_STACK(name, sz) uint8_t name[sz];
-
-#define TIME_IMMEDIATE 0
-#define TIME_INFINITE ((delaytime_t)-1)
-#define MAX_SEMAPHORE_COUNT 0x7FFF
-#define LOW_PRIORITY 0
-#define NORMAL_PRIORITY 1
-#define HIGH_PRIORITY 2
-
-typedef struct {
- semcount_t cnt;
- semcount_t limit;
-} gfxSem;
-
-typedef uint32_t gfxMutex;
-typedef void * gfxThreadHandle;
-
-#define gfxThreadClose(thread)
-#define gfxMutexDestroy(pmutex)
-#define gfxSemDestroy(psem)
-#define gfxSemCounter(psem) ((psem)->cnt)
-#define gfxSemCounterI(psem) ((psem)->cnt)
-
#ifdef __cplusplus
extern "C" {
#endif
- #if GOS_RAW_HEAP_SIZE != 0
- void gfxAddHeapBlock(void *ptr, size_t sz);
- #endif
-
void gfxHalt(const char *msg);
void gfxExit(void);
- void *gfxAlloc(size_t sz);
- void *gfxRealloc(void *ptr, size_t oldsz, size_t newsz);
- void gfxFree(void *ptr);
- void gfxYield(void);
- void gfxSleepMilliseconds(delaytime_t ms);
- void gfxSleepMicroseconds(delaytime_t ms);
- systemticks_t gfxSystemTicks(void);
- systemticks_t gfxMillisecondsToTicks(delaytime_t ms);
- void gfxSystemLock(void);
- void gfxSystemUnlock(void);
- void gfxMutexInit(gfxMutex *pmutex);
- void gfxMutexEnter(gfxMutex *pmutex);
- void gfxMutexExit(gfxMutex *pmutex);
- void gfxSemInit(gfxSem *psem, semcount_t val, semcount_t limit);
- bool_t gfxSemWait(gfxSem *psem, delaytime_t ms);
- bool_t gfxSemWaitI(gfxSem *psem);
- void gfxSemSignal(gfxSem *psem);
- void gfxSemSignalI(gfxSem *psem);
- gfxThreadHandle gfxThreadCreate(void *stackarea, size_t stacksz, threadpriority_t prio, DECLARE_THREAD_FUNCTION((*fn),p), void *param);
- threadreturn_t gfxThreadWait(gfxThreadHandle thread);
- gfxThreadHandle gfxThreadMe(void);
#ifdef __cplusplus
}
#endif
+/*===========================================================================*/
+/* Use the generic thread handling and heap handling */
+/*===========================================================================*/
+
+#define GOS_NEED_X_THREADS TRUE
+#define GOS_NEED_X_HEAP TRUE
+
+#include "gos_x_threads.h"
+#include "gos_x_heap.h"
+
#endif /* GFX_USE_OS_RAW32 */
#endif /* _GOS_RAW32_H */
diff --git a/src/gos/gos_rawrtos.c b/src/gos/gos_rawrtos.c
index c47c85bf..8efe2235 100644
--- a/src/gos/gos_rawrtos.c
+++ b/src/gos/gos_rawrtos.c
@@ -26,7 +26,8 @@ void _gosInit(void)
{
#if !GFX_NO_OS_INIT
#error "GOS: Operating System initialization for RawRTOS is not yet implemented in uGFX. Please set GFX_NO_OS_INIT to TRUE in your gfxconf.h"
- #else
+ #endif
+ #if !GFX_OS_INIT_NO_WARNING
#warning "GOS: Operating System initialization has been turned off. Make sure you call raw_os_start() before gfxInit() in your application!"
#endif
}
diff --git a/src/gos/gos_x_heap.c b/src/gos/gos_x_heap.c
new file mode 100644
index 00000000..94b74d37
--- /dev/null
+++ b/src/gos/gos_x_heap.c
@@ -0,0 +1,195 @@
+/*
+ * This file is subject to the terms of the GFX License. If a copy of
+ * the license was not distributed with this file, you can obtain one at:
+ *
+ * http://ugfx.org/license.html
+ */
+
+#include "gfx.h"
+
+#if GOS_NEED_X_HEAP
+
+#include <string.h> // Prototype for memcpy()
+
+
+#if GFX_OS_HEAP_SIZE == 0
+ #include <stdlib.h> // Prototype for malloc(), realloc() and free()
+
+ void _gosHeapInit(void) {
+ }
+ void *gfxAlloc(size_t sz) {
+ return malloc(sz);
+ }
+
+ void *gfxRealloc(void *ptr, size_t oldsz, size_t newsz) {
+ (void) oldsz;
+ return realloc(ptr, newsz);
+ }
+
+ void gfxFree(void *ptr) {
+ free(ptr);
+ }
+
+#else
+
+ // Slot structure - user memory follows
+ typedef struct memslot {
+ struct memslot *next; // The next memslot
+ size_t sz; // Includes the size of this memslot.
+ } memslot;
+
+ // Free Slot - immediately follows the memslot structure
+ typedef struct freeslot {
+ memslot *nextfree; // The next free slot
+ } freeslot;
+
+ #define GetSlotSize(sz) ((((sz) + (sizeof(freeslot) - 1)) & ~(sizeof(freeslot) - 1)) + sizeof(memslot))
+ #define NextFree(pslot) ((freeslot *)Slot2Ptr(pslot))->nextfree
+ #define Ptr2Slot(p) ((memslot *)(p) - 1)
+ #define Slot2Ptr(pslot) ((pslot)+1)
+
+ static memslot * firstSlot;
+ static memslot * lastSlot;
+ static memslot * freeSlots;
+ static char heap[GFX_OS_HEAP_SIZE];
+
+ void _gosHeapInit(void) {
+ lastSlot = 0;
+ gfxAddHeapBlock(heap, GFX_OS_HEAP_SIZE);
+ }
+
+ void gfxAddHeapBlock(void *ptr, size_t sz) {
+ if (sz < sizeof(memslot)+sizeof(freeslot))
+ return;
+
+ if (lastSlot)
+ lastSlot->next = (memslot *)ptr;
+ else
+ firstSlot = lastSlot = freeSlots = (memslot *)ptr;
+
+ lastSlot->next = 0;
+ lastSlot->sz = sz;
+ NextFree(lastSlot) = 0;
+ }
+
+ void *gfxAlloc(size_t sz) {
+ register memslot *prev, *p, *new;
+
+ if (!sz) return 0;
+ sz = GetSlotSize(sz);
+ for (prev = 0, p = freeSlots; p != 0; prev = p, p = NextFree(p)) {
+ // Loop till we have a block big enough
+ if (p->sz < sz)
+ continue;
+ // Can we save some memory by splitting this block?
+ if (p->sz >= sz + sizeof(memslot)+sizeof(freeslot)) {
+ new = (memslot *)((char *)p + sz);
+ new->next = p->next;
+ p->next = new;
+ new->sz = p->sz - sz;
+ p->sz = sz;
+ if (lastSlot == p)
+ lastSlot = new;
+ NextFree(new) = NextFree(p);
+ NextFree(p) = new;
+ }
+ // Remove it from the free list
+ if (prev)
+ NextFree(prev) = NextFree(p);
+ else
+ freeSlots = NextFree(p);
+ // Return the result found
+ return Slot2Ptr(p);
+ }
+ // No slots large enough
+ return 0;
+ }
+
+ void *gfxRealloc(void *ptr, size_t oldsz, size_t sz) {
+ register memslot *prev, *p, *new;
+ (void) oldsz;
+
+ if (!ptr)
+ return gfxAlloc(sz);
+ if (!sz) {
+ gfxFree(ptr);
+ return 0;
+ }
+
+ p = Ptr2Slot(ptr);
+ sz = GetSlotSize(sz);
+
+ // If the next slot is free (and contiguous) merge it into this one
+ if ((char *)p + p->sz == (char *)p->next) {
+ for (prev = 0, new = freeSlots; new != 0; prev = new, new = NextFree(new)) {
+ if (new == p->next) {
+ p->next = new->next;
+ p->sz += new->sz;
+ if (prev)
+ NextFree(prev) = NextFree(new);
+ else
+ freeSlots = NextFree(new);
+ if (lastSlot == new)
+ lastSlot = p;
+ break;
+ }
+ }
+ }
+
+ // If this block is large enough we are nearly done
+ if (sz < p->sz) {
+ // Can we save some memory by splitting this block?
+ if (p->sz >= sz + sizeof(memslot)+sizeof(freeslot)) {
+ new = (memslot *)((char *)p + sz);
+ new->next = p->next;
+ p->next = new;
+ new->sz = p->sz - sz;
+ p->sz = sz;
+ if (lastSlot == p)
+ lastSlot = new;
+ NextFree(new) = freeSlots;
+ freeSlots = new;
+ }
+ return Slot2Ptr(p);
+ }
+
+ // We need to do this the hard way
+ if ((new = gfxAlloc(sz)))
+ return 0;
+ memcpy(new, ptr, p->sz - sizeof(memslot));
+ gfxFree(ptr);
+ return new;
+ }
+
+ void gfxFree(void *ptr) {
+ register memslot *prev, *p, *new;
+
+ if (!ptr)
+ return;
+
+ p = Ptr2Slot(ptr);
+
+ // If the next slot is free (and contiguous) merge it into this one
+ if ((char *)p + p->sz == (char *)p->next) {
+ for (prev = 0, new = freeSlots; new != 0; prev = new, new = NextFree(new)) {
+ if (new == p->next) {
+ p->next = new->next;
+ p->sz += new->sz;
+ if (prev)
+ NextFree(prev) = NextFree(new);
+ else
+ freeSlots = NextFree(new);
+ if (lastSlot == new)
+ lastSlot = p;
+ break;
+ }
+ }
+ }
+
+ // Add it into the free chain
+ NextFree(p) = freeSlots;
+ freeSlots = p;
+ }
+#endif
+
+#endif /* GOS_NEED_X_HEAP */
diff --git a/src/gos/gos_x_heap.h b/src/gos/gos_x_heap.h
new file mode 100644
index 00000000..3612989c
--- /dev/null
+++ b/src/gos/gos_x_heap.h
@@ -0,0 +1,62 @@
+/*
+ * This file is subject to the terms of the GFX License. If a copy of
+ * the license was not distributed with this file, you can obtain one at:
+ *
+ * http://ugfx.org/license.html
+ */
+
+/**
+ * The raw32 GOS implementation supports any 32 bit processor with or without an
+ * underlying operating system. It uses cooperative multi-tasking. Be careful
+ * when writing device drivers not to disturb the assumptions this creates by performing
+ * call-backs to uGFX code unless you define the INTERRUPTS_OFF() and INTERRUPTS_ON() macros.
+ * It still requires some C runtime library support...
+ * enough startup to initialise the stack, interrupts, static data etc and call main().
+ * setjmp() and longjmp() - for threading
+ * memcpy() - for heap and threading
+ * malloc(), realloc and free() - if GFX_OS_HEAP_SIZE == 0
+ *
+ * You must also define the following routines in your own code so that timing functions will work...
+ * systemticks_t gfxSystemTicks(void);
+ * systemticks_t gfxMillisecondsToTicks(delaytime_t ms);
+ */
+#ifndef _GOS_X_HEAP_H
+#define _GOS_X_HEAP_H
+
+#if GOS_NEED_X_HEAP
+
+
+/*===========================================================================*/
+/* Special Macros */
+/*===========================================================================*/
+
+/**
+ * @brief Set the maximum size of the heap.
+ * @note If set to 0 then the C runtime library malloc() and free() are used.
+ */
+#ifndef GFX_OS_HEAP_SIZE
+ #define GFX_OS_HEAP_SIZE 0
+#endif
+
+/*===========================================================================*/
+/* Type definitions */
+/*===========================================================================*/
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+ #if GFX_OS_HEAP_SIZE != 0
+ void gfxAddHeapBlock(void *ptr, size_t sz);
+ #endif
+
+ void *gfxAlloc(size_t sz);
+ void *gfxRealloc(void *ptr, size_t oldsz, size_t newsz);
+ void gfxFree(void *ptr);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* GOS_NEED_X_HEAP */
+#endif /* _GOS_X_HEAP_H */
diff --git a/src/gos/gos_x_threads.c b/src/gos/gos_x_threads.c
new file mode 100644
index 00000000..8a781b21
--- /dev/null
+++ b/src/gos/gos_x_threads.c
@@ -0,0 +1,672 @@
+/*
+ * This file is subject to the terms of the GFX License. If a copy of
+ * the license was not distributed with this file, you can obtain one at:
+ *
+ * http://ugfx.org/license.html
+ */
+
+#include "gfx.h"
+
+#if GOS_NEED_X_THREADS
+
+/*********************************************************
+ * Semaphores and critical region functions
+ *********************************************************/
+
+#if !defined(INTERRUPTS_OFF) || !defined(INTERRUPTS_ON)
+ #define INTERRUPTS_OFF()
+ #define INTERRUPTS_ON()
+#endif
+
+void gfxSystemLock(void) {
+ INTERRUPTS_OFF();
+}
+
+void gfxSystemUnlock(void) {
+ INTERRUPTS_ON();
+}
+
+void gfxMutexInit(gfxMutex *pmutex) {
+ pmutex[0] = 0;
+}
+
+void gfxMutexEnter(gfxMutex *pmutex) {
+ INTERRUPTS_OFF();
+ while (pmutex[0]) {
+ INTERRUPTS_ON();
+ gfxYield();
+ INTERRUPTS_OFF();
+ }
+ pmutex[0] = 1;
+ INTERRUPTS_ON();
+}
+
+void gfxMutexExit(gfxMutex *pmutex) {
+ pmutex[0] = 0;
+}
+
+void gfxSemInit(gfxSem *psem, semcount_t val, semcount_t limit) {
+ psem->cnt = val;
+ psem->limit = limit;
+}
+
+bool_t gfxSemWait(gfxSem *psem, delaytime_t ms) {
+ systemticks_t starttm, delay;
+
+ // Convert our delay to ticks
+ starttm = 0;
+ switch (ms) {
+ case TIME_IMMEDIATE:
+ delay = TIME_IMMEDIATE;
+ break;
+ case TIME_INFINITE:
+ delay = TIME_INFINITE;
+ break;
+ default:
+ delay = gfxMillisecondsToTicks(ms);
+ if (!delay) delay = 1;
+ starttm = gfxSystemTicks();
+ }
+
+ INTERRUPTS_OFF();
+ while (psem->cnt <= 0) {
+ INTERRUPTS_ON();
+ // Check if we have exceeded the defined delay
+ switch (delay) {
+ case TIME_IMMEDIATE:
+ return FALSE;
+ case TIME_INFINITE:
+ break;
+ default:
+ if (gfxSystemTicks() - starttm >= delay)
+ return FALSE;
+ break;
+ }
+ gfxYield();
+ INTERRUPTS_OFF();
+ }
+ psem->cnt--;
+ INTERRUPTS_ON();
+ return TRUE;
+}
+
+bool_t gfxSemWaitI(gfxSem *psem) {
+ if (psem->cnt <= 0)
+ return FALSE;
+ psem->cnt--;
+ return TRUE;
+}
+
+void gfxSemSignal(gfxSem *psem) {
+ INTERRUPTS_OFF();
+ gfxSemSignalI(psem);
+ INTERRUPTS_ON();
+}
+
+void gfxSemSignalI(gfxSem *psem) {
+ if (psem->cnt < psem->limit)
+ psem->cnt++;
+}
+
+/*********************************************************
+ * Sleep functions
+ *********************************************************/
+
+void gfxSleepMilliseconds(delaytime_t ms) {
+ systemticks_t starttm, delay;
+
+ // Safety first
+ switch (ms) {
+ case TIME_IMMEDIATE:
+ return;
+ case TIME_INFINITE:
+ while(1)
+ gfxYield();
+ return;
+ }
+
+ // Convert our delay to ticks
+ delay = gfxMillisecondsToTicks(ms);
+ starttm = gfxSystemTicks();
+
+ do {
+ gfxYield();
+ } while (gfxSystemTicks() - starttm < delay);
+}
+
+void gfxSleepMicroseconds(delaytime_t ms) {
+ systemticks_t starttm, delay;
+
+ // Safety first
+ switch (ms) {
+ case TIME_IMMEDIATE:
+ return;
+ case TIME_INFINITE:
+ while(1)
+ gfxYield();
+ return;
+ }
+
+ // Convert our delay to ticks
+ delay = gfxMillisecondsToTicks(ms/1000);
+ starttm = gfxSystemTicks();
+
+ do {
+ gfxYield();
+ } while (gfxSystemTicks() - starttm < delay);
+}
+
+/*********************************************************
+ * Threading functions
+ *********************************************************/
+
+/** For each scheduler the following need to be defined...
+ *
+ * void _gfxThreadsInit(void); - Initialise the scheduler
+ * void _gfxStartThread(thread *oldt, thread *newt); - Start a new thread
+ * void _gfxTaskSwitch(thread *oldt, thread *newt); - Switch to a different thread
+ *
+ */
+
+typedef struct thread {
+ struct thread * next; // Next thread
+ int flags; // Flags
+ #define FLG_THD_ALLOC 0x0001
+ #define FLG_THD_MAIN 0x0002
+ #define FLG_THD_DEAD 0x0004
+ #define FLG_THD_WAIT 0x0008
+ size_t size; // Size of the thread stack (including this structure)
+ threadreturn_t (*fn)(void *param); // Thread function
+ void * param; // Parameter for the thread function
+ void * cxt; // The current thread context.
+ } thread;
+
+typedef struct threadQ {
+ thread *head;
+ thread *tail;
+} threadQ;
+
+static threadQ readyQ; // The list of ready threads
+static threadQ deadQ; // Where we put threads waiting to be deallocated
+static thread * current; // The current running thread
+static thread mainthread; // The main thread context
+
+#if GFX_CPU == GFX_CPU_UNKNOWN
+
+ #include <string.h> // Prototype for memcpy()
+ #include <setjmp.h>
+
+ /**
+ * Some compilers define a _setjmp() and a setjmp().
+ * The difference between them is that setjmp() saves the signal masks.
+ * That is of no use to us so we prefer to use the _setjmp() methods.
+ * If they don't exist compile them to be the standard setjmp() function.
+ * Similarly for longjmp().
+ */
+ #if (!defined(setjmp) && !defined(_setjmp)) || defined(__KEIL__) || defined(__C51__)
+ #define CXT_SAVE setjmp
+ #else
+ #define CXT_SAVE _setjmp
+ #endif
+ #if (!defined(longjmp) && !defined(_longjmp)) || defined(__KEIL__) || defined(__C51__)
+ #define CXT_RESTORE longjmp
+ #else
+ #define CXT_RESTORE _longjmp
+ #endif
+
+ // A place to store the main thread context.
+ // All other threads will store the context directly after the thread structure (as part of the stack space).
+ static jmp_buf maincxt;
+
+ /**
+ * There are some compilers we know how they store the jmpbuf. For those
+ * we can use the constant macro definitions. For others we have to "auto-detect".
+ * Auto-detection is hairy and there is no guarantee it will work on all architectures.
+ * For those it doesn't - read the compiler manuals and the library source code to
+ * work out the correct macro values.
+ * You can use the debugger to work out the values for your compiler and put them here.
+ * Defining these macros as constant values makes the system behaviour guaranteed but also
+ * makes your code compiler and cpu architecture dependent. It also saves a heap of code
+ * and a few bytes of RAM.
+ *
+ * MACROS:
+ *
+ * AUTO_DETECT_STACKFRAME TRUE/FALSE - TRUE to auto-detect stack frame structure
+ * STACK_DIR_UP Macro/bool_t - TRUE if the stack grows up instead of down
+ * MASK1 Macro/uint32_t - The 1st mask of jmp_buf elements that need relocation
+ * MASK2 Macro/uint32_t - The 2nd mask of jmp_buf elements that need relocation
+ * STACK_BASE Macro/size_t - The base of the stack frame relative to the local variables
+ * _gfxThreadsInit() Macro/Function - Initialise the scheduler
+ *
+ */
+ #if GFX_COMPILER == GFX_COMPILER_MINGW32
+
+ #define AUTO_DETECT_STACKFRAME FALSE
+ #define STACK_DIR_UP FALSE
+ #define MASK1 0x00000011
+ #define MASK2 0x00000000
+ #define STACK_BASE 12
+ #define _gfxThreadsInit() mainthread.cxt = maincxt
+
+ #else
+
+ // Use auto-detection of the stack frame format
+ // Assumes all the relevant stuff to be relocated is in the first 256 bytes of the jmpbuf.
+ #define AUTO_DETECT_STACKFRAME TRUE
+ #define STACK_DIR_UP stackdirup // TRUE if the stack grow up instead of down
+ #define MASK1 jmpmask1 // The 1st mask of jmp_buf elements that need relocation
+ #define MASK2 jmpmask2 // The 2nd mask of jmp_buf elements that need relocation
+ #define STACK_BASE stackbase // The base of the stack frame relative to the local variables
+
+ // The structure for the saved stack frame information
+ typedef struct saveloc {
+ char * localptr;
+ jmp_buf cxt;
+ } saveloc;
+
+ static bool_t stackdirup;
+ static uint32_t jmpmask1;
+ static uint32_t jmpmask2;
+ static size_t stackbase;
+ static saveloc *pframeinfo;
+
+ // These two functions are not static to prevent the compiler removing them as functions
+ void _gfxGetStackState(void) {
+ char *c;
+ pframeinfo->localptr = (char *)&c;
+ CXT_SAVE(pframeinfo->cxt);
+ }
+ void _gfxGetStackStateInFn(void) {
+ pframeinfo++;
+ _gfxGetStackState();
+ pframeinfo--;
+ }
+ static void _gfxThreadsInit(void) {
+ uint32_t i;
+ char ** pout;
+ char ** pin;
+ size_t diff;
+ char * framebase;
+ saveloc tmpsaveloc[2];
+
+ // Create the main thread context
+ mainthread.cxt = maincxt;
+
+ // Allocate a buffer to store our test data
+ pframeinfo = tmpsaveloc;
+
+ // Get details of the stack frame from within a function
+ _gfxGetStackStateInFn();
+
+ // Get details of the stack frame outside the function
+ _gfxGetStackState();
+
+ /* Work out the frame entries to relocate by treating the jump buffer as an array of pointers */
+ stackdirup = pframeinfo[1].localptr > pframeinfo[0].localptr;
+ pout = (char **)pframeinfo[0].cxt;
+ pin = (char **)pframeinfo[1].cxt;
+ diff = pframeinfo[0].localptr - pframeinfo[1].localptr;
+ framebase = pframeinfo[0].localptr;
+ jmpmask1 = jmpmask2 = 0;
+ for (i = 0; i < sizeof(jmp_buf)/sizeof(char *); i++, pout++, pin++) {
+ if ((size_t)(*pout - *pin) == diff) {
+ if (i < 32)
+ jmpmask1 |= 1 << i;
+ else
+ jmpmask2 |= 1 << (i-32);
+
+ if (stackdirup) {
+ if (framebase > *pout)
+ framebase = *pout;
+ } else {
+ if (framebase < *pout)
+ framebase = *pout;
+ }
+ }
+ }
+ stackbase = stackdirup ? (pframeinfo[0].localptr - framebase) : (framebase - pframeinfo[0].localptr);
+ }
+
+ #endif
+
+ // Move the stack frame and relocate the context data
+ static void _gfxAdjustCxt(thread *t) {
+ char ** s;
+ char * nf;
+ int diff;
+ uint32_t i;
+
+ // Copy the stack frame
+ #if AUTO_DETECT_STACKFRAME
+ if (STACK_DIR_UP) { // Stack grows up
+ nf = (char *)(t) + sizeof(thread) + sizeof(jmp_buf) + stackbase;
+ memcpy(t+1, (char *)&s - stackbase, stackbase+sizeof(char *));
+ } else { // Stack grows down
+ nf = (char *)(t) + t->size - (stackbase + sizeof(char *));
+ memcpy(nf, &s, stackbase+sizeof(char *));
+ }
+ #elif STACK_DIR_UP
+ // Stack grows up
+ nf = (char *)(t) + sizeof(thread) + sizeof(jmp_buf) + stackbase;
+ memcpy(t+1, (char *)&s - stackbase, stackbase+sizeof(char *));
+ #else
+ // Stack grows down
+ nf = (char *)(t) + t->size - (stackbase + sizeof(char *));
+ memcpy(nf, &s, stackbase+sizeof(char *));
+ #endif
+
+ // Relocate the context data
+ s = (char **)(t->cxt);
+ diff = nf - (char *)&s;
+
+ // Relocate the elements we know need to be relocated
+ for (i = MASK1; i ; i >>= 1, s++) {
+ if ((i & 1))
+ *s += diff;
+ }
+ #ifdef MASK2
+ s = (char **)(t->cxt)+32;
+ for (i = MASK2; i ; i >>= 1, s++) {
+ if ((i & 1))
+ *s += diff;
+ }
+ #endif
+ }
+ static void _gfxXSwitch(thread *oldt, thread *newt, bool_t doBuildFrame) {
+
+ // Save the old context
+ if (CXT_SAVE(oldt->cxt)) return;
+
+ // Do we need to build a new context?
+ if (doBuildFrame) {
+
+ // Save our existing context as a starting point for the new context
+ newt->cxt = newt+1;
+ if (CXT_SAVE(newt->cxt)) {
+
+ // We are now running the new thread
+
+ // We can't use any of the above function parameters here
+ // as we are on a different stack.
+
+ // Run the users function.
+ gfxThreadExit(current->fn(current->param));
+
+ // We never get here as gfxThreadExit() never returns
+ }
+
+ // Adjust the new context so the stack references are correct
+ _gfxAdjustCxt(newt);
+ }
+
+ // Start the new context
+ CXT_RESTORE(newt->cxt, 1);
+ }
+
+ #define _gfxTaskSwitch(oldt, newt) _gfxXSwitch(oldt, newt, FALSE)
+ #define _gfxStartThread(oldt, newt) _gfxXSwitch(oldt, newt, TRUE)
+
+#elif GFX_CPU == GFX_CPU_CORTEX_M0 || GFX_CPU == GFX_CPU_CORTEX_M1
+
+ // Use the EABI calling standard (ARM's AAPCS) - Save r4 - r11
+ // The context is saved at the current stack location and a pointer is maintained in the thread structure.
+
+ #define _gfxThreadsInit()
+
+ static __attribute__((pcs("aapcs"),naked)) void _gfxTaskSwitch(thread *oldt, thread *newt) {
+ __asm__ volatile ( "push {r4, r5, r6, r7, lr} \n\t"
+ "mov r4, r8 \n\t"
+ "mov r5, r9 \n\t"
+ "mov r6, r10 \n\t"
+ "mov r7, r11 \n\t"
+ "push {r4, r5, r6, r7} \n\t"
+ "str sp, %[oldtcxt] \n\t"
+ "ldr sp, %[newtcxt] \n\t"
+ "pop {r4, r5, r6, r7} \n\t"
+ "mov r8, r4 \n\t"
+ "mov r9, r5 \n\t"
+ "mov r10, r6 \n\t"
+ "mov r11, r7 \n\t"
+ "pop {r4, r5, r6, r7, pc} \n\t"
+ : [newtcxt] "=m" (newt->cxt)
+ : [oldtcxt] "m" (oldt->cxt)
+ : "memory");
+ }
+
+ static __attribute__((pcs("aapcs"),naked)) void _gfxStartThread(thread *oldt, thread *newt) {
+ newt->cxt = (char *)newt + newt->size;
+ __asm__ volatile ( "push {r4, r5, r6, r7, r8, r9, r10, r11, lr} \n\t" // save current context
+ "str sp, %[oldtcxt] \n\t" // save context pointer
+ "ldr sp, %[newtcxt] \n\t" // load new context pointer
+ : [newtcxt] "=m" (newt->cxt)
+ : [oldtcxt] "m" (oldt->cxt)
+ : "memory");
+
+ // Run the users function
+ gfxThreadExit(current->fn(current->param));
+ }
+
+#elif GFX_CPU == GFX_CPU_CORTEX_M3 || GFX_CPU == GFX_CPU_CORTEX_M4 || GFX_CPU == GFX_CPU_CORTEX_M7
+
+ // Use the EABI calling standard (ARM's AAPCS) - Save r4 - r11
+ // The context is saved at the current stack location and a pointer is maintained in the thread structure.
+
+ #if CORTEX_USE_FPU
+ #warning "GOS Threads: You have specified GFX_CPU=GFX_CPU_CORTX_M? with no hardware floating point support but CORTEX_USE_FPU is TRUE. Try using GFX_CPU_GFX_CPU_CORTEX_M?_FP instead"
+ #endif
+
+ #define _gfxThreadsInit()
+
+ static __attribute__((pcs("aapcs"),naked)) void _gfxTaskSwitch(thread *oldt, thread *newt) {
+ __asm__ volatile ( "push {r4, r5, r6, r7, r8, r9, r10, r11, lr} \n\t"
+ "str sp, %[oldtcxt] \n\t"
+ "ldr sp, %[newtcxt] \n\t"
+ "pop {r4, r5, r6, r7, r8, r9, r10, r11, pc} \n\t"
+ : [newtcxt] "=m" (newt->cxt)
+ : [oldtcxt] "m" (oldt->cxt)
+ : "memory");
+ }
+
+ static __attribute__((pcs("aapcs"),naked)) void _gfxStartThread(thread *oldt, thread *newt) {
+ newt->cxt = (char *)newt + newt->size;
+ __asm__ volatile ( "push {r4, r5, r6, r7, r8, r9, r10, r11, lr} \n\t"
+ "str sp, %[oldtcxt] \n\t"
+ "ldr sp, %[newtcxt] \n\t"
+ : [newtcxt] "=m" (newt->cxt)
+ : [oldtcxt] "m" (oldt->cxt)
+ : "memory");
+
+ // Run the users function
+ gfxThreadExit(current->fn(current->param));
+ }
+
+#elif GFX_CPU == GFX_CPU == GFX_CPU_CORTEX_M4_FP || GFX_CPU == GFX_CPU_CORTEX_M7_FP
+
+ // Use the EABI calling standard (ARM's AAPCS) - Save r4 - r11 and floating point
+ // The context is saved at the current stack location and a pointer is maintained in the thread structure.
+
+ #if !CORTEX_USE_FPU
+ #warning "GOS Threads: You have specified GFX_CPU=GFX_CPU_CORTX_M?_FP with hardware floating point support but CORTEX_USE_FPU is FALSE. Try using GFX_CPU_GFX_CPU_CORTEX_M? instead"
+ #endif
+
+ #define _gfxThreadsInit()
+
+ static __attribute__((pcs("aapcs-vfp"),naked)) void _gfxTaskSwitch(thread *oldt, thread *newt) {
+ __asm__ volatile ( "push {r4, r5, r6, r7, r8, r9, r10, r11, lr} \n\t"
+ "vpush {s16-s31} \n\t"
+ "str sp, %[oldtcxt] \n\t"
+ "ldr sp, %[newtcxt] \n\t"
+ "vpop {s16-s31} \n\t"
+ "pop {r4, r5, r6, r7, r8, r9, r10, r11, pc} \n\t"
+ : [newtcxt] "=m" (newt->cxt)
+ : [oldtcxt] "m" (oldt->cxt)
+ : "memory");
+ }
+
+ static __attribute__((pcs("aapcs-vfp"),naked)) void _gfxStartThread(thread *oldt, thread *newt) {
+ newt->cxt = (char *)newt + newt->size;
+ __asm__ volatile ( "push {r4, r5, r6, r7, r8, r9, r10, r11, lr} \n\t"
+ "vpush {s16-s31} \n\t"
+ "str sp, %[oldtcxt] \n\t"
+ "ldr sp, %[newtcxt] \n\t"
+ : [newtcxt] "=m" (newt->cxt)
+ : [oldtcxt] "m" (oldt->cxt)
+ : "memory");
+
+ // Run the users function
+ gfxThreadExit(current->fn(current->param));
+ }
+
+#else
+ #error "GOS Threads: Unsupported Scheduler. Try setting GFX_CPU = GFX_CPU_UNKNOWN"
+#endif
+
+static void Qinit(threadQ * q) {
+ q->head = q->tail = 0;
+}
+
+static void Qadd(threadQ * q, thread *t) {
+ t->next = 0;
+ if (q->head) {
+ q->tail->next = t;
+ q->tail = t;
+ } else
+ q->head = q->tail = t;
+}
+
+static thread *Qpop(threadQ * q) {
+ struct thread * t;
+
+ if (!q->head)
+ return 0;
+ t = q->head;
+ q->head = t->next;
+ return t;
+}
+
+void _gosThreadsInit(void) {
+ Qinit(&readyQ);
+
+ mainthread.next = 0;
+ mainthread.size = sizeof(thread);
+ mainthread.flags = FLG_THD_MAIN;
+ mainthread.fn = 0;
+ mainthread.param = 0;
+
+ _gfxThreadsInit();
+
+ current = &mainthread;
+}
+
+gfxThreadHandle gfxThreadMe(void) {
+ return (gfxThreadHandle)current;
+}
+
+// Check if there are dead processes to deallocate
+static void cleanUpDeadThreads(void) {
+ thread *p;
+
+ while ((p = Qpop(&deadQ)))
+ gfxFree(p);
+}
+
+void gfxYield(void) {
+ thread *me;
+
+ // Clean up zombies
+ cleanUpDeadThreads();
+
+ // Is there another thread to run?
+ if (!readyQ.head)
+ return;
+
+ Qadd(&readyQ, me = current);
+ current = Qpop(&readyQ);
+ _gfxTaskSwitch(me, current);
+}
+
+// This routine is not currently public - but it could be.
+void gfxThreadExit(threadreturn_t ret) {
+ thread *me;
+
+ // Save the results in case someone is waiting
+ me = current;
+ me->param = (void *)ret;
+ me->flags |= FLG_THD_DEAD;
+
+ // Add us to the dead list if we need deallocation as we can't free ourselves.
+ // If someone is waiting on the thread they will do the cleanup.
+ if ((me->flags & (FLG_THD_ALLOC|FLG_THD_WAIT)) == FLG_THD_ALLOC)
+ Qadd(&deadQ, me);
+
+ // Set the next thread. Exit if it was the last thread
+ if (!(current = Qpop(&readyQ)))
+ gfxExit();
+
+ // Switch to the new thread
+ _gfxTaskSwitch(me, current);
+
+ // We never get back here as we didn't re-queue ourselves
+}
+
+gfxThreadHandle gfxThreadCreate(void *stackarea, size_t stacksz, threadpriority_t prio, DECLARE_THREAD_FUNCTION((*fn),p), void *param) {
+ thread * t;
+ thread * me;
+ (void) prio;
+
+ // Ensure we have a minimum stack size
+ if (stacksz < sizeof(thread)+64) {
+ stacksz = sizeof(thread)+64;
+ stackarea = 0;
+ }
+
+ if (stackarea) {
+ t = (thread *)stackarea;
+ t->flags = 0;
+ } else {
+ t = (thread *)gfxAlloc(stacksz);
+ if (!t)
+ return 0;
+ t->flags = FLG_THD_ALLOC;
+ }
+ t->size = stacksz;
+ t->fn = fn;
+ t->param = param;
+
+ // Add the current thread to the queue because we are starting a new thread.
+ me = current;
+ Qadd(&readyQ, me);
+ current = t;
+
+ _gfxStartThread(me, t);
+
+ // Return the new thread handle
+ return t;
+}
+
+threadreturn_t gfxThreadWait(gfxThreadHandle th) {
+ thread * t;
+
+ t = th;
+ if (t == current)
+ return -1;
+
+ // Mark that we are waiting
+ t->flags |= FLG_THD_WAIT;
+
+ // Wait for the thread to die
+ while(!(t->flags & FLG_THD_DEAD))
+ gfxYield();
+
+ // Unmark
+ t->flags &= ~FLG_THD_WAIT;
+
+ // Clean up resources if needed
+ if (t->flags & FLG_THD_ALLOC)
+ gfxFree(t);
+
+ // Return the status left by the dead process
+ return (threadreturn_t)t->param;
+}
+
+#endif /* GFX_USE_OS_RAW32 */
diff --git a/src/gos/gos_x_threads.h b/src/gos/gos_x_threads.h
new file mode 100644
index 00000000..78c30ac4
--- /dev/null
+++ b/src/gos/gos_x_threads.h
@@ -0,0 +1,103 @@
+/*
+ * This file is subject to the terms of the GFX License. If a copy of
+ * the license was not distributed with this file, you can obtain one at:
+ *
+ * http://ugfx.org/license.html
+ */
+
+/**
+ * This threading implementation supports most 32 bit processors with or without an
+ * underlying operating system. It uses cooperative multi-tasking. Be careful
+ * when writing device drivers not to disturb the assumptions this creates by performing
+ * call-backs from interrupt handlers to uGFX code unless you define the INTERRUPTS_OFF()
+ * and INTERRUPTS_ON() macros.
+ * It still requires some C runtime library support for the setjmp implementation...
+ * setjmp() and longjmp() - for threading
+ * memcpy() - for heap and threading
+ *
+ * You must also define the following routines in your own code so that timing functions will work...
+ * systemticks_t gfxSystemTicks(void);
+ * systemticks_t gfxMillisecondsToTicks(delaytime_t ms);
+ */
+#ifndef _GOS_X_THREADS_H
+#define _GOS_X_THREADS_H
+
+#if GOS_NEED_X_THREADS
+
+typedef uint32_t delaytime_t;
+typedef uint32_t systemticks_t;
+typedef short semcount_t;
+typedef int threadreturn_t;
+typedef int threadpriority_t;
+
+#define DECLARE_THREAD_FUNCTION(fnName, param) threadreturn_t fnName(void *param)
+#define DECLARE_THREAD_STACK(name, sz) uint8_t name[sz];
+
+#define TIME_IMMEDIATE 0
+#define TIME_INFINITE ((delaytime_t)-1)
+#define MAX_SEMAPHORE_COUNT 0x7FFF
+#define LOW_PRIORITY 0
+#define NORMAL_PRIORITY 1
+#define HIGH_PRIORITY 2
+
+typedef struct {
+ semcount_t cnt;
+ semcount_t limit;
+} gfxSem;
+
+typedef uint32_t gfxMutex;
+typedef void * gfxThreadHandle;
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+ // Required timing functions - supplied by the user or the operating system
+ systemticks_t gfxSystemTicks(void);
+ systemticks_t gfxMillisecondsToTicks(delaytime_t ms);
+
+ // Sleep Functions
+ void gfxSleepMilliseconds(delaytime_t ms);
+ void gfxSleepMicroseconds(delaytime_t ms);
+ void gfxYield(void);
+
+ // System Locking
+ void gfxSystemLock(void);
+ void gfxSystemUnlock(void);
+
+ // Mutexes
+ void gfxMutexInit(gfxMutex *pmutex);
+ #define gfxMutexDestroy(pmutex)
+ void gfxMutexEnter(gfxMutex *pmutex);
+ void gfxMutexExit(gfxMutex *pmutex);
+
+ // Semaphores
+ void gfxSemInit(gfxSem *psem, semcount_t val, semcount_t limit);
+ #define gfxSemDestroy(psem)
+ bool_t gfxSemWait(gfxSem *psem, delaytime_t ms);
+ bool_t gfxSemWaitI(gfxSem *psem);
+ void gfxSemSignal(gfxSem *psem);
+ void gfxSemSignalI(gfxSem *psem);
+
+ // Deprecated Semaphore functions (they still work here)
+ #define gfxSemCounter(psem) ((psem)->cnt)
+ #define gfxSemCounterI(psem) ((psem)->cnt)
+
+ // Threads
+ gfxThreadHandle gfxThreadCreate(void *stackarea, size_t stacksz, threadpriority_t prio, DECLARE_THREAD_FUNCTION((*fn),p), void *param);
+ #define gfxThreadClose(thread)
+ threadreturn_t gfxThreadWait(gfxThreadHandle thread);
+ gfxThreadHandle gfxThreadMe(void);
+
+ /** The following is not part of the public ugfx API has some operating systems
+ * simply do not provide this capability.
+ * For RAW32 we need it anyway so we might as well declare it here.
+ */
+ void gfxThreadExit(threadreturn_t ret);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* GOS_NEED_X_THREADS */
+#endif /* _GOS_X_THREADS_H */