aboutsummaryrefslogtreecommitdiffstats
path: root/src/gos/gos_arduino.c
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 /src/gos/gos_arduino.c
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.
Diffstat (limited to 'src/gos/gos_arduino.c')
-rw-r--r--src/gos/gos_arduino.c492
1 files changed, 13 insertions, 479 deletions
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 */