Module: wine Branch: master Commit: ae5a02e808f6d8fbbb182e556c76827cf9f804db URL: https://gitlab.winehq.org/wine/wine/-/commit/ae5a02e808f6d8fbbb182e556c76827...
Author: Rémi Bernon rbernon@codeweavers.com Date: Mon Jun 24 23:35:06 2024 +0200
server: Update the active hooks bitmaps when hooks are added / removed.
---
include/wine/server_protocol.h | 4 +-- server/hook.c | 70 ++++++++++++++++++++++++------------------ server/protocol.def | 2 +- server/queue.c | 42 +++++++++++++++++++++++++ server/user.h | 2 ++ server/winstation.c | 2 ++ 6 files changed, 89 insertions(+), 33 deletions(-)
diff --git a/include/wine/server_protocol.h b/include/wine/server_protocol.h index b8a4878c7d5..b39be73443c 100644 --- a/include/wine/server_protocol.h +++ b/include/wine/server_protocol.h @@ -899,7 +899,7 @@ typedef volatile struct
typedef volatile struct { - int placeholder; + int hooks_count[WH_MAX - WH_MIN + 2]; } queue_shm_t;
typedef volatile union @@ -6575,7 +6575,7 @@ union generic_reply
/* ### protocol_version begin ### */
-#define SERVER_PROTOCOL_VERSION 816 +#define SERVER_PROTOCOL_VERSION 817
/* ### protocol_version end ### */
diff --git a/server/hook.c b/server/hook.c index ed5ab7f5938..3047f52492d 100644 --- a/server/hook.c +++ b/server/hook.c @@ -173,6 +173,15 @@ static struct hook *add_hook( struct desktop *desktop, struct process *process, hook->module_size = module_size; list_add_head( &table->hooks[index], &hook->chain ); if (thread) thread->desktop_users++; + + if (!global) + add_queue_hook_count( hook->thread, index, 1 ); + else LIST_FOR_EACH_ENTRY( thread, &desktop->threads, struct thread, desktop_entry ) + { + if (!run_hook_in_thread( hook, thread )) continue; + add_queue_hook_count( thread, index, 1 ); + } + return hook; }
@@ -315,12 +324,43 @@ static void hook_table_destroy( struct object *obj ) /* remove a hook, freeing it if the chain is not in use */ static void remove_hook( struct hook *hook ) { + struct desktop *desktop = hook->desktop; + int global = hook->table == desktop->global_hooks; + struct thread *thread; + + if (!global) + add_queue_hook_count( hook->thread, hook->index, -1 ); + else LIST_FOR_EACH_ENTRY( thread, &desktop->threads, struct thread, desktop_entry ) + { + if (!run_hook_in_thread( hook, thread )) continue; + add_queue_hook_count( thread, hook->index, -1 ); + } + if (hook->table->counts[hook->index]) hook->proc = 0; /* chain is in use, just mark it and return */ else free_hook( hook ); }
+/* update the thread message queue hooks counters from the desktop global hooks */ +void add_desktop_hook_count( struct desktop *desktop, struct thread *thread, int count ) +{ + struct hook_table *table; + struct hook *hook; + int index; + + if (!(table = desktop->global_hooks)) return; + + for (index = 0; index < ARRAY_SIZE(table->hooks); index++) + { + LIST_FOR_EACH_ENTRY( hook, &table->hooks[index], struct hook, chain ) + { + if (!run_hook_in_thread( hook, thread )) continue; + add_queue_hook_count( thread, hook->index, count ); + } + } +} + /* release a hook chain, removing deleted hooks if the use count drops to 0 */ static void release_hook_chain( struct hook_table *table, int index ) { @@ -362,36 +402,6 @@ void remove_thread_hooks( struct thread *thread ) } }
-/* get a bitmap of active hooks in a hook table */ -static int is_hook_active( struct hook_table *table, int index ) -{ - struct hook *hook = get_first_hook( table, index ); - - while (hook) - { - if (hook->proc && run_hook_in_current_thread( hook )) return 1; - hook = HOOK_ENTRY( list_next( &table->hooks[index], &hook->chain ) ); - } - return 0; -} - -/* get a bitmap of all active hooks for the current thread */ -unsigned int get_active_hooks(void) -{ - struct hook_table *table = get_queue_hooks( current ); - struct hook_table *global_hooks = get_global_hooks( current ); - unsigned int ret = 1u << 31; /* set high bit to indicate that the bitmap is valid */ - int id; - - for (id = WH_MINHOOK; id <= WH_WINEVENT; id++) - { - if ((table && is_hook_active( table, id - WH_MINHOOK )) || - (global_hooks && is_hook_active( global_hooks, id - WH_MINHOOK ))) - ret |= 1 << (id - WH_MINHOOK); - } - return ret; -} - /* return the thread that owns the first global hook */ struct thread *get_first_global_hook( struct desktop *desktop, int id ) { diff --git a/server/protocol.def b/server/protocol.def index 97b4805c552..12c27a8e3e1 100644 --- a/server/protocol.def +++ b/server/protocol.def @@ -915,7 +915,7 @@ typedef volatile struct
typedef volatile struct { - int placeholder; + int hooks_count[WH_MAX - WH_MIN + 2]; /* active hooks count */ } queue_shm_t;
typedef volatile union diff --git a/server/queue.c b/server/queue.c index 5f4e5fa33c2..6d9c9f20a5f 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; + struct desktop *desktop; int i;
if (!input) @@ -328,7 +329,19 @@ static struct msg_queue *create_msg_queue( struct thread *thread, struct thread_ return NULL; }
+ SHARED_WRITE_BEGIN( queue->shared, queue_shm_t ) + { + memset( (void *)shared->hooks_count, 0, sizeof(shared->hooks_count) ); + } + SHARED_WRITE_END; + thread->queue = queue; + + if ((desktop = get_thread_desktop( thread, 0 ))) + { + add_desktop_hook_count( desktop, thread, 1 ); + release_object( desktop ); + } } if (new_input) release_object( new_input ); return queue; @@ -612,6 +625,35 @@ void set_queue_hooks( struct thread *thread, struct hook_table *hooks ) queue->hooks = hooks; }
+/* get the thread message queue active hooks bitmap */ +unsigned int get_active_hooks(void) +{ + unsigned int ret = 1u << 31; /* set high bit to indicate that the bitmap is valid */ + struct msg_queue *queue; + int bit; + + if (!(queue = current->queue)) return ret; + + for (bit = 0; bit < ARRAY_SIZE(queue->shared->hooks_count); bit++) + if (queue->shared->hooks_count[bit]) ret |= 1 << bit; + + return ret; +} + +/* update the thread message queue hooks counters */ +void add_queue_hook_count( struct thread *thread, unsigned int index, int count ) +{ + if (!thread->queue) return; + + SHARED_WRITE_BEGIN( thread->queue->shared, queue_shm_t ) + { + shared->hooks_count[index] += count; + } + SHARED_WRITE_END; + + assert( thread->queue->shared->hooks_count[index] >= 0 ); +} + /* check the queue status */ static inline int is_signaled( struct msg_queue *queue ) { diff --git a/server/user.h b/server/user.h index 99491293a7c..4633c7dae7f 100644 --- a/server/user.h +++ b/server/user.h @@ -108,12 +108,14 @@ extern void cleanup_clipboard_thread( struct thread *thread ); extern void remove_thread_hooks( struct thread *thread ); extern unsigned int get_active_hooks(void); extern struct thread *get_first_global_hook( struct desktop *desktop, int id ); +extern void add_desktop_hook_count( struct desktop *desktop, struct thread *thread, int count );
/* queue functions */
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 void add_queue_hook_count( struct thread *thread, unsigned int index, int count ); 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 ); diff --git a/server/winstation.c b/server/winstation.c index 45c7defa1f7..75b604ae1c3 100644 --- a/server/winstation.c +++ b/server/winstation.c @@ -410,6 +410,7 @@ static void close_desktop_timeout( void *private ) static void add_desktop_thread( struct desktop *desktop, struct thread *thread ) { list_add_tail( &desktop->threads, &thread->desktop_entry ); + add_desktop_hook_count( desktop, thread, 1 );
if (!thread->process->is_system) { @@ -441,6 +442,7 @@ static void remove_desktop_user( struct desktop *desktop, struct thread *thread /* remove a thread from the list of threads attached to a desktop */ static void remove_desktop_thread( struct desktop *desktop, struct thread *thread ) { + add_desktop_hook_count( desktop, thread, -1 ); list_remove( &thread->desktop_entry );
if (!thread->process->is_system) remove_desktop_user( desktop, thread );