Commit af35aada authored by Stefan Dösinger's avatar Stefan Dösinger Committed by Alexandre Julliard

ntdll: Make RtlDeregisterWaitEx(handle, INVALID_HANDLE_VALUE) thread safe.

Chromium signals the wait semaphore and calls DeregisterWaitEx with CompletionHandle = INVALID_HANDLE_VALUE in close succession. Sometimes the worker thread decides to run the callback, but before it sets CallbackInProgress RtlDeregisterWaitEx decides that the callback is not running and returns STATUS_SUCCESS. Chromium then releases resources that the callback needs to run, resulting in random crashes. Signed-off-by: 's avatarStefan Dösinger <stefan@codeweavers.com> Signed-off-by: 's avatarSebastian Lackner <sebastian@fds-team.de> Signed-off-by: 's avatarAlexandre Julliard <julliard@winehq.org>
parent 41236123
...@@ -541,11 +541,13 @@ static DWORD CALLBACK wait_thread_proc(LPVOID Arg) ...@@ -541,11 +541,13 @@ static DWORD CALLBACK wait_thread_proc(LPVOID Arg)
break; break;
} }
completion_event = wait_work_item->CompletionEvent;
if (completion_event) NtSetEvent( completion_event, NULL );
if (interlocked_inc( &wait_work_item->DeleteCount ) == 2 ) if (interlocked_inc( &wait_work_item->DeleteCount ) == 2 )
{
completion_event = wait_work_item->CompletionEvent;
delete_wait_work_item( wait_work_item ); delete_wait_work_item( wait_work_item );
if (completion_event) NtSetEvent( completion_event, NULL );
}
return 0; return 0;
} }
...@@ -633,44 +635,47 @@ NTSTATUS WINAPI RtlRegisterWait(PHANDLE NewWaitObject, HANDLE Object, ...@@ -633,44 +635,47 @@ NTSTATUS WINAPI RtlRegisterWait(PHANDLE NewWaitObject, HANDLE Object,
NTSTATUS WINAPI RtlDeregisterWaitEx(HANDLE WaitHandle, HANDLE CompletionEvent) NTSTATUS WINAPI RtlDeregisterWaitEx(HANDLE WaitHandle, HANDLE CompletionEvent)
{ {
struct wait_work_item *wait_work_item = WaitHandle; struct wait_work_item *wait_work_item = WaitHandle;
NTSTATUS status = STATUS_SUCCESS; NTSTATUS status;
HANDLE LocalEvent = NULL;
BOOLEAN CallbackInProgress;
TRACE( "(%p)\n", WaitHandle ); TRACE( "(%p %p)\n", WaitHandle, CompletionEvent );
if (WaitHandle == NULL) if (WaitHandle == NULL)
return STATUS_INVALID_HANDLE; return STATUS_INVALID_HANDLE;
NtSetEvent( wait_work_item->CancelEvent, NULL ); CallbackInProgress = wait_work_item->CallbackInProgress;
if (wait_work_item->CallbackInProgress) if (CompletionEvent == INVALID_HANDLE_VALUE || !CallbackInProgress)
{ {
if (CompletionEvent != NULL) status = NtCreateEvent( &LocalEvent, EVENT_ALL_ACCESS, NULL, NotificationEvent, FALSE );
{ if (status != STATUS_SUCCESS)
if (CompletionEvent == INVALID_HANDLE_VALUE) return status;
{ interlocked_xchg_ptr( &wait_work_item->CompletionEvent, LocalEvent );
status = NtCreateEvent( &CompletionEvent, EVENT_ALL_ACCESS, NULL, NotificationEvent, FALSE ); }
if (status != STATUS_SUCCESS) else if (CompletionEvent != NULL)
return status; {
interlocked_xchg_ptr( &wait_work_item->CompletionEvent, CompletionEvent ); interlocked_xchg_ptr( &wait_work_item->CompletionEvent, CompletionEvent );
if (wait_work_item->CallbackInProgress)
NtWaitForSingleObject( CompletionEvent, FALSE, NULL );
NtClose( CompletionEvent );
}
else
{
interlocked_xchg_ptr( &wait_work_item->CompletionEvent, CompletionEvent );
if (wait_work_item->CallbackInProgress)
status = STATUS_PENDING;
}
}
else
status = STATUS_PENDING;
} }
NtSetEvent( wait_work_item->CancelEvent, NULL );
if (interlocked_inc( &wait_work_item->DeleteCount ) == 2 ) if (interlocked_inc( &wait_work_item->DeleteCount ) == 2 )
{ {
status = STATUS_SUCCESS; status = STATUS_SUCCESS;
delete_wait_work_item( wait_work_item ); delete_wait_work_item( wait_work_item );
} }
else if (LocalEvent)
{
NtWaitForSingleObject( LocalEvent, FALSE, NULL );
status = STATUS_SUCCESS;
}
else
{
status = STATUS_PENDING;
}
if (LocalEvent)
NtClose( LocalEvent );
return status; return status;
} }
......
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