From e3545c55bf706984af5962221f95881d868c5407 Mon Sep 17 00:00:00 2001 From: inmarket Date: Mon, 29 Sep 2014 15:45:44 +1000 Subject: [PATCH 1/3] Bug fixes for the linux GOS layer. Also add POSIX semaphore implementation. --- src/gos/gfx_linux.c | 173 ++++++++++++++++++++++++++------------------ src/gos/gfx_linux.h | 31 ++++++-- 2 files changed, 128 insertions(+), 76 deletions(-) diff --git a/src/gos/gfx_linux.c b/src/gos/gfx_linux.c index fc716ec9..e6fbe26c 100644 --- a/src/gos/gfx_linux.c +++ b/src/gos/gfx_linux.c @@ -14,8 +14,6 @@ #include #include -#include -#include #include #if USE_SCHED_NOT_PTHREAD_YIELD #include @@ -70,16 +68,16 @@ void gfxSleepMilliseconds(delaytime_t ms) { default: ts.tv_sec = ms / 1000; - ts.tv_nsec = (ms % 1000) * 1000; + ts.tv_nsec = (ms % 1000) * 1000000; nanosleep(&ts, 0); return; } } -void gfxSleepMicroseconds(delaytime_t ms) { +void gfxSleepMicroseconds(delaytime_t us) { struct timespec ts; - switch(ms) { + switch(us) { case TIME_IMMEDIATE: linuxyield(); return; @@ -90,8 +88,8 @@ void gfxSleepMicroseconds(delaytime_t ms) { return; default: - ts.tv_sec = ms / 1000000; - ts.tv_nsec = ms % 1000000; + ts.tv_sec = us / 1000000; + ts.tv_nsec = (us % 1000000) * 1000; nanosleep(&ts, 0); return; } @@ -101,8 +99,7 @@ systemticks_t gfxSystemTicks(void) { struct timespec ts; clock_gettime(CLOCK_MONOTONIC, &ts); - - return ts.tv_sec * 1000UL + ts.tv_nsec / 1000UL; + return ts.tv_sec * 1000 + ts.tv_nsec / 1000000; } gfxThreadHandle gfxThreadCreate(void *stackarea, size_t stacksz, threadpriority_t prio, DECLARE_THREAD_FUNCTION((*fn),p), void *param) { @@ -133,81 +130,119 @@ threadreturn_t gfxThreadWait(gfxThreadHandle thread) { return retval; } -void gfxSemInit(gfxSem *pSem, semcount_t val, semcount_t limit) { - pthread_mutex_init(&pSem->mtx, 0); - pthread_cond_init(&pSem->cond, 0); - pthread_mutex_lock(&pSem->mtx); - pSem->cnt = val; - pSem->max = limit; - pthread_mutex_unlock(&pSem->mtx); -} - -void gfxSemDestroy(gfxSem *pSem) { - pthread_mutex_destroy(&pSem->mtx); - pthread_cond_destroy(&pSem->cond); -} - -bool_t gfxSemWait(gfxSem *pSem, delaytime_t ms) { - pthread_mutex_lock(&pSem->mtx); - - switch (ms) { +#if GFX_USE_POSIX_SEMAPHORES + void gfxSemInit(gfxSem *pSem, semcount_t val, semcount_t limit) { + pSem->max = limit; + sem_init(&pSem->sem, 0, val); + } + void gfxSemDestroy(gfxSem *pSem) { + sem_destroy(&pSem->sem); + } + bool_t gfxSemWait(gfxSem *pSem, delaytime_t ms) { + switch (ms) { case TIME_INFINITE: - while (!pSem->cnt) - pthread_cond_wait(&pSem->cond, &pSem->mtx); - break; + return sem_wait(&pSem->sem) ? FALSE : TRUE; case TIME_IMMEDIATE: - if (!pSem->cnt) { - pthread_mutex_unlock(&pSem->mtx); - return FALSE; - } - break; + return sem_trywait(&pSem->sem) ? FALSE : TRUE; default: { - struct timeval now; struct timespec tm; - gettimeofday(&now, 0); - tm.tv_sec = now.tv_sec + ms / 1000; - tm.tv_nsec = (now.tv_usec + ms % 1000) * 1000; - while (!pSem->cnt) { - if (pthread_cond_timedwait(&pSem->cond, &pSem->mtx, &tm) == ETIMEDOUT) { - pthread_mutex_unlock(&pSem->mtx); - return FALSE; + clock_gettime(CLOCK_REALTIME, &tm); + tm.tv_sec += ms / 1000; + tm.tv_nsec += (ms % 1000) * 1000000; + return sem_timedwait(&pSem->sem, &tm) ? FALSE : TRUE; + } + } + } + void gfxSemSignal(gfxSem *pSem) { + if (gfxSemCounter(pSem) < pSem->max) + sem_post(&pSem->sem); + } + semcount_t gfxSemCounter(gfxSem *pSem) { + int res; + + res = 0; + sem_getvalue(&pSem->sem, &res); + return res; + } +#else + void gfxSemInit(gfxSem *pSem, semcount_t val, semcount_t limit) { + pthread_mutex_init(&pSem->mtx, 0); + pthread_cond_init(&pSem->cond, 0); + pthread_mutex_lock(&pSem->mtx); + pSem->cnt = val; + pSem->max = limit; + pthread_mutex_unlock(&pSem->mtx); + } + void gfxSemDestroy(gfxSem *pSem) { + pthread_mutex_destroy(&pSem->mtx); + pthread_cond_destroy(&pSem->cond); + } + bool_t gfxSemWait(gfxSem *pSem, delaytime_t ms) { + pthread_mutex_lock(&pSem->mtx); + + switch (ms) { + case TIME_INFINITE: + while (!pSem->cnt) + pthread_cond_wait(&pSem->cond, &pSem->mtx); + break; + + case TIME_IMMEDIATE: + if (!pSem->cnt) { + pthread_mutex_unlock(&pSem->mtx); + return FALSE; + } + break; + + default: + { + struct timespec tm; + + clock_gettime(CLOCK_REALTIME, &tm); + tm.tv_sec += ms / 1000; + tm.tv_nsec += (ms % 1000) * 1000000; + while (!pSem->cnt) { + // We used to test the return value for ETIMEDOUT. This doesn't + // work in some current pthread libraries which return -1 instead + // and set errno to ETIMEDOUT. So, we will return FALSE on any error + // including a ETIMEDOUT. + if (pthread_cond_timedwait(&pSem->cond, &pSem->mtx, &tm)) { + pthread_mutex_unlock(&pSem->mtx); + return FALSE; + } } } - } - break; + break; + } + + pSem->cnt--; + pthread_mutex_unlock(&pSem->mtx); + return TRUE; } + void gfxSemSignal(gfxSem *pSem) { + pthread_mutex_lock(&pSem->mtx); - pSem->cnt--; - pthread_mutex_unlock(&pSem->mtx); + if (pSem->cnt < pSem->max) { + pSem->cnt++; + pthread_cond_signal(&pSem->cond); + } - return TRUE; -} - -void gfxSemSignal(gfxSem *pSem) { - pthread_mutex_lock(&pSem->mtx); - - if (pSem->cnt < pSem->max) { - pSem->cnt++; - pthread_cond_signal(&pSem->cond); + pthread_mutex_unlock(&pSem->mtx); } + semcount_t gfxSemCounter(gfxSem *pSem) { + semcount_t res; - pthread_mutex_unlock(&pSem->mtx); -} + // The locking is really only required if obtaining the count is a divisible operation + // which it might be on a 8/16 bit processor with a 32 bit semaphore count. + pthread_mutex_lock(&pSem->mtx); + res = pSem->cnt; + pthread_mutex_unlock(&pSem->mtx); -semcount_t gfxSemCounter(gfxSem *pSem) { - semcount_t res; - - // The locking is really only required if obtaining the count is a divisible operation - // which it might be on a 8/16 bit processor with a 32 bit semaphore count. - pthread_mutex_lock(&pSem->mtx); - res = pSem->cnt; - pthread_mutex_unlock(&pSem->mtx); - - return res; -} + return res; + } +#endif // GFX_USE_POSIX_SEMAPHORES #endif /* GFX_USE_OS_LINUX */ diff --git a/src/gos/gfx_linux.h b/src/gos/gfx_linux.h index bd31184e..39cfbc85 100644 --- a/src/gos/gfx_linux.h +++ b/src/gos/gfx_linux.h @@ -10,11 +10,20 @@ #if GFX_USE_OS_LINUX +// We don't put this in the general sys_options.h as it is Linux specific. +#ifndef GFX_USE_POSIX_SEMAPHORES + #define GFX_USE_POSIX_SEMAPHORES TRUE +#endif + #include #include #include #include +#if GFX_USE_POSIX_SEMAPHORES + #include +#endif + /* Already defined int8_t, uint8_t, int16_t, uint16_t, int32_t, uint32_t, size_t */ typedef int8_t bool_t; @@ -42,7 +51,6 @@ typedef pthread_mutex_t gfxMutex; #define gfxMutexExit(pmtx) pthread_mutex_unlock(pmtx) #define gfxSemWaitI(psem) gfxSemWait(psem, TIME_IMMEDIATE) #define gfxSemSignalI(psem) gfxSemSignal(psem) -#define gfxSemCounterI(pSem) ((pSem)->cnt) #define TIME_IMMEDIATE 0 #define TIME_INFINITE ((delaytime_t)-1) @@ -51,12 +59,21 @@ typedef pthread_mutex_t gfxMutex; #define NORMAL_PRIORITY 0 #define HIGH_PRIORITY -10 -typedef struct gfxSem { - pthread_mutex_t mtx; - pthread_cond_t cond; - semcount_t cnt; - semcount_t max; -} gfxSem; +#if GFX_USE_POSIX_SEMAPHORES + typedef struct gfxSem { + sem_t sem; + semcount_t max; + } gfxSem; + #define gfxSemCounterI(psem) gfxSemCounter(psem) +#else + typedef struct gfxSem { + pthread_mutex_t mtx; + pthread_cond_t cond; + semcount_t cnt; + semcount_t max; + } gfxSem; + #define gfxSemCounterI(psem) ((psem)->cnt) +#endif /*===========================================================================*/ /* Function declarations. */ From 3abbf8e1b2bac9ca02ab22d00fad828e5ff54898 Mon Sep 17 00:00:00 2001 From: inmarket Date: Mon, 29 Sep 2014 15:46:08 +1000 Subject: [PATCH 2/3] Bug fixes for the OSX GOS layer --- src/gos/gfx_osx.c | 42 +++++++++++++++++------------------------- 1 file changed, 17 insertions(+), 25 deletions(-) diff --git a/src/gos/gfx_osx.c b/src/gos/gfx_osx.c index f2e58f77..f21b8a75 100644 --- a/src/gos/gfx_osx.c +++ b/src/gos/gfx_osx.c @@ -21,18 +21,6 @@ static gfxMutex SystemMutex; - -void get_ticks(mach_timespec_t *mts){ - clock_serv_t cclock; - //mach_timespec_t mts; - - host_get_clock_service(mach_host_self(), SYSTEM_CLOCK, &cclock); - clock_get_time(cclock, mts); - mach_port_deallocate(mach_task_self(), cclock); - - -} - void _gosInit(void) { /* No initialization of the operating system itself is needed */ @@ -66,35 +54,35 @@ void gfxSleepMilliseconds(delaytime_t ms) { case TIME_INFINITE: while(1) sleep(60); return; default: ts.tv_sec = ms / 1000; - ts.tv_nsec = (ms % 1000) * 1000; + ts.tv_nsec = (ms % 1000) * 1000000; nanosleep(&ts, 0); return; } } -void gfxSleepMicroseconds(delaytime_t ms) { +void gfxSleepMicroseconds(delaytime_t us) { struct timespec ts; - switch(ms) { + switch(us) { case TIME_IMMEDIATE: gfxYield(); return; case TIME_INFINITE: while(1) sleep(60); return; default: - ts.tv_sec = ms / 1000000; - ts.tv_nsec = ms % 1000000; + ts.tv_sec = us / 1000000; + ts.tv_nsec = (us % 1000000) * 1000; nanosleep(&ts, 0); return; } } systemticks_t gfxSystemTicks(void) { - //struct timespec ts; - //clock_gettime(CLOCK_MONOTONIC, &ts); + mach_timespec_t ts; + clock_serv_t cclock; - mach_timespec_t ts; - get_ticks(&ts); + host_get_clock_service(mach_host_self(), SYSTEM_CLOCK, &cclock); + clock_get_time(cclock, &ts); + mach_port_deallocate(mach_task_self(), cclock); - - return ts.tv_sec * 1000UL + ts.tv_nsec / 1000UL; + return ts.tv_sec * 1000UL + ts.tv_nsec / 1000000; } gfxThreadHandle gfxThreadCreate(void *stackarea, size_t stacksz, threadpriority_t prio, DECLARE_THREAD_FUNCTION((*fn),p), void *param) { @@ -157,9 +145,13 @@ bool_t gfxSemWait(gfxSem *pSem, delaytime_t ms) { gettimeofday(&now, 0); tm.tv_sec = now.tv_sec + ms / 1000; - tm.tv_nsec = (now.tv_usec + ms % 1000) * 1000; + tm.tv_nsec = now.tv_usec * 1000 + (ms % 1000) * 1000000; while (!pSem->cnt) { - if (pthread_cond_timedwait(&pSem->cond, &pSem->mtx, &tm) == ETIMEDOUT) { + // We used to test the return value for ETIMEDOUT. This doesn't + // work in some current pthread libraries which return -1 instead + // and set errno to ETIMEDOUT. So, we will return FALSE on any error + // including a ETIMEDOUT. + if (pthread_cond_timedwait(&pSem->cond, &pSem->mtx, &tm)) { pthread_mutex_unlock(&pSem->mtx); return FALSE; } From e2f3a68c3b9b97799ac446fa5c0bc8bfdf9d9012 Mon Sep 17 00:00:00 2001 From: inmarket Date: Mon, 29 Sep 2014 15:46:34 +1000 Subject: [PATCH 3/3] Progress bar optimisation. --- src/gwin/gwin_progressbar.c | 53 +++++++++++++++++-------------------- src/gwin/gwin_progressbar.h | 7 +++-- 2 files changed, 28 insertions(+), 32 deletions(-) diff --git a/src/gwin/gwin_progressbar.c b/src/gwin/gwin_progressbar.c index ef28e8dc..d5b8721a 100644 --- a/src/gwin/gwin_progressbar.c +++ b/src/gwin/gwin_progressbar.c @@ -79,13 +79,12 @@ GHandle gwinGProgressbarCreate(GDisplay *g, GProgressbarObject *gs, const GWidge gs->pos = 0; #if GWIN_PROGRESSBAR_AUTO - gs->delay = 0; gtimerInit(&gs->gt); #endif ResetDisplayPos(gs); gwinSetVisible((GHandle)gs, pInit->g.show); - + return (GHandle)gs; } @@ -183,39 +182,37 @@ void gwinProgressbarDecrement(GHandle gh) { static void _progressbarCallback(void *param) { #define gsw ((GProgressbarObject *)gh) GHandle gh = (GHandle)param; - + if (gh->vmt != (gwinVMT *)&progressbarVMT) return; - + gwinProgressbarIncrement(gh); - - if (gsw->pos < gsw->max) - gtimerStart(&(gsw->gt), _progressbarCallback, gh, FALSE, gsw->delay); - - #undef gsw - } - - void gwinProgressbarStart(GHandle gh, delaytime_t delay) { - #define gsw ((GProgressbarObject *)gh) - - if (gh->vmt != (gwinVMT *)&progressbarVMT) - return; - - gsw->delay = delay; - - gtimerStart(&(gsw->gt), _progressbarCallback, gh, FALSE, gsw->delay); - + + if (gsw->pos >= gsw->max) + gtimerStop(&gsw->gt); + #undef gsw } - - void gwinProgressbarStop(GHandle gh) { + + void gwinProgressbarStart(GHandle gh, delaytime_t delay) { #define gsw ((GProgressbarObject *)gh) - + if (gh->vmt != (gwinVMT *)&progressbarVMT) return; - - gtimerStop(&(gsw->gt)); - + + gtimerStart(&gsw->gt, _progressbarCallback, gh, TRUE, delay); + + #undef gsw + } + + void gwinProgressbarStop(GHandle gh) { + #define gsw ((GProgressbarObject *)gh) + + if (gh->vmt != (gwinVMT *)&progressbarVMT) + return; + + gtimerStop(&gsw->gt); + #undef gsw } #endif /* GWIN_PROGRESSBAR_AUTO */ @@ -226,7 +223,7 @@ void gwinProgressbarDecrement(GHandle gh) { void gwinProgressbarDraw_Std(GWidgetObject *gw, void *param) { #define gsw ((GProgressbarObject *)gw) - + const GColorSet * pcol; (void) param; diff --git a/src/gwin/gwin_progressbar.h b/src/gwin/gwin_progressbar.h index 49c11a98..dae9d40a 100644 --- a/src/gwin/gwin_progressbar.h +++ b/src/gwin/gwin_progressbar.h @@ -33,7 +33,6 @@ typedef struct GProgressbarObject { int pos; #if GWIN_PROGRESSBAR_AUTO GTimer gt; - delaytime_t delay; #endif } GProgressbarObject; @@ -59,7 +58,7 @@ extern "C" { * @note A progressbar does not take any GINPUT inputs. * * @api - */ + */ GHandle gwinGProgressbarCreate(GDisplay *g, GProgressbarObject *gb, const GWidgetInit *pInit); #define gwinProgressbarCreate(w, pInit) gwinGProgressbarCreate(GDISP, w, pInit) @@ -165,14 +164,14 @@ void gwinProgressbarDecrement(GHandle gh); * @api */ void gwinProgressbarStart(GHandle gh, delaytime_t delay); - + /** * @brief Stop the timer which is started by @p gwinProgressbarStart() * * @param[in] gh The window handle (must be a progressbar window) * * @api - */ + */ void gwinProgressbarStop(GHandle gh); #endif /* GWIN_PROGRESSBAR_AUTO */