This test is failing from time to time. Making sure the parent thread
has terminated before continuing triggers the underlying race condition,
and makes the test to always fail.
Signed-off-by: Rémi Bernon <rbernon(a)codeweavers.com>
---
Supersedes: 205970-205971
v3: Fix another stupid mistake where the thread handle is closed before
the grand child had a chance to wait on it.
dlls/user32/tests/msg.c | 52 +++++++++++++++++++++++++----------------
1 file changed, 32 insertions(+), 20 deletions(-)
diff --git a/dlls/user32/tests/msg.c b/dlls/user32/tests/msg.c
index 13e085dfacc..fab8f291a52 100644
--- a/dlls/user32/tests/msg.c
+++ b/dlls/user32/tests/msg.c
@@ -8791,7 +8791,10 @@ static void test_paint_messages(void)
struct wnd_event
{
HWND hwnd;
+ HWND child_hwnd;
+ HANDLE child;
HANDLE grand_child;
+ HANDLE ready_event;
HANDLE start_event;
HANDLE stop_event;
};
@@ -8822,42 +8825,48 @@ static DWORD CALLBACK create_grand_child_thread( void *param )
{
struct wnd_event *wnd_event = param;
HWND hchild;
- MSG msg;
+ DWORD ret;
hchild = CreateWindowExA(0, "TestWindowClass", "Test child",
- WS_CHILD | WS_VISIBLE, 0, 0, 10, 10, wnd_event->hwnd, 0, 0, NULL);
+ WS_CHILD | WS_VISIBLE, 0, 0, 10, 10, wnd_event->child_hwnd, 0, 0, NULL);
ok (hchild != 0, "Failed to create child window\n");
flush_events();
flush_sequence();
+
+ /* wait for wnd_event->child to be set */
+ ret = WaitForSingleObject( wnd_event->ready_event, 1000 );
+ ok( !ret, "WaitForSingleObject failed %x\n", ret );
SetEvent( wnd_event->start_event );
- for (;;)
- {
- MsgWaitForMultipleObjects(0, NULL, FALSE, 1000, QS_ALLINPUT);
- if (!IsWindow( hchild )) break; /* will be destroyed when parent thread exits */
- while (PeekMessageA(&msg, 0, 0, 0, PM_REMOVE)) DispatchMessageA(&msg);
- }
+ /* wait for parent window thread to exit */
+ ret = WaitForSingleObject( wnd_event->child, 1000 );
+ ok( !ret, "WaitForSingleObject returned %x, error: %u\n", ret, GetLastError() );
+ ok( IsWindow( hchild ), "Child window already destroyed\n" );
+ flush_events();
+ todo_wine ok( !IsWindow( hchild ), "Child window not destroyed\n" );
+
return 0;
}
static DWORD CALLBACK create_child_thread( void *param )
{
struct wnd_event *wnd_event = param;
- struct wnd_event child_event;
DWORD ret, tid;
MSG msg;
- child_event.hwnd = CreateWindowExA(0, "TestWindowClass", "Test child",
- WS_CHILD | WS_VISIBLE, 0, 0, 10, 10, wnd_event->hwnd, 0, 0, NULL);
- ok (child_event.hwnd != 0, "Failed to create child window\n");
- SetFocus( child_event.hwnd );
+ wnd_event->child_hwnd = CreateWindowExA( 0, "TestWindowClass", "Test child", WS_CHILD | WS_VISIBLE,
+ 0, 0, 10, 10, wnd_event->hwnd, 0, 0, NULL );
+ ok( wnd_event->child_hwnd != 0, "Failed to create child windows\n" );
+ SetFocus( wnd_event->child_hwnd );
+
+ wnd_event->grand_child = CreateThread( NULL, 0, create_grand_child_thread, wnd_event, 0, &tid );
+ ok( wnd_event->grand_child != 0, "CreateThread failed, error %u\n", GetLastError() );
+
flush_events();
flush_sequence();
- child_event.start_event = wnd_event->start_event;
- wnd_event->grand_child = CreateThread(NULL, 0, create_grand_child_thread, &child_event, 0, &tid);
for (;;)
{
- DWORD ret = MsgWaitForMultipleObjects(1, &child_event.start_event, FALSE, 1000, QS_SENDMESSAGE);
+ DWORD ret = MsgWaitForMultipleObjects(1, &wnd_event->start_event, FALSE, 1000, QS_SENDMESSAGE);
if (ret != 1) break;
while (PeekMessageA(&msg, 0, 0, 0, PM_REMOVE)) DispatchMessageA(&msg);
}
@@ -8997,9 +9006,11 @@ static void test_interthread_messages(void)
flush_events();
flush_sequence();
log_all_parent_messages++;
+ wnd_event.ready_event = CreateEventA( NULL, TRUE, FALSE, NULL );
wnd_event.start_event = CreateEventA( NULL, TRUE, FALSE, NULL );
wnd_event.stop_event = CreateEventA( NULL, TRUE, FALSE, NULL );
- hThread = CreateThread( NULL, 0, create_child_thread, &wnd_event, 0, &tid );
+ wnd_event.child = CreateThread( NULL, 0, create_child_thread, &wnd_event, 0, &tid );
+ SetEvent( wnd_event.ready_event );
for (;;)
{
ret = MsgWaitForMultipleObjects(1, &wnd_event.start_event, FALSE, 1000, QS_SENDMESSAGE);
@@ -9009,18 +9020,19 @@ static void test_interthread_messages(void)
ok( !ret, "MsgWaitForMultipleObjects failed %x\n", ret );
/* now wait for the thread without processing messages; this shouldn't deadlock */
SetEvent( wnd_event.stop_event );
- ret = WaitForSingleObject( hThread, 5000 );
+ ret = WaitForSingleObject( wnd_event.child, 5000 );
ok( !ret, "WaitForSingleObject failed %x\n", ret );
- CloseHandle( hThread );
ret = WaitForSingleObject( wnd_event.grand_child, 5000 );
ok( !ret, "WaitForSingleObject failed %x\n", ret );
CloseHandle( wnd_event.grand_child );
+ CloseHandle( wnd_event.child );
CloseHandle( wnd_event.start_event );
CloseHandle( wnd_event.stop_event );
+ CloseHandle( wnd_event.ready_event );
flush_events();
- ok_sequence(WmExitThreadSeq, "destroy child on thread exit", FALSE);
+ ok_sequence( WmExitThreadSeq, "destroy child on thread exit", TRUE );
log_all_parent_messages--;
DestroyWindow( wnd_event.hwnd );
--
2.31.0