Fixes to GEVENT
This commit is contained in:
parent
da2735ab67
commit
e0eacb846c
@ -23,6 +23,7 @@ FEATURE: Added high-level functions to modify image color palettes
|
|||||||
FIX: Improving gdispDrawThickLine()
|
FIX: Improving gdispDrawThickLine()
|
||||||
FEATURE: Added gdispAddFont() for adding a dynamic font to the permanent font list
|
FEATURE: Added gdispAddFont() for adding a dynamic font to the permanent font list
|
||||||
FEATURE: Added gmiscHittestPoly() for checking whether a point is inside of a polygon
|
FEATURE: Added gmiscHittestPoly() for checking whether a point is inside of a polygon
|
||||||
|
FIX: Fixed strange multi-thread issues in GEVENT
|
||||||
|
|
||||||
|
|
||||||
*** Release 2.6 ***
|
*** Release 2.6 ***
|
||||||
|
@ -16,10 +16,8 @@
|
|||||||
#endif
|
#endif
|
||||||
|
|
||||||
/* Flags in the listener structure */
|
/* Flags in the listener structure */
|
||||||
#define GLISTENER_EVENTBUSY 0x0001 // The event buffer is busy
|
#define GLISTENER_WITHLISTENER 0x0001 // The listener is current using the buffer
|
||||||
#define GLISTENER_WAITING 0x0002 // The listener is waiting for a signal
|
#define GLISTENER_WITHSOURCE 0x0002 // The source is currently using the buffer
|
||||||
#define GLISTENER_WITHSOURCE 0x0004 // The listener is being looked at by a source for a possible event
|
|
||||||
#define GLISTENER_PENDING 0x0008 // There is an event waiting ready to go without a current listener
|
|
||||||
|
|
||||||
/* This mutex protects access to our tables */
|
/* This mutex protects access to our tables */
|
||||||
static gfxMutex geventMutex;
|
static gfxMutex geventMutex;
|
||||||
@ -30,11 +28,10 @@ static GSourceListener Assignments[GEVENT_MAX_SOURCE_LISTENERS];
|
|||||||
/* Send an exit event if possible. */
|
/* Send an exit event if possible. */
|
||||||
/* We already have the geventMutex */
|
/* We already have the geventMutex */
|
||||||
static void doExitEvent(GListener *pl) {
|
static void doExitEvent(GListener *pl) {
|
||||||
// Don't do the exit if someone else currently has the event lock
|
// Don't do the exit if someone else currently is using the buffer
|
||||||
if ((pl->flags & (GLISTENER_WAITING|GLISTENER_EVENTBUSY)) == GLISTENER_WAITING) {
|
if (!(pl->flags & GLISTENER_WITHLISTENER)) {
|
||||||
pl->flags |= GLISTENER_EVENTBUSY; // Event buffer is in use
|
|
||||||
pl->event.type = GEVENT_EXIT; // Set up the EXIT event
|
pl->event.type = GEVENT_EXIT; // Set up the EXIT event
|
||||||
pl->flags &= ~GLISTENER_WAITING; // Wake up the listener (with data)
|
pl->flags = GLISTENER_WITHLISTENER; // Event buffer is now in use by the listener
|
||||||
gfxSemSignal(&pl->waitqueue);
|
gfxSemSignal(&pl->waitqueue);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -119,38 +116,36 @@ void geventDetachSource(GListener *pl, GSourceHandle gsh) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
GEvent *geventEventWait(GListener *pl, delaytime_t timeout) {
|
GEvent *geventEventWait(GListener *pl, delaytime_t timeout) {
|
||||||
gfxMutexEnter(&geventMutex);
|
/* NOTE:
|
||||||
// Don't allow waiting if we are on callbacks or if there is already a thread waiting
|
We no longer try to protect against two threads trying to listen on the
|
||||||
if (pl->callback || (pl->flags & GLISTENER_WAITING)) {
|
one listener. This was never allowed, it makes little sense to try to do so,
|
||||||
gfxMutexExit(&geventMutex);
|
and the testing caused strange multi-thread windows of opportunity.
|
||||||
|
|
||||||
|
In practice it is probably safer than it used to be - the only potential
|
||||||
|
issue is that the buffer may be prematurely marked as not in use by the listener.
|
||||||
|
If the calling code can guarantee that the event buffer is free when either thread
|
||||||
|
calls the event wait - it is now safe for them to do so.
|
||||||
|
ie. it is the implicit geventEventComplete() that is the only thing that now raises
|
||||||
|
possible multi-thread issues.
|
||||||
|
*/
|
||||||
|
|
||||||
|
// Don't allow waiting if we are on callbacks
|
||||||
|
if (pl->callback)
|
||||||
return 0;
|
return 0;
|
||||||
}
|
|
||||||
|
// Event buffer is not in use by the listener - this is an implicit geventEventComplete() call
|
||||||
|
pl->flags &= ~GLISTENER_WITHLISTENER;
|
||||||
|
|
||||||
// Check to see if there is a pending event ready for us
|
// Wait for an event
|
||||||
if ((pl->flags & GLISTENER_PENDING)) {
|
if (!gfxSemWait(&pl->waitqueue, timeout))
|
||||||
pl->flags &= ~GLISTENER_PENDING; // We have now got this
|
return 0; // Timeout
|
||||||
pl->flags |= GLISTENER_EVENTBUSY; // Event buffer is definitely busy
|
|
||||||
gfxMutexExit(&geventMutex);
|
|
||||||
return &pl->event;
|
|
||||||
}
|
|
||||||
|
|
||||||
// No - wait for one.
|
return &pl->event;
|
||||||
pl->flags &= ~GLISTENER_EVENTBUSY; // Event buffer is definitely not busy
|
|
||||||
pl->flags |= GLISTENER_WAITING; // We will now be waiting on the thread
|
|
||||||
gfxMutexExit(&geventMutex);
|
|
||||||
if (gfxSemWait(&pl->waitqueue, timeout))
|
|
||||||
return &pl->event;
|
|
||||||
|
|
||||||
// Timeout - clear the waiting flag.
|
|
||||||
// We know this is safe as any other thread will still think there is someone waiting.
|
|
||||||
gfxMutexEnter(&geventMutex);
|
|
||||||
pl->flags &= ~GLISTENER_WAITING;
|
|
||||||
gfxMutexExit(&geventMutex);
|
|
||||||
return 0;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void geventEventComplete(GListener *pl) {
|
void geventEventComplete(GListener *pl) {
|
||||||
pl->flags &= ~GLISTENER_EVENTBUSY;
|
// The listener is done with the buffer
|
||||||
|
pl->flags &= ~GLISTENER_WITHLISTENER;
|
||||||
}
|
}
|
||||||
|
|
||||||
void geventRegisterCallback(GListener *pl, GEventCallbackFn fn, void *param) {
|
void geventRegisterCallback(GListener *pl, GEventCallbackFn fn, void *param) {
|
||||||
@ -160,7 +155,7 @@ void geventRegisterCallback(GListener *pl, GEventCallbackFn fn, void *param) {
|
|||||||
pl->param = param; // Set the param
|
pl->param = param; // Set the param
|
||||||
pl->callback = fn; // Set the callback function
|
pl->callback = fn; // Set the callback function
|
||||||
if (fn)
|
if (fn)
|
||||||
pl->flags &= ~GLISTENER_EVENTBUSY; // The event buffer is immediately available
|
pl->flags &= ~GLISTENER_WITHLISTENER; // The event buffer is immediately available
|
||||||
gfxMutexExit(&geventMutex);
|
gfxMutexExit(&geventMutex);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -176,7 +171,7 @@ GSourceListener *geventGetSourceListener(GSourceHandle gsh, GSourceListener *las
|
|||||||
|
|
||||||
// Unlock the last listener event buffer if it wasn't used.
|
// Unlock the last listener event buffer if it wasn't used.
|
||||||
if (lastlr && lastlr->pListener && (lastlr->pListener->flags & GLISTENER_WITHSOURCE))
|
if (lastlr && lastlr->pListener && (lastlr->pListener->flags & GLISTENER_WITHSOURCE))
|
||||||
lastlr->pListener->flags &= ~(GLISTENER_WITHSOURCE|GLISTENER_EVENTBUSY);
|
lastlr->pListener->flags &= ~GLISTENER_WITHSOURCE;
|
||||||
|
|
||||||
// Loop through the table looking for attachments to this source
|
// Loop through the table looking for attachments to this source
|
||||||
for(psl = lastlr ? (lastlr+1) : Assignments; psl < Assignments+GEVENT_MAX_SOURCE_LISTENERS; psl++) {
|
for(psl = lastlr ? (lastlr+1) : Assignments; psl < Assignments+GEVENT_MAX_SOURCE_LISTENERS; psl++) {
|
||||||
@ -191,14 +186,13 @@ GSourceListener *geventGetSourceListener(GSourceHandle gsh, GSourceListener *las
|
|||||||
|
|
||||||
GEvent *geventGetEventBuffer(GSourceListener *psl) {
|
GEvent *geventGetEventBuffer(GSourceListener *psl) {
|
||||||
gfxMutexEnter(&geventMutex);
|
gfxMutexEnter(&geventMutex);
|
||||||
if ((psl->pListener->flags & GLISTENER_EVENTBUSY)) {
|
if ((psl->pListener->flags & (GLISTENER_WITHLISTENER|GLISTENER_WITHSOURCE))) {
|
||||||
// Oops - event buffer is still in use
|
|
||||||
gfxMutexExit(&geventMutex);
|
gfxMutexExit(&geventMutex);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Allocate the event buffer
|
// Allocate the event buffer to the source
|
||||||
psl->pListener->flags |= (GLISTENER_WITHSOURCE|GLISTENER_EVENTBUSY);
|
psl->pListener->flags |= GLISTENER_WITHSOURCE;
|
||||||
gfxMutexExit(&geventMutex);
|
gfxMutexExit(&geventMutex);
|
||||||
return &psl->pListener->event;
|
return &psl->pListener->event;
|
||||||
}
|
}
|
||||||
@ -209,7 +203,7 @@ void geventSendEvent(GSourceListener *psl) {
|
|||||||
|
|
||||||
// Mark it back as free and as sent. This is early to be marking as free but it protects
|
// Mark it back as free and as sent. This is early to be marking as free but it protects
|
||||||
// if the callback alters the listener in any way
|
// if the callback alters the listener in any way
|
||||||
psl->pListener->flags &= ~(GLISTENER_WITHSOURCE|GLISTENER_EVENTBUSY|GLISTENER_PENDING);
|
psl->pListener->flags = 0;
|
||||||
gfxMutexExit(&geventMutex);
|
gfxMutexExit(&geventMutex);
|
||||||
|
|
||||||
// Do the callback
|
// Do the callback
|
||||||
@ -217,14 +211,8 @@ void geventSendEvent(GSourceListener *psl) {
|
|||||||
|
|
||||||
} else {
|
} else {
|
||||||
// Wake up the listener
|
// Wake up the listener
|
||||||
psl->pListener->flags &= ~GLISTENER_WITHSOURCE;
|
psl->pListener->flags = GLISTENER_WITHLISTENER;
|
||||||
if ((psl->pListener->flags & GLISTENER_WAITING)) {
|
gfxSemSignal(&psl->pListener->waitqueue);
|
||||||
psl->pListener->flags &= ~(GLISTENER_WAITING|GLISTENER_PENDING);
|
|
||||||
gfxSemSignal(&psl->pListener->waitqueue);
|
|
||||||
} else
|
|
||||||
psl->pListener->flags |= GLISTENER_PENDING;
|
|
||||||
|
|
||||||
// The listener thread will free the event buffer when ready
|
|
||||||
gfxMutexExit(&geventMutex);
|
gfxMutexExit(&geventMutex);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -146,7 +146,6 @@ void geventDetachSource(GListener *pl, GSourceHandle gsh);
|
|||||||
* @brief Wait for an event on a listener from an assigned source.
|
* @brief Wait for an event on a listener from an assigned source.
|
||||||
* @details The type of the event should be checked (pevent->type) and then pevent should
|
* @details The type of the event should be checked (pevent->type) and then pevent should
|
||||||
* be typecast to the actual event type if it needs to be processed.
|
* be typecast to the actual event type if it needs to be processed.
|
||||||
* timeout specifies the time to wait in system ticks.
|
|
||||||
* TIME_INFINITE means no timeout - wait forever for an event.
|
* TIME_INFINITE means no timeout - wait forever for an event.
|
||||||
* TIME_IMMEDIATE means return immediately
|
* TIME_IMMEDIATE means return immediately
|
||||||
* @note The returned GEvent is released when this routine is called again
|
* @note The returned GEvent is released when this routine is called again
|
||||||
@ -154,9 +153,11 @@ void geventDetachSource(GListener *pl, GSourceHandle gsh);
|
|||||||
* allows the GEvent object to be reused earlier which can reduce missed events. The GEvent
|
* allows the GEvent object to be reused earlier which can reduce missed events. The GEvent
|
||||||
* object MUST NOT be used after this function is called (and is blocked waiting for the next
|
* object MUST NOT be used after this function is called (and is blocked waiting for the next
|
||||||
* event) or after geventEventComplete() is called.
|
* event) or after geventEventComplete() is called.
|
||||||
|
* The one listener object should not be waited on using more than one thread simultanously
|
||||||
|
* because of the implicit geventEventComplete() that occurs when this function is called.
|
||||||
*
|
*
|
||||||
* @param[in] pl The listener
|
* @param[in] pl The listener
|
||||||
* @param[in] timeout The timeout
|
* @param[in] timeout The timeout in milliseconds
|
||||||
*
|
*
|
||||||
* @return NULL on timeout
|
* @return NULL on timeout
|
||||||
*/
|
*/
|
||||||
@ -216,7 +217,7 @@ GSourceListener *geventGetSourceListener(GSourceHandle gsh, GSourceListener *las
|
|||||||
*
|
*
|
||||||
* @param[in] psl The source listener
|
* @param[in] psl The source listener
|
||||||
*
|
*
|
||||||
* @return NULL if the listener is not currently listening.
|
* @return NULL if the event buffer for this listener is currently in use.
|
||||||
*/
|
*/
|
||||||
GEvent *geventGetEventBuffer(GSourceListener *psl);
|
GEvent *geventGetEventBuffer(GSourceListener *psl);
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user