From: Rémi Bernon rbernon@codeweavers.com
--- server/protocol.def | 6 ++++++ server/queue.c | 8 ++++++++ 2 files changed, 14 insertions(+)
diff --git a/server/protocol.def b/server/protocol.def index 11539654dc3..97b4805c552 100644 --- a/server/protocol.def +++ b/server/protocol.def @@ -913,9 +913,15 @@ typedef volatile struct unsigned char keystate[256]; /* asynchronous key state */ } desktop_shm_t;
+typedef volatile struct +{ + int placeholder; +} queue_shm_t; + typedef volatile union { desktop_shm_t desktop; + queue_shm_t queue; } object_shm_t;
typedef volatile struct diff --git a/server/queue.c b/server/queue.c index a7814c83737..5f4e5fa33c2 100644 --- a/server/queue.c +++ b/server/queue.c @@ -146,6 +146,7 @@ struct msg_queue struct hook_table *hooks; /* hook table */ timeout_t last_get_msg; /* time of last get message call */ int keystate_lock; /* owns an input keystate lock */ + const queue_shm_t *shared; /* queue in session shared memory */ };
struct hotkey @@ -321,6 +322,12 @@ static struct msg_queue *create_msg_queue( struct thread *thread, struct thread_ list_init( &queue->expired_timers ); for (i = 0; i < NB_MSG_KINDS; i++) list_init( &queue->msg_list[i] );
+ if (!(queue->shared = alloc_shared_object())) + { + release_object( queue ); + return NULL; + } + thread->queue = queue; } if (new_input) release_object( new_input ); @@ -1210,6 +1217,7 @@ static void msg_queue_destroy( struct object *obj ) release_object( queue->input ); if (queue->hooks) release_object( queue->hooks ); if (queue->fd) release_object( queue->fd ); + if (queue->shared) free_shared_object( queue->shared ); }
static void msg_queue_poll_event( struct fd *fd, int event )
From: Rémi Bernon rbernon@codeweavers.com
--- server/protocol.def | 2 +- server/queue.c | 21 ++++++++++++++++++++- 2 files changed, 21 insertions(+), 2 deletions(-)
diff --git a/server/protocol.def b/server/protocol.def index 97b4805c552..70cd835b647 100644 --- a/server/protocol.def +++ b/server/protocol.def @@ -915,7 +915,7 @@ typedef volatile struct
typedef volatile struct { - int placeholder; + obj_handle_t handle; /* handle to the queue */ } queue_shm_t;
typedef volatile union diff --git a/server/queue.c b/server/queue.c index 5f4e5fa33c2..d56b199f1f0 100644 --- a/server/queue.c +++ b/server/queue.c @@ -290,6 +290,7 @@ static struct msg_queue *create_msg_queue( struct thread *thread, struct thread_ { struct thread_input *new_input = NULL; struct msg_queue *queue; + obj_handle_t handle; int i;
if (!input) @@ -328,6 +329,13 @@ static struct msg_queue *create_msg_queue( struct thread *thread, struct thread_ return NULL; }
+ handle = alloc_handle( thread->process, queue, SYNCHRONIZE, 0 ); + SHARED_WRITE_BEGIN( queue->shared, queue_shm_t ) + { + shared->handle = handle; + } + SHARED_WRITE_END; + thread->queue = queue; } if (new_input) release_object( new_input ); @@ -337,8 +345,19 @@ static struct msg_queue *create_msg_queue( struct thread *thread, struct thread_ /* free the message queue of a thread at thread exit */ void free_msg_queue( struct thread *thread ) { + obj_handle_t handle; + remove_thread_hooks( thread ); if (!thread->queue) return; + + SHARED_WRITE_BEGIN( thread->queue->shared, queue_shm_t ) + { + handle = shared->handle; + shared->handle = 0; + } + SHARED_WRITE_END; + close_handle( thread->process, handle ); + release_object( thread->queue ); thread->queue = NULL; } @@ -2866,7 +2885,7 @@ DECL_HANDLER(get_msg_queue) struct msg_queue *queue = get_current_queue();
reply->handle = 0; - if (queue) reply->handle = alloc_handle( current->process, queue, SYNCHRONIZE, 0 ); + if (queue) reply->handle = queue->shared->handle; }
From: Rémi Bernon rbernon@codeweavers.com
--- dlls/win32u/message.c | 13 +++++++------ dlls/win32u/win32u_private.h | 1 + dlls/win32u/winstation.c | 35 +++++++++++++++++++++++++++++++++++ server/protocol.def | 2 +- server/queue.c | 4 +--- 5 files changed, 45 insertions(+), 10 deletions(-)
diff --git a/dlls/win32u/message.c b/dlls/win32u/message.c index b7062414658..43f6f19050e 100644 --- a/dlls/win32u/message.c +++ b/dlls/win32u/message.c @@ -2941,16 +2941,17 @@ static void process_sent_messages(void) static HANDLE get_server_queue_handle(void) { struct user_thread_info *thread_info = get_user_thread_info(); + struct object_lock lock = OBJECT_LOCK_INIT; + const queue_shm_t *queue_shm; + UINT status; HANDLE ret;
if (!(ret = thread_info->server_queue)) { - SERVER_START_REQ( get_msg_queue ) - { - wine_server_call( req ); - ret = wine_server_ptr_handle( reply->handle ); - } - SERVER_END_REQ; + while ((status = get_shared_queue( &lock, &queue_shm )) == STATUS_PENDING) + ret = wine_server_ptr_handle( queue_shm->handle ); + if (status) ret = 0; + thread_info->server_queue = ret; if (!ret) ERR( "Cannot get server thread queue\n" ); } diff --git a/dlls/win32u/win32u_private.h b/dlls/win32u/win32u_private.h index e2e35d6c40d..cd64751e95b 100644 --- a/dlls/win32u/win32u_private.h +++ b/dlls/win32u/win32u_private.h @@ -219,6 +219,7 @@ struct object_lock * on it, within the loop, or after, unless the function has returned STATUS_SUCCESS. */ extern NTSTATUS get_shared_desktop( struct object_lock *lock, const desktop_shm_t **desktop_shm ); +extern NTSTATUS get_shared_queue( struct object_lock *lock, const queue_shm_t **queue_shm );
extern BOOL is_virtual_desktop(void);
diff --git a/dlls/win32u/winstation.c b/dlls/win32u/winstation.c index 1676539c69c..1a1b37f6eda 100644 --- a/dlls/win32u/winstation.c +++ b/dlls/win32u/winstation.c @@ -48,6 +48,7 @@ WINE_DECLARE_DEBUG_CHANNEL(win); struct session_thread_data { const shared_object_t *shared_desktop; /* thread desktop shared session cached object */ + const shared_object_t *shared_queue; /* thread message queue shared session cached object */ };
struct session_block @@ -219,6 +220,40 @@ NTSTATUS get_shared_desktop( struct object_lock *lock, const desktop_shm_t **des return STATUS_SUCCESS; }
+NTSTATUS get_shared_queue( struct object_lock *lock, const queue_shm_t **queue_shm ) +{ + struct session_thread_data *data = get_session_thread_data(); + const shared_object_t *object; + + TRACE( "lock %p, queue_shm %p\n", lock, queue_shm ); + + if (!(object = data->shared_queue)) + { + obj_locator_t locator; + + SERVER_START_REQ( get_msg_queue ) + { + wine_server_call( req ); + locator = reply->locator; + } + SERVER_END_REQ; + + data->shared_queue = find_shared_session_object( locator ); + if (!(object = data->shared_queue)) return STATUS_INVALID_HANDLE; + memset( lock, 0, sizeof(*lock) ); + } + + if (!lock->id || !shared_object_release_seqlock( object, lock->seq )) + { + shared_object_acquire_seqlock( object, &lock->seq ); + *queue_shm = &object->shm.queue; + lock->id = object->id; + return STATUS_PENDING; + } + + return STATUS_SUCCESS; +} + BOOL is_virtual_desktop(void) { HANDLE desktop = NtUserGetThreadDesktop( GetCurrentThreadId() ); diff --git a/server/protocol.def b/server/protocol.def index 70cd835b647..d200dfc7528 100644 --- a/server/protocol.def +++ b/server/protocol.def @@ -2118,7 +2118,7 @@ struct process_info /* Get the message queue of the current thread */ @REQ(get_msg_queue) @REPLY - obj_handle_t handle; /* handle to the queue */ + obj_locator_t locator; /* locator for the shared session object */ @END
diff --git a/server/queue.c b/server/queue.c index d56b199f1f0..60c9b98dec8 100644 --- a/server/queue.c +++ b/server/queue.c @@ -2883,9 +2883,7 @@ DECL_HANDLER(is_window_hung) DECL_HANDLER(get_msg_queue) { struct msg_queue *queue = get_current_queue(); - - reply->handle = 0; - if (queue) reply->handle = queue->shared->handle; + if (queue) reply->locator = get_shared_object_locator( queue->shared ); }
From: Rémi Bernon rbernon@codeweavers.com
--- server/hook.c | 6 +++--- server/protocol.def | 1 + server/queue.c | 20 +++++++++++++++++++- server/user.h | 1 + 4 files changed, 24 insertions(+), 4 deletions(-)
diff --git a/server/hook.c b/server/hook.c index c22e3748b8b..aff3a5b12b6 100644 --- a/server/hook.c +++ b/server/hook.c @@ -463,7 +463,7 @@ DECL_HANDLER(set_hook) hook->module = module; hook->module_size = module_size; reply->handle = hook->handle; - reply->active_hooks = get_active_hooks(); + reply->active_hooks = set_queue_active_hooks( current ); } else free( module );
@@ -501,7 +501,7 @@ DECL_HANDLER(remove_hook) } } remove_hook( hook ); - reply->active_hooks = get_active_hooks(); + reply->active_hooks = set_queue_active_hooks( current ); }
@@ -518,7 +518,7 @@ DECL_HANDLER(start_hook_chain) return; }
- reply->active_hooks = get_active_hooks(); + reply->active_hooks = set_queue_active_hooks( current );
if (!table || !(hook = get_first_valid_hook( table, req->id - WH_MINHOOK, req->event, req->window, req->object_id, req->child_id ))) diff --git a/server/protocol.def b/server/protocol.def index d200dfc7528..c20137a05f1 100644 --- a/server/protocol.def +++ b/server/protocol.def @@ -916,6 +916,7 @@ typedef volatile struct typedef volatile struct { obj_handle_t handle; /* handle to the queue */ + unsigned int active_hooks; /* active hooks bitmap */ } queue_shm_t;
typedef volatile union diff --git a/server/queue.c b/server/queue.c index 60c9b98dec8..cd6ab1bccdc 100644 --- a/server/queue.c +++ b/server/queue.c @@ -333,6 +333,7 @@ static struct msg_queue *create_msg_queue( struct thread *thread, struct thread_ SHARED_WRITE_BEGIN( queue->shared, queue_shm_t ) { shared->handle = handle; + shared->active_hooks = 0; } SHARED_WRITE_END;
@@ -631,6 +632,23 @@ void set_queue_hooks( struct thread *thread, struct hook_table *hooks ) queue->hooks = hooks; }
+/* update the thread message queue active hooks bitmap */ +unsigned int set_queue_active_hooks( struct thread *thread ) +{ + unsigned int active_hooks = get_active_hooks(); + + if (thread->queue) + { + SHARED_WRITE_BEGIN( thread->queue->shared, queue_shm_t ) + { + shared->active_hooks = active_hooks; + } + SHARED_WRITE_END; + } + + return active_hooks; +} + /* check the queue status */ static inline int is_signaled( struct msg_queue *queue ) { @@ -3092,7 +3110,7 @@ DECL_HANDLER(get_message) user_handle_t get_win = get_user_full_handle( req->get_win ); unsigned int filter = req->flags >> 16;
- reply->active_hooks = get_active_hooks(); + reply->active_hooks = set_queue_active_hooks( current );
if (get_win && get_win != 1 && get_win != -1 && !get_user_object( get_win, USER_WINDOW )) { diff --git a/server/user.h b/server/user.h index 99491293a7c..3d7dcce6e13 100644 --- a/server/user.h +++ b/server/user.h @@ -114,6 +114,7 @@ extern struct thread *get_first_global_hook( struct desktop *desktop, int id ); extern void free_msg_queue( struct thread *thread ); extern struct hook_table *get_queue_hooks( struct thread *thread ); extern void set_queue_hooks( struct thread *thread, struct hook_table *hooks ); +extern unsigned int set_queue_active_hooks( struct thread *thread ); extern void inc_queue_paint_count( struct thread *thread, int incr ); extern void queue_cleanup_window( struct thread *thread, user_handle_t win ); extern int init_thread_queue( struct thread *thread );
From: Rémi Bernon rbernon@codeweavers.com
--- dlls/win32u/hook.c | 17 ++++++++++++----- 1 file changed, 12 insertions(+), 5 deletions(-)
diff --git a/dlls/win32u/hook.c b/dlls/win32u/hook.c index eca9e7d6ce9..2137b31fa2b 100644 --- a/dlls/win32u/hook.c +++ b/dlls/win32u/hook.c @@ -62,10 +62,17 @@ static const char *debugstr_hook_id( unsigned int id )
BOOL is_hooked( INT id ) { - struct user_thread_info *thread_info = get_user_thread_info(); + unsigned int hook_bit = (1 << (id - WH_MINHOOK)); + struct object_lock lock = OBJECT_LOCK_INIT; + const queue_shm_t *queue_shm; + BOOL ret = TRUE; + UINT status; + + while ((status = get_shared_queue( &lock, &queue_shm )) == STATUS_PENDING) + ret = !queue_shm->active_hooks || (queue_shm->active_hooks & hook_bit);
- if (!thread_info->active_hooks) return TRUE; - return (thread_info->active_hooks & (1 << (id - WH_MINHOOK))) != 0; + if (status) return TRUE; + return ret; }
/*********************************************************************** @@ -430,7 +437,7 @@ LRESULT call_message_hooks( INT id, INT code, WPARAM wparam, LPARAM lparam, size
if (!is_hooked( id )) { - TRACE( "skipping hook %s mask %x\n", hook_names[id-WH_MINHOOK], thread_info->active_hooks ); + TRACE( "skipping hook %s\n", hook_names[id - WH_MINHOOK] ); return 0; }
@@ -569,7 +576,7 @@ void WINAPI NtUserNotifyWinEvent( DWORD event, HWND hwnd, LONG object_id, LONG c
if (!is_hooked( WH_WINEVENT )) { - TRACE( "skipping hook mask %x\n", thread_info->active_hooks ); + TRACE( "skipping hook\n" ); return; }
From: Rémi Bernon rbernon@codeweavers.com
--- dlls/win32u/hook.c | 9 --------- dlls/win32u/message.c | 1 - dlls/win32u/ntuser_private.h | 1 - 3 files changed, 11 deletions(-)
diff --git a/dlls/win32u/hook.c b/dlls/win32u/hook.c index 2137b31fa2b..3ccd7caa4a3 100644 --- a/dlls/win32u/hook.c +++ b/dlls/win32u/hook.c @@ -136,7 +136,6 @@ HHOOK WINAPI NtUserSetWindowsHookEx( HINSTANCE inst, UNICODE_STRING *module, DWO if (!wine_server_call_err( req )) { handle = wine_server_ptr_handle( reply->handle ); - get_user_thread_info()->active_hooks = reply->active_hooks; } } SERVER_END_REQ; @@ -157,7 +156,6 @@ BOOL WINAPI NtUserUnhookWindowsHookEx( HHOOK handle ) req->handle = wine_server_user_handle( handle ); req->id = 0; status = wine_server_call_err( req ); - if (!status) get_user_thread_info()->active_hooks = reply->active_hooks; } SERVER_END_REQ; if (status == STATUS_INVALID_HANDLE) RtlSetLastWin32Error( ERROR_INVALID_HOOK_HANDLE ); @@ -177,7 +175,6 @@ BOOL unhook_windows_hook( INT id, HOOKPROC proc ) req->id = id; req->proc = wine_server_client_ptr( proc ); status = wine_server_call_err( req ); - if (!status) get_user_thread_info()->active_hooks = reply->active_hooks; } SERVER_END_REQ; if (status == STATUS_INVALID_HANDLE) RtlSetLastWin32Error( ERROR_INVALID_HOOK_HANDLE ); @@ -428,7 +425,6 @@ LRESULT call_current_hook( HHOOK hhook, INT code, WPARAM wparam, LPARAM lparam ) LRESULT call_message_hooks( INT id, INT code, WPARAM wparam, LPARAM lparam, size_t lparam_size, size_t message_size, BOOL ansi ) { - struct user_thread_info *thread_info = get_user_thread_info(); struct win_hook_params info; WCHAR module[MAX_PATH]; DWORD_PTR ret; @@ -458,7 +454,6 @@ LRESULT call_message_hooks( INT id, INT code, WPARAM wparam, LPARAM lparam, size info.tid = reply->tid; info.proc = wine_server_get_ptr( reply->proc ); info.next_unicode = reply->unicode; - thread_info->active_hooks = reply->active_hooks; } } SERVER_END_REQ; @@ -526,7 +521,6 @@ HWINEVENTHOOK WINAPI NtUserSetWinEventHook( DWORD event_min, DWORD event_max, HM if (!wine_server_call_err( req )) { handle = wine_server_ptr_handle( reply->handle ); - get_user_thread_info()->active_hooks = reply->active_hooks; } } SERVER_END_REQ; @@ -547,7 +541,6 @@ BOOL WINAPI NtUserUnhookWinEvent( HWINEVENTHOOK handle ) req->handle = wine_server_user_handle( handle ); req->id = WH_WINEVENT; ret = !wine_server_call_err( req ); - if (ret) get_user_thread_info()->active_hooks = reply->active_hooks; } SERVER_END_REQ; return ret; @@ -558,7 +551,6 @@ BOOL WINAPI NtUserUnhookWinEvent( HWINEVENTHOOK handle ) */ void WINAPI NtUserNotifyWinEvent( DWORD event, HWND hwnd, LONG object_id, LONG child_id ) { - struct user_thread_info *thread_info = get_user_thread_info(); struct win_event_hook_params info; void *ret_ptr; ULONG ret_len; @@ -600,7 +592,6 @@ void WINAPI NtUserNotifyWinEvent( DWORD event, HWND hwnd, LONG object_id, LONG c info.module[wine_server_reply_size(req) / sizeof(WCHAR)] = 0; info.handle = wine_server_ptr_handle( reply->handle ); info.proc = wine_server_get_ptr( reply->proc ); - thread_info->active_hooks = reply->active_hooks; } } SERVER_END_REQ; diff --git a/dlls/win32u/message.c b/dlls/win32u/message.c index 43f6f19050e..ffa7b46427b 100644 --- a/dlls/win32u/message.c +++ b/dlls/win32u/message.c @@ -2698,7 +2698,6 @@ int peek_message( MSG *msg, const struct peek_message_filter *filter ) info.msg.pt.x = reply->x; info.msg.pt.y = reply->y; hw_id = 0; - thread_info->active_hooks = reply->active_hooks; } else buffer_size = reply->total; } diff --git a/dlls/win32u/ntuser_private.h b/dlls/win32u/ntuser_private.h index d95ea03d45f..44edadad8f8 100644 --- a/dlls/win32u/ntuser_private.h +++ b/dlls/win32u/ntuser_private.h @@ -114,7 +114,6 @@ struct user_thread_info WORD hook_call_depth; /* Number of recursively called hook procs */ WORD hook_unicode; /* Is current hook unicode? */ HHOOK hook; /* Current hook */ - UINT active_hooks; /* Bitmap of active hooks */ struct received_message_info *receive_info; /* Message being currently received */ struct imm_thread_data *imm_thread_data; /* IMM thread data */ HKL kbd_layout; /* Current keyboard layout */
From: Rémi Bernon rbernon@codeweavers.com
--- server/hook.c | 6 +++--- server/protocol.def | 4 ---- server/queue.c | 9 +++------ server/user.h | 2 +- 4 files changed, 7 insertions(+), 14 deletions(-)
diff --git a/server/hook.c b/server/hook.c index aff3a5b12b6..37d3427108d 100644 --- a/server/hook.c +++ b/server/hook.c @@ -463,7 +463,7 @@ DECL_HANDLER(set_hook) hook->module = module; hook->module_size = module_size; reply->handle = hook->handle; - reply->active_hooks = set_queue_active_hooks( current ); + set_queue_active_hooks( current ); } else free( module );
@@ -501,7 +501,7 @@ DECL_HANDLER(remove_hook) } } remove_hook( hook ); - reply->active_hooks = set_queue_active_hooks( current ); + set_queue_active_hooks( current ); }
@@ -518,7 +518,7 @@ DECL_HANDLER(start_hook_chain) return; }
- reply->active_hooks = set_queue_active_hooks( current ); + set_queue_active_hooks( current );
if (!table || !(hook = get_first_valid_hook( table, req->id - WH_MINHOOK, req->event, req->window, req->object_id, req->child_id ))) diff --git a/server/protocol.def b/server/protocol.def index c20137a05f1..1ed11f0c4fe 100644 --- a/server/protocol.def +++ b/server/protocol.def @@ -2225,7 +2225,6 @@ enum message_type int x; /* message x position */ int y; /* message y position */ unsigned int time; /* message time */ - unsigned int active_hooks; /* active hooks bitmap */ data_size_t total; /* total size of extra data */ VARARG(data,message_data); /* message data for sent messages */ @END @@ -3029,7 +3028,6 @@ enum caret_state VARARG(module,unicode_str); /* module name */ @REPLY user_handle_t handle; /* handle to the hook */ - unsigned int active_hooks; /* active hooks bitmap */ @END
@@ -3039,7 +3037,6 @@ enum caret_state client_ptr_t proc; /* hook procedure if handle is 0 */ int id; /* id of the hook if handle is 0 */ @REPLY - unsigned int active_hooks; /* active hooks bitmap */ @END
@@ -3056,7 +3053,6 @@ enum caret_state thread_id_t tid; /* thread id for low-level keyboard/mouse hooks */ int unicode; /* is it a unicode hook? */ client_ptr_t proc; /* hook procedure */ - unsigned int active_hooks; /* active hooks bitmap */ VARARG(module,unicode_str); /* module name */ @END
diff --git a/server/queue.c b/server/queue.c index cd6ab1bccdc..1a27ee9c21f 100644 --- a/server/queue.c +++ b/server/queue.c @@ -633,20 +633,17 @@ void set_queue_hooks( struct thread *thread, struct hook_table *hooks ) }
/* update the thread message queue active hooks bitmap */ -unsigned int set_queue_active_hooks( struct thread *thread ) +void set_queue_active_hooks( struct thread *thread ) { - unsigned int active_hooks = get_active_hooks(); - if (thread->queue) { + unsigned int active_hooks = get_active_hooks(); SHARED_WRITE_BEGIN( thread->queue->shared, queue_shm_t ) { shared->active_hooks = active_hooks; } SHARED_WRITE_END; } - - return active_hooks; }
/* check the queue status */ @@ -3110,7 +3107,7 @@ DECL_HANDLER(get_message) user_handle_t get_win = get_user_full_handle( req->get_win ); unsigned int filter = req->flags >> 16;
- reply->active_hooks = set_queue_active_hooks( current ); + set_queue_active_hooks( current );
if (get_win && get_win != 1 && get_win != -1 && !get_user_object( get_win, USER_WINDOW )) { diff --git a/server/user.h b/server/user.h index 3d7dcce6e13..618830e0bb0 100644 --- a/server/user.h +++ b/server/user.h @@ -114,7 +114,7 @@ extern struct thread *get_first_global_hook( struct desktop *desktop, int id ); extern void free_msg_queue( struct thread *thread ); extern struct hook_table *get_queue_hooks( struct thread *thread ); extern void set_queue_hooks( struct thread *thread, struct hook_table *hooks ); -extern unsigned int set_queue_active_hooks( struct thread *thread ); +extern void set_queue_active_hooks( struct thread *thread ); extern void inc_queue_paint_count( struct thread *thread, int incr ); extern void queue_cleanup_window( struct thread *thread, user_handle_t win ); extern int init_thread_queue( struct thread *thread );
uiautomation failures might be related, I'll have a look.
Tested MR, it works fine. LGTM