[PATCH v3 1/2] user32/tests: Wait for parent window thread before checking window.

Rémi Bernon rbernon at codeweavers.com
Tue May 18 09:33:38 CDT 2021


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 at 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




More information about the wine-devel mailing list