https://bugs.winehq.org/show_bug.cgi?id=46208
--- Comment #5 from Zebediah Figura z.figura12@gmail.com --- I think I see the bug, or at least a bug. We can run into the following race (simplified slightly):
wake-all waiter 1 waiter 2 ---------------------------------------- timeout val 2 -> 0 val 0 -> 0 ReleaseKeyed wakeup WaitForKeyed ReleaseKeyed wakeup WaitForKeyed (WaitForKeyed) (WaitForKeyed) ----------------------------------------
If this is what's going on here, waiter 1 (i.e. in this case 0037) gets stuck forever waiting for a Release() that doesn't happen.
Our implementation of ReleaseKeyedEvent() relies on the fact that the first N waiters on the queue are the N waiters on the event. Normally this is true. Even when one waiter times out and subsequently requeues itself (n.b. the requeue is so that a release doesn't block trying to wake someone who isn't waiting), it'll normally requeue itself as the Nth waiter on the event. The problem arises when the second waiter thread calls RtlSleepConditionVariable() again, before RtlWakeAllConditionVariable() is done executing; then that waiter gets woken up twice, and the first waiter not at all; and more importantly the first waiter ends up waiting forever, which probably wasn't intended.