From 81acff62c6ebd5fa692d9a361dfc51e94adf20da Mon Sep 17 00:00:00 2001 From: Augustin Cavalier Date: Thu, 3 Jan 2019 14:47:57 -0500 Subject: [PATCH] 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.) --- src/libs/compat/freebsd_network/Condvar.cpp | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/src/libs/compat/freebsd_network/Condvar.cpp b/src/libs/compat/freebsd_network/Condvar.cpp index 76aadcafb8..e4a6b45d04 100644 --- a/src/libs/compat/freebsd_network/Condvar.cpp +++ b/src/libs/compat/freebsd_network/Condvar.cpp @@ -64,9 +64,14 @@ int publishedConditionTimedWait(const void* waitChannel, const int timeout) { 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, - ticks_to_usecs(timeout)); + usecs > 0 ? usecs : 1000 * 1000); if (status != B_OK) status = EWOULDBLOCK;