From: <ebo...@us...> - 2002-09-08 16:42:52
|
Update of /cvsroot/alleg/allegro/src/win In directory usw-pr-cvs1:/tmp/cvs-serv5551/src/win Modified Files: winput.c wwnd.c Log Message: Fixed a race condition when registering input events Index: winput.c =================================================================== RCS file: /cvsroot/alleg/allegro/src/win/winput.c,v retrieving revision 1.1 retrieving revision 1.2 diff -u -d -r1.1 -r1.2 --- winput.c 27 May 2002 14:21:32 -0000 1.1 +++ winput.c 8 Sep 2002 16:42:48 -0000 1.2 @@ -29,19 +29,26 @@ #endif -#define MAX_EVENTS 4 +#define MAX_EVENTS 8 +/* input thread event queue */ int input_events; -HANDLE input_event_id[MAX_EVENTS]; /* event #0 is reserved */ +HANDLE input_event_id[MAX_EVENTS]; void (*input_event_handler[MAX_EVENTS])(void); +/* pending event waiting for being processed */ +static HANDLE pending_event_id; +static void (*pending_event_handler)(void); + +/* internal input thread management */ +static HANDLE ack_event = NULL; +static int reserved_events = 0; static int input_need_thread = FALSE; static HANDLE input_thread = NULL; -static int input_thread_suicide = FALSE; -/* input_thread_proc: +/* input_thread_proc: [input thread] * Thread function that handles the input when there is * no dedicated window thread because the library has * been attached to an external window. @@ -56,17 +63,10 @@ /* event loop */ while (TRUE) { result = WaitForMultipleObjects(input_events, input_event_id, FALSE, INFINITE); - if (result == WAIT_OBJECT_0) { - /* we were instructed to unblock, make sure we can block again */ - _enter_critical(); - _exit_critical(); - if (input_thread_suicide) - return; - } - else if ((result > WAIT_OBJECT_0) && (result < WAIT_OBJECT_0 + input_events)) { - /* one of the registered events is in signaled state */ + if (result == WAIT_OBJECT_0 + 2) + break; /* thread suicide */ + else if ((result >= WAIT_OBJECT_0) && (result < WAIT_OBJECT_0 + input_events)) (*input_event_handler[result - WAIT_OBJECT_0])(); - } } _TRACE("input thread exits\n"); @@ -75,105 +75,148 @@ -/* input_register_event: - * Adds an event to the input thread event queue. +/* register_pending_event: [input thread] + * Registers effectively the pending event. */ -int input_register_event(HANDLE event_id, void (*event_handler)(void)) +static void register_pending_event(void) { - if (input_events == MAX_EVENTS) - return -1; + /* add the pending event to the queue */ + input_event_id[input_events] = pending_event_id; + input_event_handler[input_events] = pending_event_handler; - _enter_critical(); + /* adjust the size of the queue */ + input_events++; - /* unblock the input thread if any */ - if (!input_need_thread || input_thread) - SetEvent(input_event_id[0]); + /* acknowledge the registration */ + SetEvent(ack_event); +} - /* effectively add */ - input_event_id[input_events] = event_id; - input_event_handler[input_events] = event_handler; - /* adjust the size of the queue */ - input_events++; - /* create input thread if none */ - if (input_need_thread && !input_thread) { - input_thread = (HANDLE) _beginthread(input_thread_proc, 0, NULL); - input_thread_suicide = FALSE; +/* unregister_pending_event: [input thread] + * Unregisters effectively the pending event. + */ +static void unregister_pending_event(void) +{ + int i, found = -1; + + /* look for the pending event in the event queue */ + for (i=reserved_events; i<input_events; i++) { + if (input_event_id[i] == pending_event_id) { + found = i; + break; + } } - _exit_critical(); + if (found >= 0) { + /* shift the queue to the left */ + for (i=found; i<input_events-1; i++) { + input_event_id[i] = input_event_id[i+1]; + input_event_handler[i] = input_event_handler[i+1]; + } - _TRACE("1 input event registered (total = %d)\n", input_events-1); - return 0; + /* adjust the size of the queue */ + input_events--; + } + + /* acknowledge the unregistration */ + SetEvent(ack_event); } -/* input_unregister_event: - * Removes an event from the input thread event queue. +/* input_register_event: [primary thread] + * Adds an event to the input thread event queue. */ -void input_unregister_event(HANDLE event_id) +int input_register_event(HANDLE event_id, void (*event_handler)(void)) { - int i, base; - - /* look for the requested event */ - for (i=1; i<input_events; i++) /* event #0 is reserved */ - if (input_event_id[i] == event_id) { - base = i; - goto Found; - } + if (input_events == MAX_EVENTS) + return -1; - return; + /* record the event */ + pending_event_id = event_id; + pending_event_handler = event_handler; - Found: - _enter_critical(); + /* create the input thread if none */ + if (input_need_thread && !input_thread) + input_thread = (HANDLE) _beginthread(input_thread_proc, 0, NULL); - /* unblock the input thread */ + /* ask the input thread to register the pending event */ SetEvent(input_event_id[0]); - /* shift the queue to the left if needed */ - for (i=base; i<input_events-1; i++) { - input_event_id[i] = input_event_id[i+1]; - input_event_handler[i] = input_event_handler[i+1]; - } + /* wait for the input thread to acknowledge */ + WaitForSingleObject(ack_event, INFINITE); - /* adjust the size of the queue */ - input_events--; + _TRACE("1 input event registered (total = %d)\n", input_events-reserved_events); + return 0; +} - /* kill input thread if no more event */ - if ((input_events == 1) && input_thread) { - input_thread_suicide = TRUE; + + +/* input_unregister_event: [primary thread] + * Removes an event from the input thread event queue. + */ +void input_unregister_event(HANDLE event_id) +{ + /* record the event */ + pending_event_id = event_id; + + /* ask the input thread to unregister the pending event */ + SetEvent(input_event_id[1]); + + /* wait for the input thread to acknowledge */ + WaitForSingleObject(ack_event, INFINITE); + + /* kill the input thread if no more event */ + if (input_need_thread && (input_events == reserved_events)) { + SetEvent(input_event_id[2]); /* thread suicide */ input_thread = NULL; } - _exit_critical(); - - _TRACE("1 input event unregistered (total = %d)\n", input_events-1); + _TRACE("1 input event unregistered (total = %d)\n", input_events-reserved_events); } -/* input_init: +/* input_init: [primary thread] * Initializes the module. */ void input_init(int need_thread) { - input_need_thread = need_thread; - - /* event #0 is reserved by the module */ input_event_id[0] = CreateEvent(NULL, FALSE, FALSE, NULL); - input_event_handler[0] = NULL; - input_events = 1; + input_event_handler[0] = register_pending_event; + input_event_id[1] = CreateEvent(NULL, FALSE, FALSE, NULL); + input_event_handler[1] = unregister_pending_event; + + if (need_thread) { + input_need_thread = TRUE; + input_event_id[2] = CreateEvent(NULL, FALSE, FALSE, NULL); + reserved_events = 3; + } + else { + input_need_thread = FALSE; + reserved_events = 2; + } + + input_events = reserved_events; + + ack_event = CreateEvent(NULL, FALSE, FALSE, NULL); } -/* input_exit: +/* input_exit: [primary thread] * Shuts down the module. */ void input_exit(void) { - CloseHandle(input_event_id[0]); + int i; + + for (i=0; i<reserved_events; i++) + CloseHandle(input_event_id[i]); + + input_events = 0; + + CloseHandle(ack_event); } Index: wwnd.c =================================================================== RCS file: /cvsroot/alleg/allegro/src/win/wwnd.c,v retrieving revision 1.55 retrieving revision 1.56 diff -u -d -r1.55 -r1.56 --- wwnd.c 22 Aug 2002 13:35:03 -0000 1.55 +++ wwnd.c 8 Sep 2002 16:42:48 -0000 1.56 @@ -508,12 +508,7 @@ /* message loop */ while (TRUE) { result = MsgWaitForMultipleObjects(input_events, input_event_id, FALSE, INFINITE, QS_ALLINPUT); - if (result == WAIT_OBJECT_0) { - /* we were instructed to unblock, make sure we can block again */ - _enter_critical(); - _exit_critical(); - } - else if ((result > WAIT_OBJECT_0) && (result < WAIT_OBJECT_0 + input_events)) { + if ((result >= WAIT_OBJECT_0) && (result < WAIT_OBJECT_0 + input_events)) { /* one of the registered events is in signaled state */ (*input_event_handler[result - WAIT_OBJECT_0])(); } |