[WaitHandle] Fix Wait(One|Any|All) and SignalAndWait with timeout
authorLudovic Henry <ludovic@xamarin.com>
Fri, 19 Feb 2016 21:07:22 +0000 (21:07 +0000)
committerLudovic Henry <ludovic@xamarin.com>
Mon, 22 Feb 2016 16:48:52 +0000 (16:48 +0000)
commit55492cbbee242e6fc844863c6360411e77ae3c52
tree5352d0fb5f4473441733041f63ab60bda1523fea
parent1ad39faaa0022f44e6409dac11a087197791eb3d
[WaitHandle] Fix Wait(One|Any|All) and SignalAndWait with timeout

In the case where we would call for example WaitHandle.WaitOne with a timeout, we could run in the case where we would wait way longer than the timeout would allow it (240s instead of 90s for example). This would be due to spurious wake, which would not be considered to be an error, but which would lead calling the `mono_os_cond_timedwait` function with the same timeout every time. That would mean that `mono_os_cond_timedwait` would return that it timedout, if and only if, it would timed out after N milliseconds, with N the millisecondsTimeout parameter to WaitOne in this example. That mean that any spurious wake would effectively lead to rewaiting with a full timeout every time.

That could lead to the following scenario:
 - T1 calls waitHandle.WaitOne(timeout = 1000ms) at T=0ms
 - T1 calls mono_os_cond_timedwait(timeout = 1000) at T=0ms
 - GC suspend T1 at T=500ms <- here it's not necessarily the GC, it can be anything suspending/signaling the thread
 - T1 spurious wake, and call mono_os_cond_timedwait(timeout = 1000) at T=500ms
 - GC interrupt T1 at T=1250ms
 - T1 spurious wake, and call mono_os_cond_timedwait(timeout = 1000) at T=1250ms
 - etc.

As you can see, T1 should have returned from waitHandle.WaitOne before the second spurious wake, but as it recalled mono_os_cond_timedwait with a timeout of 1000ms again, it didn't.

The fix consists in keeping track of when the call is supposed to finish, and pass an adaptable timeout to mono_os_cond_timedwait, which decreases as time goes on, to enventually reach 0, and return in a timely manner.

Fixes https://bugzilla.xamarin.com/show_bug.cgi?id=38382
mcs/class/corlib/Test/System.Threading/WaitHandleTest.cs
mono/io-layer/wait.c