freebsd_network: Handle published conditions with timeout 0.

Previously, since we passed B_RELATIVE_TIMEOUT unconditionally,
a timeout of 0 would mean that it would return as soon as there was
CPU time available (so, usually, instantly.) This usually was not
a "problem" in that it caused broken behavior, but it would result
in exceptionally high CPU usage.

At first I implemented this correctly (i.e. a timeout of 0 will block
until explicitly woken up) but then discovered that our implementation
of these functions creates subtle race conditions compared to their
FreeBSD counterparts, and so to avoid deadlocks, a timeout of 1 second
is imposed. For situations where there are deadlocks due to race
conditions, this will make them painfully obvious (e.g. all network
transfers stalling for a second every 2-3 seconds or so.)
This commit is contained in:
Augustin Cavalier 2019-01-03 14:47:57 -05:00
parent a029a69c55
commit 81acff62c6

View File

@ -64,9 +64,14 @@ int
publishedConditionTimedWait(const void* waitChannel, const int timeout) publishedConditionTimedWait(const void* waitChannel, const int timeout)
{ {
ConditionVariableEntry variableEntry; ConditionVariableEntry variableEntry;
bigtime_t usecs = ticks_to_usecs(timeout);
// FreeBSD has a condition-variable scheduling system with different
// scheduling semantics than ours does. As a result, it seems there are
// some scenarios which work fine under FreeBSD but race into a deadlock
// on Haiku. To avoid this, turn unlimited timeouts into 1sec ones.
status_t status = variableEntry.Wait(waitChannel, B_RELATIVE_TIMEOUT, status_t status = variableEntry.Wait(waitChannel, B_RELATIVE_TIMEOUT,
ticks_to_usecs(timeout)); usecs > 0 ? usecs : 1000 * 1000);
if (status != B_OK) if (status != B_OK)
status = EWOULDBLOCK; status = EWOULDBLOCK;