Module: wine Branch: master Commit: 746df92dba928c8f5bfbff44c2b7156ab5bcf195 URL: https://source.winehq.org/git/wine.git/?a=commit;h=746df92dba928c8f5bfbff44c...
Author: Piotr Caban piotr@codeweavers.com Date: Wed Mar 16 14:38:02 2022 +0100
msvcr110: Make sure we don't hang in _Condition_variable::notify* functions.
Signed-off-by: Piotr Caban piotr@codeweavers.com Signed-off-by: Alexandre Julliard julliard@winehq.org
---
dlls/msvcrt/concurrency.c | 31 +++++++++++++++++++------------ 1 file changed, 19 insertions(+), 12 deletions(-)
diff --git a/dlls/msvcrt/concurrency.c b/dlls/msvcrt/concurrency.c index 18138901594..54b2c49db99 100644 --- a/dlls/msvcrt/concurrency.c +++ b/dlls/msvcrt/concurrency.c @@ -261,6 +261,7 @@ typedef struct } event;
#if _MSVCR_VER >= 110 +#define CV_WAKE (void*)1 typedef struct cv_queue { struct cv_queue *next; LONG expired; @@ -2299,18 +2300,20 @@ void __thiscall _Condition_variable_dtor(_Condition_variable *this) DEFINE_THISCALL_WRAPPER(_Condition_variable_wait, 8) void __thiscall _Condition_variable_wait(_Condition_variable *this, critical_section *cs) { - cv_queue q; + cv_queue q, *next;
TRACE("(%p, %p)\n", this, cs);
critical_section_lock(&this->lock); q.next = this->queue; q.expired = FALSE; + next = q.next; this->queue = &q; critical_section_unlock(&this->lock);
critical_section_unlock(cs); - NtWaitForKeyedEvent(keyed_event, &q, 0, NULL); + while (q.next != CV_WAKE) + RtlWaitOnAddress(&q.next, &next, sizeof(next), NULL); critical_section_lock(cs); }
@@ -2323,7 +2326,7 @@ bool __thiscall _Condition_variable_wait_for(_Condition_variable *this, LARGE_INTEGER to; NTSTATUS status; FILETIME ft; - cv_queue *q; + cv_queue *q, *next;
TRACE("(%p %p %d)\n", this, cs, timeout);
@@ -2331,6 +2334,7 @@ bool __thiscall _Condition_variable_wait_for(_Condition_variable *this, critical_section_lock(&this->lock); q->next = this->queue; q->expired = FALSE; + next = q->next; this->queue = q; critical_section_unlock(&this->lock);
@@ -2339,14 +2343,15 @@ bool __thiscall _Condition_variable_wait_for(_Condition_variable *this, GetSystemTimeAsFileTime(&ft); to.QuadPart = ((LONGLONG)ft.dwHighDateTime << 32) + ft.dwLowDateTime + (LONGLONG)timeout * 10000; - status = NtWaitForKeyedEvent(keyed_event, q, 0, &to); - if(status == STATUS_TIMEOUT) { - if(!InterlockedExchange(&q->expired, TRUE)) { - critical_section_lock(cs); - return FALSE; + while (q->next != CV_WAKE) { + status = RtlWaitOnAddress(&q->next, &next, sizeof(next), &to); + if(status == STATUS_TIMEOUT) { + if(!InterlockedExchange(&q->expired, TRUE)) { + critical_section_lock(cs); + return FALSE; + } + break; } - else - NtWaitForKeyedEvent(keyed_event, q, 0, 0); }
operator_delete(q); @@ -2376,8 +2381,9 @@ void __thiscall _Condition_variable_notify_one(_Condition_variable *this) this->queue = node->next; critical_section_unlock(&this->lock);
+ node->next = CV_WAKE; if(!InterlockedExchange(&node->expired, TRUE)) { - NtReleaseKeyedEvent(keyed_event, node, 0, NULL); + RtlWakeAddressSingle(&node->next); return; } else { HeapFree(GetProcessHeap(), 0, node); @@ -2405,8 +2411,9 @@ void __thiscall _Condition_variable_notify_all(_Condition_variable *this) while(ptr) { cv_queue *next = ptr->next;
+ ptr->next = CV_WAKE; if(!InterlockedExchange(&ptr->expired, TRUE)) - NtReleaseKeyedEvent(keyed_event, ptr, 0, NULL); + RtlWakeAddressSingle(&ptr->next); else HeapFree(GetProcessHeap(), 0, ptr); ptr = next;