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>
This commit is contained in:
parent
13064f9914
commit
746df92dba
|
@ -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)
|
||||||
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,
|
||||||
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,
|
||||||
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,
|
||||||
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)
|
||||||
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)
|
||||||
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;
|
||||||
|
|
Loading…
Reference in New Issue