diff --git a/repos/os/src/test/signal/main.cc b/repos/os/src/test/signal/main.cc index 9f3586868..33ef04e2e 100644 --- a/repos/os/src/test/signal/main.cc +++ b/repos/os/src/test/signal/main.cc @@ -32,9 +32,9 @@ class Sender : Thread Signal_transmitter _transmitter; unsigned const _interval_ms; bool const _verbose; - bool _stop { false }; + bool volatile _stop { false }; unsigned _submit_cnt { 0 }; - bool _idle { false }; + bool volatile _idle { false }; void entry() { @@ -65,6 +65,14 @@ class Sender : Thread Thread::start(); } + ~Sender() + { + if (!_stop && Thread::myself() != this) { + _stop = true; + join(); + } + } + /*************** ** Accessors ** ***************/ @@ -524,7 +532,7 @@ struct Nested_stress_test : Signal_test struct Sender : Thread { Signal_transmitter transmitter; - bool destruct { false }; + bool volatile destruct { false }; Sender(Env &env, char const *name, Signal_context_capability cap) : Thread(env, name, 8*1024), transmitter(cap) { } @@ -540,8 +548,10 @@ struct Nested_stress_test : Signal_test { Entrypoint ep; char const *name; - unsigned count { 0 }; - bool destruct { false }; + unsigned count { 0 }; + unsigned level { 0 }; + bool volatile destruct { false }; + bool volatile ready_for_destruction { false }; Io_signal_handler handler { ep, *this, &Receiver::handle }; @@ -554,7 +564,11 @@ struct Nested_stress_test : Signal_test * We have to get out of the nesting if the host wants to destroy * us to avoid a deadlock at the lock in the signal handler. */ - if (destruct) { return; } + if (destruct) { + if (level == 0) + ready_for_destruction = true; + return; + } /* raise call counter */ count++; @@ -564,7 +578,10 @@ struct Nested_stress_test : Signal_test * gives zero, then unwind the whole nesting and start afresh. */ if ((count & ((1 << UNWIND_COUNT_MOD_LOG2) - 1)) != 0) { - ep.wait_and_dispatch_one_io_signal(); } + level ++; + ep.wait_and_dispatch_one_io_signal(); + level --; + } } }; @@ -599,26 +616,33 @@ struct Nested_stress_test : Signal_test /* tell timer not to send any signals anymore. */ timer.sigh(Timer::Session::Signal_context_capability()); - /* let senders stop burning our CPU time */ - sender_1.destruct = true; - sender_2.destruct = true; - sender_3.destruct = true; - /* let receivers unwind their nesting and stop with the next signal */ receiver_1.destruct = true; receiver_2.destruct = true; receiver_3.destruct = true; /* - * Send final signals ourselves because otherwise we would have to - * synchronize with the senders. + * Wait until receiver threads get out of + * wait_and_dispatch_one_io_signal, otherwise we may (dead)lock forever + * during destruction of the Io_signal_handler. */ - sender_1.transmitter.submit(); - sender_2.transmitter.submit(); - sender_3.transmitter.submit(); + log("waiting for receivers"); + + while (!receiver_1.ready_for_destruction) { } + while (!receiver_2.ready_for_destruction) { } + while (!receiver_3.ready_for_destruction) { } + + /* let senders stop burning our CPU time */ + sender_1.destruct = true; + sender_2.destruct = true; + sender_3.destruct = true; + + log ("waiting for senders"); /* wait until threads joined */ sender_1.join(); sender_2.join(), sender_3.join(); + + log("destructing ..."); } void handle_poll()