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

Rémi Bernon rbernon at codeweavers.com
Fri Nov 8 05:18:30 CST 2019


This test is failing from time to time. Making sure the parent thread
is complete before continuing triggers the underlying race condition,
and makes the test to always fail.

Signed-off-by: Rémi Bernon <rbernon at codeweavers.com>
---

Notes:
    v3: As we wait for the child thread completion, the grand child now
    copies its parameter from the stack of its parent to avoid accessing
    invalid memory.
    
    The failure was hard to reproduce. The most reliable way without the
    sleep added here is to start multiple runs on the testbot, changing
    locale for each run. The locale change seems to have an impact on
    the timing and triggers the race condition.

 dlls/user32/tests/msg.c | 18 ++++++++++++++----
 1 file changed, 14 insertions(+), 4 deletions(-)

diff --git a/dlls/user32/tests/msg.c b/dlls/user32/tests/msg.c
index 193a20fd958..c18c90762ab 100644
--- a/dlls/user32/tests/msg.c
+++ b/dlls/user32/tests/msg.c
@@ -8551,6 +8551,7 @@ struct wnd_event
     HANDLE grand_child;
     HANDLE start_event;
     HANDLE stop_event;
+    HANDLE child_stopped_event;
 };
 
 static DWORD WINAPI thread_proc(void *param)
@@ -8577,16 +8578,20 @@ static DWORD WINAPI thread_proc(void *param)
 
 static DWORD CALLBACK create_grand_child_thread( void *param )
 {
-    struct wnd_event *wnd_event = param;
+    struct wnd_event wnd_event = *(struct 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.hwnd, 0, 0, NULL);
     ok (hchild != 0, "Failed to create child window\n");
     flush_events();
     flush_sequence();
-    SetEvent( wnd_event->start_event );
+    SetEvent( wnd_event.start_event );
+
+    ret = WaitForSingleObject( wnd_event.child_stopped_event, 500 );
+    ok( !ret, "WaitForSingleObject failed %x\n", ret );
 
     for (;;)
     {
@@ -8611,6 +8616,7 @@ static DWORD CALLBACK create_child_thread( void *param )
     flush_events();
     flush_sequence();
     child_event.start_event = wnd_event->start_event;
+    child_event.child_stopped_event = wnd_event->child_stopped_event;
     wnd_event->grand_child = CreateThread(NULL, 0, create_grand_child_thread, &child_event, 0, &tid);
     for (;;)
     {
@@ -8756,6 +8762,7 @@ static void test_interthread_messages(void)
     log_all_parent_messages++;
     wnd_event.start_event = CreateEventA( NULL, TRUE, FALSE, NULL );
     wnd_event.stop_event = CreateEventA( NULL, TRUE, FALSE, NULL );
+    wnd_event.child_stopped_event = CreateEventA( NULL, TRUE, FALSE, NULL );
     hThread = CreateThread( NULL, 0, create_child_thread, &wnd_event, 0, &tid );
     for (;;)
     {
@@ -8770,14 +8777,17 @@ static void test_interthread_messages(void)
     ok( !ret, "WaitForSingleObject failed %x\n", ret );
     CloseHandle( hThread );
 
+    SetEvent( wnd_event.child_stopped_event );
     ret = WaitForSingleObject( wnd_event.grand_child, 5000 );
+    todo_wine
     ok( !ret, "WaitForSingleObject failed %x\n", ret );
     CloseHandle( wnd_event.grand_child );
 
     CloseHandle( wnd_event.start_event );
     CloseHandle( wnd_event.stop_event );
+    CloseHandle( wnd_event.child_stopped_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.24.0.rc2




More information about the wine-devel mailing list