From: Chris Hanson Date: Fri, 3 Nov 1995 01:22:21 +0000 (+0000) Subject: Fix timing bug in inter-thread communications. This bug occurs when X-Git-Tag: 20090517-FFI~5794 X-Git-Url: https://birchwood-abbey.net/git?a=commitdiff_plain;h=09297236c20ce9c0af7da5776f9744529a3e8d3b;p=mit-scheme.git Fix timing bug in inter-thread communications. This bug occurs when two threads read the same tqueue simultaneously, which violates the assumption that each tqueue is read by only one thread. This fix is a kludge that will be replaced later by a redesigned communications model. --- diff --git a/v7/src/microcode/os2msg.c b/v7/src/microcode/os2msg.c index 95dcdfa12..71e3b50ca 100644 --- a/v7/src/microcode/os2msg.c +++ b/v7/src/microcode/os2msg.c @@ -1,6 +1,6 @@ /* -*-C-*- -$Id: os2msg.c,v 1.9 1995/04/28 07:04:59 cph Exp $ +$Id: os2msg.c,v 1.10 1995/11/03 01:22:09 cph Exp $ Copyright (c) 1994-95 Massachusetts Institute of Technology @@ -481,20 +481,14 @@ subqueue_emptyp (qid_t qid) int OS2_tqueue_select (tqueue_t * tqueue, int blockp) { - while (1) + msg_t * message = (read_tqueue (tqueue, blockp)); + if ((TQUEUE_TYPE (tqueue)) == tqt_scm) { - msg_t * message = (read_tqueue (tqueue, blockp)); - if ((TQUEUE_TYPE (tqueue)) == tqt_scm) - { - process_interrupt_messages (); - if (pending_interrupts_p ()) - return (-2); - } - if (message != 0) - return (MSG_SENDER (message)); - if (!blockp) - return (-1); + process_interrupt_messages (); + if (pending_interrupts_p ()) + return (-2); } + return ((message != 0) ? (MSG_SENDER (message)) : (-1)); } static msg_t * @@ -598,6 +592,16 @@ read_std_tqueue (tqueue_t * tqueue, int blockp) (void) OS2_reset_event_semaphore (STD_TQUEUE_EVENT (tqueue)); OS2_release_mutex_semaphore (STD_TQUEUE_MUTEX (tqueue)); (void) OS2_wait_event_semaphore ((STD_TQUEUE_EVENT (tqueue)), 1); + /* Don't wait more than once; the caller must be prepared to + call again if a message is required. The reason this is + necessary is that two threads may be waiting on the same + tqueue at the same time, and when a message shows up, the + wrong thread might read it. If we allowed the loop to + continue, the thread that was waiting for the message would + wake up, see no message, and go to sleep; meanwhile, the + other thread has already stored the message in the correct + subqueue. */ + blockp = 0; } } diff --git a/v7/src/microcode/pros2io.c b/v7/src/microcode/pros2io.c index a43e84d66..86cc37c96 100644 --- a/v7/src/microcode/pros2io.c +++ b/v7/src/microcode/pros2io.c @@ -1,6 +1,6 @@ /* -*-C-*- -$Id: pros2io.c,v 1.4 1995/04/28 06:59:29 cph Exp $ +$Id: pros2io.c,v 1.5 1995/11/03 01:22:21 cph Exp $ Copyright (c) 1994-95 Massachusetts Institute of Technology @@ -106,6 +106,7 @@ DEFINE_PRIMITIVE ("OS2-SELECT-REGISTRY-TEST", Prim_OS2_select_registry_test, 3, /* This first phase checks the qid subqueues and OS2_scheme_tqueue for any previously-queued input. */ + check_for_input: for (qid = 0; (qid <= QID_MAX); qid += 1) { (results [qid]) = 0; @@ -132,8 +133,10 @@ DEFINE_PRIMITIVE ("OS2-SELECT-REGISTRY-TEST", Prim_OS2_select_registry_test, 3, (OS2_scheme_tqueue_avail_map [qid]) = 0; n = (OS2_tqueue_select (OS2_scheme_tqueue, blockp)); if (n == (-1)) - break; - else if (n < 0) + /* If we're unblocked and there's no message in the + tqueue, go back and check for input again. */ + goto check_for_input; + if (n < 0) interruptp = 1; else for (qid = 0; (qid <= QID_MAX); qid += 1)