alternative deadlock issue fix.

This fix also fixes the deadlock issue without putting any
new strain into the main packet processing path.

Instead of occasionally returning true in MaybeReady sometime,
we occasionally process threads if time_mgr time is not running.

If time_mgr time is running, we have heartbeat messages that will
trigger processing in any case -- processing always checks the
exact state of the Queues.

This fix probably also means that we can remove the communication
loads from all input framework tests and run them all simultaneously.
This commit is contained in:
Bernhard Amann 2013-10-24 23:39:16 -07:00
parent c980d1055e
commit 2ac0d77f06
2 changed files with 10 additions and 5 deletions

View file

@ -82,7 +82,11 @@ double Manager::NextTimestamp(double* network_time)
{ {
MsgThread* t = *i; MsgThread* t = *i;
if ( (*i)->MightHaveOut() && ! t->Killed() ) if ( ( (*i)->MightHaveOut() && ! t->Killed() ) // there might be something in the queue
// Workaround: when running without network source, and without any communication,
// timer_manager is always 1. Hence the previous if will never trigger heartbeats
// In this case, we still have to check process our threads from time to time.
|| ( timer_mgr->Time() == 1.0 && random() % 10000 == 0 ) )
return timer_mgr->Time(); return timer_mgr->Time();
} }

View file

@ -63,11 +63,12 @@ public:
/** /**
* Returns true if the next Get() operation might succeed. This * Returns true if the next Get() operation might succeed. This
* function may occasionally return a value not indicating the actual * function may occasionally return a value not indicating the actual
* state, but won't do so very often. Occasionally we also return a * state, but won't do so very often. Note that this means that it can
* true unconditionally to avoid a deadlock when both pointers happen * consistently return false even if there is something in the Queue.
* to be equal even though there's stuff queued. * You have to check real queue status from time to time to be sure that
* it is empty.
*/ */
bool MaybeReady() { return (read_ptr != write_ptr) || (random() % 10000 == 0); } bool MaybeReady() { return (read_ptr != write_ptr); }
/** Wake up the reader if it's currently blocked for input. This is /** Wake up the reader if it's currently blocked for input. This is
primarily to give it a chance to check termination quickly. primarily to give it a chance to check termination quickly.