Commit 746df92d authored by Piotr Caban's avatar Piotr Caban Committed by Alexandre Julliard

msvcr110: Make sure we don't hang in _Condition_variable::notify* functions.

parent 13064f99
...@@ -261,6 +261,7 @@ typedef struct ...@@ -261,6 +261,7 @@ typedef struct
} event; } event;
#if _MSVCR_VER >= 110 #if _MSVCR_VER >= 110
#define CV_WAKE (void*)1
typedef struct cv_queue { typedef struct cv_queue {
struct cv_queue *next; struct cv_queue *next;
LONG expired; LONG expired;
...@@ -2299,18 +2300,20 @@ void __thiscall _Condition_variable_dtor(_Condition_variable *this) ...@@ -2299,18 +2300,20 @@ void __thiscall _Condition_variable_dtor(_Condition_variable *this)
DEFINE_THISCALL_WRAPPER(_Condition_variable_wait, 8) DEFINE_THISCALL_WRAPPER(_Condition_variable_wait, 8)
void __thiscall _Condition_variable_wait(_Condition_variable *this, critical_section *cs) void __thiscall _Condition_variable_wait(_Condition_variable *this, critical_section *cs)
{ {
cv_queue q; cv_queue q, *next;
TRACE("(%p, %p)\n", this, cs); TRACE("(%p, %p)\n", this, cs);
critical_section_lock(&this->lock); critical_section_lock(&this->lock);
q.next = this->queue; q.next = this->queue;
q.expired = FALSE; q.expired = FALSE;
next = q.next;
this->queue = &q; this->queue = &q;
critical_section_unlock(&this->lock); critical_section_unlock(&this->lock);
critical_section_unlock(cs); 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); critical_section_lock(cs);
} }
...@@ -2323,7 +2326,7 @@ bool __thiscall _Condition_variable_wait_for(_Condition_variable *this, ...@@ -2323,7 +2326,7 @@ bool __thiscall _Condition_variable_wait_for(_Condition_variable *this,
LARGE_INTEGER to; LARGE_INTEGER to;
NTSTATUS status; NTSTATUS status;
FILETIME ft; FILETIME ft;
cv_queue *q; cv_queue *q, *next;
TRACE("(%p %p %d)\n", this, cs, timeout); TRACE("(%p %p %d)\n", this, cs, timeout);
...@@ -2331,6 +2334,7 @@ bool __thiscall _Condition_variable_wait_for(_Condition_variable *this, ...@@ -2331,6 +2334,7 @@ bool __thiscall _Condition_variable_wait_for(_Condition_variable *this,
critical_section_lock(&this->lock); critical_section_lock(&this->lock);
q->next = this->queue; q->next = this->queue;
q->expired = FALSE; q->expired = FALSE;
next = q->next;
this->queue = q; this->queue = q;
critical_section_unlock(&this->lock); critical_section_unlock(&this->lock);
...@@ -2339,14 +2343,15 @@ bool __thiscall _Condition_variable_wait_for(_Condition_variable *this, ...@@ -2339,14 +2343,15 @@ bool __thiscall _Condition_variable_wait_for(_Condition_variable *this,
GetSystemTimeAsFileTime(&ft); GetSystemTimeAsFileTime(&ft);
to.QuadPart = ((LONGLONG)ft.dwHighDateTime << 32) + to.QuadPart = ((LONGLONG)ft.dwHighDateTime << 32) +
ft.dwLowDateTime + (LONGLONG)timeout * 10000; ft.dwLowDateTime + (LONGLONG)timeout * 10000;
status = NtWaitForKeyedEvent(keyed_event, q, 0, &to); while (q->next != CV_WAKE) {
if(status == STATUS_TIMEOUT) { status = RtlWaitOnAddress(&q->next, &next, sizeof(next), &to);
if(!InterlockedExchange(&q->expired, TRUE)) { if(status == STATUS_TIMEOUT) {
critical_section_lock(cs); if(!InterlockedExchange(&q->expired, TRUE)) {
return FALSE; critical_section_lock(cs);
return FALSE;
}
break;
} }
else
NtWaitForKeyedEvent(keyed_event, q, 0, 0);
} }
operator_delete(q); operator_delete(q);
...@@ -2376,8 +2381,9 @@ void __thiscall _Condition_variable_notify_one(_Condition_variable *this) ...@@ -2376,8 +2381,9 @@ void __thiscall _Condition_variable_notify_one(_Condition_variable *this)
this->queue = node->next; this->queue = node->next;
critical_section_unlock(&this->lock); critical_section_unlock(&this->lock);
node->next = CV_WAKE;
if(!InterlockedExchange(&node->expired, TRUE)) { if(!InterlockedExchange(&node->expired, TRUE)) {
NtReleaseKeyedEvent(keyed_event, node, 0, NULL); RtlWakeAddressSingle(&node->next);
return; return;
} else { } else {
HeapFree(GetProcessHeap(), 0, node); HeapFree(GetProcessHeap(), 0, node);
...@@ -2405,8 +2411,9 @@ void __thiscall _Condition_variable_notify_all(_Condition_variable *this) ...@@ -2405,8 +2411,9 @@ void __thiscall _Condition_variable_notify_all(_Condition_variable *this)
while(ptr) { while(ptr) {
cv_queue *next = ptr->next; cv_queue *next = ptr->next;
ptr->next = CV_WAKE;
if(!InterlockedExchange(&ptr->expired, TRUE)) if(!InterlockedExchange(&ptr->expired, TRUE))
NtReleaseKeyedEvent(keyed_event, ptr, 0, NULL); RtlWakeAddressSingle(&ptr->next);
else else
HeapFree(GetProcessHeap(), 0, ptr); HeapFree(GetProcessHeap(), 0, ptr);
ptr = next; ptr = next;
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment