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@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 );
On thread destroy, a WM_WINE_DESTROYWINDOW is sent for the children windows owned by other threads. However there's then a race condition between these threads peeking for messages and the current thread detaching its child windows from their owning threads -which clears their message queues.
Signed-off-by: Rémi Bernon rbernon@codeweavers.com --- dlls/user32/tests/msg.c | 3 +-- server/window.c | 2 +- 2 files changed, 2 insertions(+), 3 deletions(-)
diff --git a/dlls/user32/tests/msg.c b/dlls/user32/tests/msg.c index c18c90762ab..c3f7d932d32 100644 --- a/dlls/user32/tests/msg.c +++ b/dlls/user32/tests/msg.c @@ -8779,7 +8779,6 @@ static void test_interthread_messages(void)
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 );
@@ -8787,7 +8786,7 @@ static void test_interthread_messages(void) CloseHandle( wnd_event.stop_event ); CloseHandle( wnd_event.child_stopped_event ); flush_events(); - ok_sequence(WmExitThreadSeq, "destroy child on thread exit", TRUE); + ok_sequence(WmExitThreadSeq, "destroy child on thread exit", FALSE); log_all_parent_messages--; DestroyWindow( wnd_event.hwnd );
diff --git a/server/window.c b/server/window.c index c9b131cba5d..3985ea4eb20 100644 --- a/server/window.c +++ b/server/window.c @@ -1914,7 +1914,7 @@ void destroy_window( struct window *win ) post_message( win->parent->handle, WM_PARENTNOTIFY, WM_DESTROY, win->handle ); }
- detach_window_thread( win ); + if (win->thread == current) detach_window_thread( win ); if (win->win_region) free_region( win->win_region ); if (win->update_region) free_region( win->update_region ); if (win->class) release_class( win->class );
Hi,
While running your changed tests, I think I found new failures. Being a bot and all I'm not very good at pattern recognition, so I might be wrong, but could you please double-check?
Full results can be found at: https://testbot.winehq.org/JobDetails.pl?Key=59644
Your paranoid android.
=== wvistau64 (32 bit report) ===
user32: msg.c:16285: Test failed: 1: WaitForSingleObject failed
=== w1064v1809 (32 bit report) ===
user32: msg.c:10356: Test failed: did not get expected count for minimum timeout (54 != ~100).
=== w1064v1809_ar (32 bit report) ===
user32: msg.c:12372: Test failed: message time not advanced: 138ce 138ce msg.c:12373: Test failed: coords not changed: (101 101) (101 101) msg.c:12390: Test failed: message time not advanced: 138ce 138ce msg.c:12391: Test failed: coords not changed: (101 101) (101 101)
=== w1064v1809_he (32 bit report) ===
user32: msg.c:5141: Test failed: ShowWindow(SW_HIDE):overlapped: 0: the msg sequence is not complete: expected 0000 - actual 0024
=== w1064v1809_zh_CN (32 bit report) ===
user32: msg.c:16285: Test failed: 0: WaitForSingleObject failed
=== w864 (64 bit report) ===
user32: msg.c:12428: Test failed: expected PeekMessage to return FALSE, got 1
=== debian10 (32 bit Japanese:Japan report) ===
Report errors: user32:msg prints too much data (35241 bytes)
There's still a timeout related failure around this test, but on Windows this time...:
* https://testbot.winehq.org/JobDetails.pl?Key=59643#k210 * https://testbot.winehq.org/JobDetails.pl?Key=59645#k213
Hi,
While running your changed tests, I think I found new failures. Being a bot and all I'm not very good at pattern recognition, so I might be wrong, but could you please double-check?
Full results can be found at: https://testbot.winehq.org/JobDetails.pl?Key=59643
Your paranoid android.
=== w1064v1809_2scr (32 bit report) ===
user32: msg.c:8773: Test failed: MsgWaitForMultipleObjects failed 102
=== w1064v1809_ar (task log) ===
Task errors: The task timed out
=== w1064v1809 (64 bit report) ===
user32: msg.c:10357: Test failed: did not get expected count for minimum timeout (54 != ~100).
=== debian10 (32 bit Japanese:Japan report) ===
Report errors: user32:msg prints too much data (35423 bytes)