Fix Callback_process() being called from a callback called from
Callback_process() git-svn-id: svn://svn.code.sf.net/p/sc2/code/trunk@2546 8092fc87-c524-0410-9efc-e669fe64eaf9
This commit is contained in:
@@ -16,11 +16,12 @@
|
|||||||
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#include <sys/types.h>
|
|
||||||
//#include <stdbool.h>
|
|
||||||
#include "types.h"
|
|
||||||
#include <stdlib.h>
|
|
||||||
#include "port.h"
|
#include "port.h"
|
||||||
|
#include "types.h"
|
||||||
|
|
||||||
|
#include <assert.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <sys/types.h>
|
||||||
|
|
||||||
typedef struct CallbackLink CallbackLink;
|
typedef struct CallbackLink CallbackLink;
|
||||||
|
|
||||||
@@ -34,9 +35,8 @@ struct CallbackLink {
|
|||||||
};
|
};
|
||||||
|
|
||||||
static CallbackLink *callbacks;
|
static CallbackLink *callbacks;
|
||||||
static CallbackLink *oldCallbacks;
|
|
||||||
// callback list currently being processed
|
|
||||||
static CallbackLink **callbacksEnd;
|
static CallbackLink **callbacksEnd;
|
||||||
|
static CallbackLink *const *callbacksProcessEnd;
|
||||||
|
|
||||||
static inline void
|
static inline void
|
||||||
CallbackList_lock(void) {
|
CallbackList_lock(void) {
|
||||||
@@ -61,6 +61,7 @@ void
|
|||||||
Callback_init(void) {
|
Callback_init(void) {
|
||||||
callbacks = NULL;
|
callbacks = NULL;
|
||||||
callbacksEnd = &callbacks;
|
callbacksEnd = &callbacks;
|
||||||
|
callbacksProcessEnd = &callbacks;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Callbacks are guaranteed to be called in the order that they are queued.
|
// Callbacks are guaranteed to be called in the order that they are queued.
|
||||||
@@ -79,12 +80,6 @@ Callback_add(CallbackFunction callback, CallbackArg arg) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
// Pre: CallbackList is locked.
|
|
||||||
static void
|
|
||||||
CallbackLink_unlink(CallbackLink **linkPtr) {
|
|
||||||
*linkPtr = (*linkPtr)->next;
|
|
||||||
}
|
|
||||||
|
|
||||||
static void
|
static void
|
||||||
CallbackLink_delete(CallbackLink *link) {
|
CallbackLink_delete(CallbackLink *link) {
|
||||||
free(link);
|
free(link);
|
||||||
@@ -116,10 +111,15 @@ Callback_removeCallback(CallbackID id) {
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
CallbackLink_unlink(linkPtr);
|
if (callbacksEnd == &(*linkPtr)->next)
|
||||||
CallbackLink_delete(link);
|
callbacksEnd = linkPtr;
|
||||||
|
if (callbacksProcessEnd == &(*linkPtr)->next)
|
||||||
|
callbacksProcessEnd = linkPtr;
|
||||||
|
*linkPtr = (*linkPtr)->next;
|
||||||
|
|
||||||
CallbackList_unlock();
|
CallbackList_unlock();
|
||||||
|
|
||||||
|
CallbackLink_delete(link);
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -131,7 +131,7 @@ CallbackLink_doCallback(CallbackLink *link) {
|
|||||||
// Call all queued callbacks currently in the queue. Callbacks queued
|
// Call all queued callbacks currently in the queue. Callbacks queued
|
||||||
// from inside the called functions will not be processed until the next
|
// from inside the called functions will not be processed until the next
|
||||||
// call of Callback_process().
|
// call of Callback_process().
|
||||||
// It is not allowed to remove callbacks from inside the called functions.
|
// It is allowed to remove callbacks from inside the called functions.
|
||||||
// NB: Callback_process() must never be called from more than one thread
|
// NB: Callback_process() must never be called from more than one thread
|
||||||
// at the same time. It's the only sensible way to ensure that the
|
// at the same time. It's the only sensible way to ensure that the
|
||||||
// callbacks are called in the order in which they were queued.
|
// callbacks are called in the order in which they were queued.
|
||||||
@@ -141,19 +141,29 @@ void
|
|||||||
Callback_process(void) {
|
Callback_process(void) {
|
||||||
CallbackLink *link;
|
CallbackLink *link;
|
||||||
|
|
||||||
// Create a new queue so that the old queue can be processed
|
// We set 'callbacksProcessEnd' to callbacksEnd. Callbacks added
|
||||||
// at once, without additional locking.
|
// from inside a callback function will be placed after
|
||||||
|
// callbacksProcessEnd, and will hence not be processed this
|
||||||
|
// call of Callback_process().
|
||||||
CallbackList_lock();
|
CallbackList_lock();
|
||||||
oldCallbacks = callbacks;
|
callbacksProcessEnd = callbacksEnd;
|
||||||
callbacks = NULL;
|
|
||||||
callbacksEnd = &callbacks;
|
|
||||||
CallbackList_unlock();
|
CallbackList_unlock();
|
||||||
|
|
||||||
for (;;) {
|
for (;;) {
|
||||||
link = oldCallbacks;
|
CallbackList_lock();
|
||||||
if (link == NULL)
|
if (callbacksProcessEnd == &callbacks) {
|
||||||
|
CallbackList_unlock();
|
||||||
break;
|
break;
|
||||||
oldCallbacks = link->next;
|
}
|
||||||
|
assert(callbacks != NULL);
|
||||||
|
// If callbacks == NULL, then callbacksProcessEnd == &callbacks
|
||||||
|
link = callbacks;
|
||||||
|
callbacks = link->next;
|
||||||
|
if (callbacksEnd == &link->next)
|
||||||
|
callbacksEnd = &callbacks;
|
||||||
|
if (callbacksProcessEnd == &link->next)
|
||||||
|
callbacksProcessEnd = &callbacks;
|
||||||
|
CallbackList_unlock();
|
||||||
|
|
||||||
CallbackLink_doCallback(link);
|
CallbackLink_doCallback(link);
|
||||||
CallbackLink_delete(link);
|
CallbackLink_delete(link);
|
||||||
|
|||||||
Reference in New Issue
Block a user