From: Rémi Bernon rbernon@codeweavers.com
Drivers still send some messages around, and that will update the queue masks before waiting for the message reply. We need to restore the masks back to what the wait would expect now that we are looping until queue gets signaled.
Wine-Bug: https://bugs.winehq.org/show_bug.cgi?id=58816 --- dlls/win32u/dce.c | 2 +- dlls/win32u/message.c | 74 ++++++++++++++++-------------------- dlls/win32u/ntuser_private.h | 1 - server/queue.c | 1 - 4 files changed, 34 insertions(+), 44 deletions(-)
diff --git a/dlls/win32u/dce.c b/dlls/win32u/dce.c index 6ba5f1c7c44..4dcddd2059a 100644 --- a/dlls/win32u/dce.c +++ b/dlls/win32u/dce.c @@ -1803,7 +1803,7 @@ BOOL WINAPI NtUserRedrawWindow( HWND hwnd, const RECT *rect, HRGN hrgn, UINT fla }
/* process pending expose events before painting */ - if (flags & RDW_UPDATENOW) process_driver_events( QS_PAINT ); + if (flags & RDW_UPDATENOW) check_for_events( QS_PAINT );
if (rect && !hrgn) { diff --git a/dlls/win32u/message.c b/dlls/win32u/message.c index 9c3e0aae7d4..d62d8d245b7 100644 --- a/dlls/win32u/message.c +++ b/dlls/win32u/message.c @@ -3195,6 +3195,23 @@ static BOOL is_queue_signaled(void) return signaled; }
+static BOOL check_queue_masks( UINT wake_mask, UINT changed_mask ) +{ + struct object_lock lock = OBJECT_LOCK_INIT; + const queue_shm_t *queue_shm; + BOOL skip = FALSE; + UINT status; + + while ((status = get_shared_queue( &lock, &queue_shm )) == STATUS_PENDING) + { + if (queue_shm->wake_mask != wake_mask || queue_shm->changed_mask != changed_mask) skip = FALSE; + else skip = get_tick_count() - (UINT64)queue_shm->access_time / 10000 < 3000; /* avoid hung queue */ + } + + if (status) return FALSE; + return skip; +} + static BOOL check_internal_bits( UINT mask ) { struct object_lock lock = OBJECT_LOCK_INIT; @@ -3209,13 +3226,19 @@ static BOOL check_internal_bits( UINT mask ) return signaled; }
-BOOL process_driver_events( UINT mask ) +static BOOL process_driver_events( UINT events_mask, UINT wake_mask, UINT changed_mask ) { - if (check_internal_bits( QS_DRIVER ) && user_driver->pProcessEvents( mask )) + BOOL drained = FALSE; + + if (check_internal_bits( QS_DRIVER )) drained = user_driver->pProcessEvents( events_mask ); + + if (drained || !check_queue_masks( wake_mask, changed_mask )) { SERVER_START_REQ( set_queue_mask ) { - req->poll_events = 1; + req->poll_events = drained; + req->wake_mask = wake_mask; + req->changed_mask = changed_mask; wine_server_call( req ); } SERVER_END_REQ; @@ -3234,7 +3257,7 @@ BOOL process_driver_events( UINT mask )
void check_for_events( UINT flags ) { - if (!process_driver_events( flags )) flush_window_surfaces( TRUE ); + if (!process_driver_events( flags, 0, 0 ) && !(flags & QS_PAINT)) flush_window_surfaces( TRUE ); }
/* monotonic timer tick for throttling driver event checks */ @@ -3251,7 +3274,7 @@ static inline void check_for_driver_events(void) if (get_user_thread_info()->last_driver_time != get_driver_check_time()) { flush_window_surfaces( FALSE ); - process_driver_events( QS_ALLINPUT ); + process_driver_events( QS_ALLINPUT, 0, 0 ); get_user_thread_info()->last_driver_time = get_driver_check_time(); } } @@ -3265,7 +3288,7 @@ static inline LARGE_INTEGER *get_nt_timeout( LARGE_INTEGER *time, DWORD timeout }
/* wait for message or signaled handle */ -static DWORD wait_message( DWORD count, const HANDLE *handles, DWORD timeout, DWORD mask, DWORD flags ) +static DWORD wait_message( DWORD count, const HANDLE *handles, DWORD timeout, DWORD wake_mask, DWORD changed_mask, DWORD flags ) { struct thunk_lock_params params = {.dispatch.callback = thunk_lock_callback}; LARGE_INTEGER time, now, *abs; @@ -3288,9 +3311,9 @@ static DWORD wait_message( DWORD count, const HANDLE *handles, DWORD timeout, DW params.restore = TRUE; }
- process_driver_events( QS_ALLINPUT ); + process_driver_events( QS_ALLINPUT, wake_mask, changed_mask ); do ret = NtWaitForMultipleObjects( count, handles, !(flags & MWMO_WAITALL), !!(flags & MWMO_ALERTABLE), abs ); - while (ret == count - 1 && !process_driver_events( QS_ALLINPUT )); + while (ret == count - 1 && !process_driver_events( QS_ALLINPUT, wake_mask, changed_mask )); if (HIWORD(ret)) /* is it an error code? */ { RtlSetLastWin32Error( RtlNtStatusToDosError(ret) ); @@ -3305,26 +3328,6 @@ static DWORD wait_message( DWORD count, const HANDLE *handles, DWORD timeout, DW return ret; }
-/*********************************************************************** - * check_queue_masks - */ -static BOOL check_queue_masks( UINT wake_mask, UINT changed_mask ) -{ - struct object_lock lock = OBJECT_LOCK_INIT; - const queue_shm_t *queue_shm; - BOOL skip = FALSE; - UINT status; - - while ((status = get_shared_queue( &lock, &queue_shm )) == STATUS_PENDING) - { - if (queue_shm->wake_mask != wake_mask || queue_shm->changed_mask != changed_mask) skip = FALSE; - else skip = get_tick_count() - (UINT64)queue_shm->access_time / 10000 < 3000; /* avoid hung queue */ - } - - if (status) return FALSE; - return skip; -} - /*********************************************************************** * wait_objects * @@ -3339,18 +3342,7 @@ static DWORD wait_objects( DWORD count, const HANDLE *handles, DWORD timeout,
flush_window_surfaces( TRUE );
- if (!check_queue_masks( wake_mask, changed_mask )) - { - SERVER_START_REQ( set_queue_mask ) - { - req->wake_mask = wake_mask; - req->changed_mask = changed_mask; - wine_server_call( req ); - } - SERVER_END_REQ; - } - - return wait_message( count, handles, timeout, changed_mask, flags ); + return wait_message( count, handles, timeout, wake_mask, changed_mask, flags ); }
static HANDLE normalize_std_handle( HANDLE handle ) @@ -3682,7 +3674,7 @@ static void wait_message_reply( UINT flags ) continue; }
- wait_message( 1, &server_queue, INFINITE, wake_mask, 0 ); + wait_message( 1, &server_queue, INFINITE, wake_mask, wake_mask, 0 ); } }
diff --git a/dlls/win32u/ntuser_private.h b/dlls/win32u/ntuser_private.h index b5562ef4743..a89f5b67b16 100644 --- a/dlls/win32u/ntuser_private.h +++ b/dlls/win32u/ntuser_private.h @@ -212,7 +212,6 @@ extern void free_dce( struct dce *dce, HWND hwnd ); extern void invalidate_dce( WND *win, const RECT *old_rect );
/* message.c */ -extern BOOL process_driver_events( UINT mask ); extern void check_for_events( UINT flags );
/* systray.c */ diff --git a/server/queue.c b/server/queue.c index 151b86d1652..b46f20f1340 100644 --- a/server/queue.c +++ b/server/queue.c @@ -3107,7 +3107,6 @@ DECL_HANDLER(set_queue_mask) if (!queue->fd) return; clear_queue_bits( queue, QS_DRIVER ); set_fd_events( queue->fd, POLLIN ); - return; }
SHARED_WRITE_BEGIN( queue_shm, queue_shm_t )