[PATCH v17 0/7] MR7610: win32u: Create a shared object for user handle entries.
For https://gitlab.winehq.org/wine/wine/-/merge_requests/7512 to use it to locate window shared objects. -- v17: win32u: Use the session shared object for user handle entries. win32u: Use the session shared object to implement is_window. server: Move the user object handle table to the shared memory. server: Allocate a session shared memory header structure. server: Use NTUSER_OBJ constants for user object types. server: Remove const qualifier from shared memory pointers. include: Implement ReadAcquire64. https://gitlab.winehq.org/wine/wine/-/merge_requests/7610
From: Rémi Bernon <rbernon(a)codeweavers.com> --- server/file.h | 11 +++--- server/mapping.c | 8 ++-- server/queue.c | 98 ++++++++++++++++++++++++------------------------ server/user.h | 2 +- 4 files changed, 59 insertions(+), 60 deletions(-) diff --git a/server/file.h b/server/file.h index 59b73c0245c..8fc82a460ff 100644 --- a/server/file.h +++ b/server/file.h @@ -193,15 +193,14 @@ extern struct mapping *create_session_mapping( struct object *root, const struct unsigned int attr, const struct security_descriptor *sd ); extern void set_session_mapping( struct mapping *mapping ); -extern const volatile void *alloc_shared_object(void); -extern void free_shared_object( const volatile void *object_shm ); -extern void invalidate_shared_object( const volatile void *object_shm ); -extern struct obj_locator get_shared_object_locator( const volatile void *object_shm ); +extern volatile void *alloc_shared_object(void); +extern void free_shared_object( volatile void *object_shm ); +extern void invalidate_shared_object( volatile void *object_shm ); +extern struct obj_locator get_shared_object_locator( volatile void *object_shm ); #define SHARED_WRITE_BEGIN( object_shm, type ) \ do { \ - const type *__shared = (object_shm); \ - type *shared = (type *)__shared; \ + type *shared = (object_shm); \ shared_object_t *__obj = CONTAINING_RECORD( shared, shared_object_t, shm ); \ LONG64 __seq = __obj->seq + 1, __end = __seq + 1; \ assert( (__seq & 1) != 0 ); \ diff --git a/server/mapping.c b/server/mapping.c index 247b28cf6f5..a74573efe0e 100644 --- a/server/mapping.c +++ b/server/mapping.c @@ -1375,7 +1375,7 @@ static struct session_block *find_free_session_block( mem_size_t size ) return grow_session_mapping( size ); } -const volatile void *alloc_shared_object(void) +volatile void *alloc_shared_object(void) { struct session_object *object; struct list *ptr; @@ -1407,7 +1407,7 @@ const volatile void *alloc_shared_object(void) return &object->obj.shm; } -void free_shared_object( const volatile void *object_shm ) +void free_shared_object( volatile void *object_shm ) { struct session_object *object = CONTAINING_RECORD( object_shm, struct session_object, obj.shm ); @@ -1422,7 +1422,7 @@ void free_shared_object( const volatile void *object_shm ) } /* invalidate client caches for a shared object by giving it a new id */ -void invalidate_shared_object( const volatile void *object_shm ) +void invalidate_shared_object( volatile void *object_shm ) { struct session_object *object = CONTAINING_RECORD( object_shm, struct session_object, obj.shm ); @@ -1433,7 +1433,7 @@ void invalidate_shared_object( const volatile void *object_shm ) SHARED_WRITE_END; } -struct obj_locator get_shared_object_locator( const volatile void *object_shm ) +struct obj_locator get_shared_object_locator( volatile void *object_shm ) { struct session_object *object = CONTAINING_RECORD( object_shm, struct session_object, obj.shm ); struct obj_locator locator = {.offset = object->offset, .id = object->obj.id}; diff --git a/server/queue.c b/server/queue.c index b4b6069f927..cfbc9e6c89b 100644 --- a/server/queue.c +++ b/server/queue.c @@ -109,7 +109,7 @@ struct thread_input int caret_state; /* caret on/off state */ struct list msg_list; /* list of hardware messages */ unsigned char desktop_keystate[256]; /* desktop keystate when keystate was synced */ - const input_shm_t *shared; /* thread input in session shared memory */ + input_shm_t *shared; /* thread input in session shared memory */ }; struct msg_queue @@ -133,7 +133,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 */ + queue_shm_t *shared; /* queue in session shared memory */ }; struct hotkey @@ -359,8 +359,8 @@ void free_msg_queue( struct thread *thread ) /* synchronize thread input keystate with the desktop */ static void sync_input_keystate( struct thread_input *input ) { - const input_shm_t *input_shm = input->shared; - const desktop_shm_t *desktop_shm; + input_shm_t *input_shm = input->shared; + desktop_shm_t *desktop_shm; int i; if (!input->desktop || input_shm->keystate_lock) return; @@ -380,7 +380,7 @@ static void sync_input_keystate( struct thread_input *input ) /* locks thread input keystate to prevent synchronization */ static void lock_input_keystate( struct thread_input *input ) { - const input_shm_t *input_shm = input->shared; + input_shm_t *input_shm = input->shared; SHARED_WRITE_BEGIN( input_shm, input_shm_t ) { @@ -392,7 +392,7 @@ static void lock_input_keystate( struct thread_input *input ) /* unlock the thread input keystate and synchronize it again */ static void unlock_input_keystate( struct thread_input *input ) { - const input_shm_t *input_shm = input->shared; + input_shm_t *input_shm = input->shared; SHARED_WRITE_BEGIN( input_shm, input_shm_t ) { @@ -407,7 +407,7 @@ static void unlock_input_keystate( struct thread_input *input ) static int assign_thread_input( struct thread *thread, struct thread_input *new_input ) { struct msg_queue *queue = thread->queue; - const input_shm_t *input_shm; + input_shm_t *input_shm; if (!queue) { @@ -471,7 +471,7 @@ static struct message *alloc_hardware_message( lparam_t info, struct hw_msg_sour static int is_cursor_clipped( struct desktop *desktop ) { - const desktop_shm_t *desktop_shm = desktop->shared; + desktop_shm_t *desktop_shm = desktop->shared; struct rectangle top_rect, clip_rect = desktop_shm->cursor.clip; get_virtual_screen_rect( desktop, &top_rect, 1 ); return !is_rect_equal( &clip_rect, &top_rect ); @@ -481,7 +481,7 @@ static void queue_cursor_message( struct desktop *desktop, user_handle_t win, un lparam_t wparam, lparam_t lparam ) { static const struct hw_msg_source source = { IMDT_UNAVAILABLE, IMO_SYSTEM }; - const desktop_shm_t *desktop_shm = desktop->shared; + desktop_shm_t *desktop_shm = desktop->shared; struct thread_input *input; struct message *msg; @@ -518,7 +518,7 @@ static int update_desktop_cursor_window( struct desktop *desktop, user_handle_t if (updated && (input = get_desktop_cursor_thread_input( desktop ))) { - const input_shm_t *input_shm = input->shared; + input_shm_t *input_shm = input->shared; user_handle_t handle = input_shm->cursor_count < 0 ? 0 : input_shm->cursor; /* when clipping send the message to the foreground window as well, as some driver have an artificial overlay window */ if (is_cursor_clipped( desktop )) queue_cursor_message( desktop, 0, WM_WINE_SETCURSOR, win, handle ); @@ -530,7 +530,7 @@ static int update_desktop_cursor_window( struct desktop *desktop, user_handle_t static int update_desktop_cursor_pos( struct desktop *desktop, user_handle_t win, int x, int y ) { - const desktop_shm_t *desktop_shm = desktop->shared; + desktop_shm_t *desktop_shm = desktop->shared; int updated; unsigned int time = get_tick_count(); @@ -588,7 +588,7 @@ static void set_cursor_pos( struct desktop *desktop, int x, int y ) /* sync cursor position after window change */ void update_cursor_pos( struct desktop *desktop ) { - const desktop_shm_t *desktop_shm; + desktop_shm_t *desktop_shm; desktop_shm = desktop->shared; set_cursor_pos( desktop, desktop_shm->cursor.x, desktop_shm->cursor.y ); @@ -598,7 +598,7 @@ void update_cursor_pos( struct desktop *desktop ) static void get_message_defaults( struct msg_queue *queue, int *x, int *y, unsigned int *time ) { struct desktop *desktop = queue->input->desktop; - const desktop_shm_t *desktop_shm = desktop->shared; + desktop_shm_t *desktop_shm = desktop->shared; *x = desktop_shm->cursor.x; *y = desktop_shm->cursor.y; @@ -608,7 +608,7 @@ static void get_message_defaults( struct msg_queue *queue, int *x, int *y, unsig /* set the cursor clip rectangle */ void set_clip_rectangle( struct desktop *desktop, const struct rectangle *rect, unsigned int flags, int reset ) { - const desktop_shm_t *desktop_shm = desktop->shared; + desktop_shm_t *desktop_shm = desktop->shared; struct rectangle top_rect, new_rect; unsigned int old_flags; int x, y; @@ -650,7 +650,7 @@ void set_clip_rectangle( struct desktop *desktop, const struct rectangle *rect, /* change the foreground input and reset the cursor clip rect */ static void set_foreground_input( struct desktop *desktop, struct thread_input *input ) { - const input_shm_t *input_shm, *old_input_shm; + input_shm_t *input_shm, *old_input_shm; shared_object_t dummy_obj = {0}; if (desktop->foreground_input == input) return; @@ -706,7 +706,7 @@ void add_queue_hook_count( struct thread *thread, unsigned int index, int count /* check the queue status */ static inline int is_signaled( struct msg_queue *queue ) { - const queue_shm_t *queue_shm = queue->shared; + queue_shm_t *queue_shm = queue->shared; return (queue_shm->wake_bits & queue_shm->wake_mask) || (queue_shm->changed_bits & queue_shm->changed_mask); } @@ -714,7 +714,7 @@ static inline int is_signaled( struct msg_queue *queue ) /* set some queue bits */ static inline void set_queue_bits( struct msg_queue *queue, unsigned int bits ) { - const queue_shm_t *queue_shm = queue->shared; + queue_shm_t *queue_shm = queue->shared; if (bits & (QS_KEY | QS_MOUSEBUTTON)) { @@ -735,7 +735,7 @@ static inline void set_queue_bits( struct msg_queue *queue, unsigned int bits ) /* clear some queue bits */ static inline void clear_queue_bits( struct msg_queue *queue, unsigned int bits ) { - const queue_shm_t *queue_shm = queue->shared; + queue_shm_t *queue_shm = queue->shared; SHARED_WRITE_BEGIN( queue_shm, queue_shm_t ) { @@ -1300,7 +1300,7 @@ static void msg_queue_remove_queue(struct object *obj, struct wait_queue_entry * static void msg_queue_dump( struct object *obj, int verbose ) { struct msg_queue *queue = (struct msg_queue *)obj; - const queue_shm_t *queue_shm = queue->shared; + queue_shm_t *queue_shm = queue->shared; fprintf( stderr, "Msg queue bits=%x mask=%x\n", queue_shm->wake_bits, queue_shm->wake_mask ); } @@ -1325,7 +1325,7 @@ static int msg_queue_signaled( struct object *obj, struct wait_queue_entry *entr static void msg_queue_satisfied( struct object *obj, struct wait_queue_entry *entry ) { struct msg_queue *queue = (struct msg_queue *)obj; - const queue_shm_t *queue_shm = queue->shared; + queue_shm_t *queue_shm = queue->shared; SHARED_WRITE_BEGIN( queue_shm, queue_shm_t ) { @@ -1340,7 +1340,7 @@ static void msg_queue_destroy( struct object *obj ) struct msg_queue *queue = (struct msg_queue *)obj; struct list *ptr; struct hotkey *hotkey, *hotkey2; - const input_shm_t *input_shm = queue->input->shared; + input_shm_t *input_shm = queue->input->shared; int i; cleanup_results( queue ); @@ -1393,7 +1393,7 @@ static void msg_queue_poll_event( struct fd *fd, int event ) static void thread_input_dump( struct object *obj, int verbose ) { struct thread_input *input = (struct thread_input *)obj; - const input_shm_t *input_shm = input->shared; + input_shm_t *input_shm = input->shared; fprintf( stderr, "Thread input focus=%08x capture=%08x active=%08x\n", input_shm->focus, input_shm->capture, input_shm->active ); } @@ -1416,7 +1416,7 @@ static void thread_input_destroy( struct object *obj ) static inline void thread_input_cleanup_window( struct msg_queue *queue, user_handle_t window ) { struct thread_input *input = queue->input; - const input_shm_t *input_shm = input->shared; + input_shm_t *input_shm = input->shared; SHARED_WRITE_BEGIN( input_shm, input_shm_t ) { @@ -1454,7 +1454,7 @@ static int check_queue_input_window( struct msg_queue *queue, user_handle_t wind void check_thread_queue_idle( struct thread *thread ) { struct msg_queue *queue = thread->queue; - const queue_shm_t *queue_shm = queue->shared; + queue_shm_t *queue_shm = queue->shared; if ((queue_shm->wake_mask & QS_SMRESULT)) return; if (thread->process->idle_event) set_event( thread->process->idle_event ); @@ -1488,7 +1488,7 @@ int attach_thread_input( struct thread *thread_from, struct thread *thread_to ) if (thread_from->queue) { - const input_shm_t *old_input_shm, *input_shm; + input_shm_t *old_input_shm, *input_shm; old_input = thread_from->queue->input; old_input_shm = old_input->shared; input_shm = input->shared; @@ -1504,7 +1504,7 @@ int attach_thread_input( struct thread *thread_from, struct thread *thread_to ) ret = assign_thread_input( thread_from, input ); if (ret) { - const input_shm_t *input_shm = input->shared; + input_shm_t *input_shm = input->shared; SHARED_WRITE_BEGIN( input_shm, input_shm_t ) { memset( (void *)shared->keystate, 0, sizeof(shared->keystate) ); @@ -1523,7 +1523,7 @@ void detach_thread_input( struct thread *thread_from ) if ((input = create_thread_input( thread_from ))) { - const input_shm_t *old_input_shm, *input_shm; + input_shm_t *old_input_shm, *input_shm; old_input_shm = old_input->shared; input_shm = input->shared; @@ -1767,7 +1767,7 @@ static void update_key_state( volatile unsigned char *keystate, unsigned int msg static void update_thread_input_key_state( struct thread_input *input, unsigned int msg, lparam_t wparam ) { - const input_shm_t *input_shm = input->shared; + input_shm_t *input_shm = input->shared; SHARED_WRITE_BEGIN( input_shm, input_shm_t ) { update_key_state( shared->keystate, msg, wparam, 0 ); @@ -1816,7 +1816,7 @@ static void release_hardware_message( struct msg_queue *queue, unsigned int hw_i static int queue_hotkey_message( struct desktop *desktop, struct message *msg ) { - const desktop_shm_t *desktop_shm = desktop->shared; + desktop_shm_t *desktop_shm = desktop->shared; struct hotkey *hotkey; unsigned int modifiers = 0; @@ -1857,7 +1857,7 @@ static user_handle_t find_hardware_message_window( struct desktop *desktop, stru struct message *msg, unsigned int *msg_code, struct thread **thread ) { - const input_shm_t *input_shm = input ? input->shared : NULL; + input_shm_t *input_shm = input ? input->shared : NULL; user_handle_t win = 0; *thread = NULL; @@ -1930,7 +1930,7 @@ static unsigned int get_rawinput_device_flags( struct process *process, struct m /* queue a hardware message into a given thread input */ static void queue_hardware_message( struct desktop *desktop, struct message *msg, int always_queue ) { - const desktop_shm_t *desktop_shm = desktop->shared; + desktop_shm_t *desktop_shm = desktop->shared; user_handle_t win; struct thread *thread; struct thread_input *input; @@ -2042,7 +2042,7 @@ static struct thread *get_foreground_thread( struct desktop *desktop, user_handl /* if desktop has no foreground process, assume the receiving window is */ if (desktop->foreground_input) { - const input_shm_t *input_shm = desktop->foreground_input->shared; + input_shm_t *input_shm = desktop->foreground_input->shared; return get_window_thread( input_shm->focus ); } if (window) return get_window_thread( window ); @@ -2247,7 +2247,7 @@ static void dispatch_rawinput_message( struct desktop *desktop, struct rawinput_ static int queue_mouse_message( struct desktop *desktop, user_handle_t win, const union hw_input *input, unsigned int origin, struct msg_queue *sender ) { - const desktop_shm_t *desktop_shm = desktop->shared; + desktop_shm_t *desktop_shm = desktop->shared; struct hardware_msg_data *msg_data; struct rawinput_message raw_msg; struct message *msg; @@ -2372,7 +2372,7 @@ static void stop_key_repeat( struct desktop *desktop ) static int queue_keyboard_message( struct desktop *desktop, user_handle_t win, const union hw_input *input, unsigned int origin, struct msg_queue *sender, int repeat ) { - const desktop_shm_t *desktop_shm = desktop->shared; + desktop_shm_t *desktop_shm = desktop->shared; struct hw_msg_source source = { IMDT_KEYBOARD, origin }; struct hardware_msg_data *msg_data; struct message *msg; @@ -2563,7 +2563,7 @@ static void queue_pointer_message( struct pointer *pointer, int repeated ) }; struct hw_msg_source source = { IMDT_UNAVAILABLE, IMDT_TOUCH }; struct desktop *desktop = pointer->desktop; - const desktop_shm_t *desktop_shm = desktop->shared; + desktop_shm_t *desktop_shm = desktop->shared; const union hw_input *input = &pointer->input; unsigned int i, wparam = input->hw.wparam; timeout_t time = get_tick_count(); @@ -2642,7 +2642,7 @@ static struct pointer *find_pointer_from_id( struct desktop *desktop, unsigned i static void queue_custom_hardware_message( struct desktop *desktop, user_handle_t win, unsigned int origin, const union hw_input *input ) { - const desktop_shm_t *desktop_shm = desktop->shared; + desktop_shm_t *desktop_shm = desktop->shared; struct hw_msg_source source = { IMDT_UNAVAILABLE, origin }; struct thread *foreground; struct pointer *pointer; @@ -3140,7 +3140,7 @@ DECL_HANDLER(set_queue_mask) if (queue) { - const queue_shm_t *queue_shm = queue->shared; + queue_shm_t *queue_shm = queue->shared; SHARED_WRITE_BEGIN( queue_shm, queue_shm_t ) { @@ -3176,7 +3176,7 @@ DECL_HANDLER(get_queue_status) struct msg_queue *queue = current->queue; if (queue) { - const queue_shm_t *queue_shm = queue->shared; + queue_shm_t *queue_shm = queue->shared; reply->wake_bits = queue_shm->wake_bits; reply->changed_bits = queue_shm->changed_bits; @@ -3277,7 +3277,7 @@ DECL_HANDLER(send_hardware_message) struct desktop *desktop; unsigned int origin = (req->flags & SEND_HWMSG_INJECTED ? IMO_INJECTED : IMO_HARDWARE); struct msg_queue *sender = req->flags & SEND_HWMSG_INJECTED ? get_current_queue() : NULL; - const desktop_shm_t *desktop_shm; + desktop_shm_t *desktop_shm; int wait = 0; if (!(desktop = get_hardware_input_desktop( req->win ))) return; @@ -3334,7 +3334,7 @@ DECL_HANDLER(get_message) struct list *ptr; struct msg_queue *queue = get_current_queue(); user_handle_t get_win = get_user_full_handle( req->get_win ); - const queue_shm_t *queue_shm; + queue_shm_t *queue_shm; unsigned int filter; if (get_win && get_win != 1 && get_win != -1 && !get_user_object( get_win, USER_WINDOW )) @@ -3804,7 +3804,7 @@ DECL_HANDLER(get_key_state) else { struct msg_queue *queue = get_current_queue(); - const input_shm_t *input_shm = queue->input->shared; + input_shm_t *input_shm = queue->input->shared; unsigned char *keystate = (void *)input_shm->keystate; sync_input_keystate( queue->input ); reply->state = keystate[req->key & 0xff]; @@ -3818,7 +3818,7 @@ DECL_HANDLER(set_key_state) struct msg_queue *queue = get_current_queue(); struct desktop *desktop = queue->input->desktop; data_size_t size = min( 256, get_req_data_size() ); - const input_shm_t *input_shm = queue->input->shared; + input_shm_t *input_shm = queue->input->shared; SHARED_WRITE_BEGIN( input_shm, input_shm_t ) { @@ -3879,7 +3879,7 @@ DECL_HANDLER(set_focus_window) reply->previous = 0; if (queue && check_queue_input_window( queue, req->handle )) { - const input_shm_t *input_shm = queue->input->shared; + input_shm_t *input_shm = queue->input->shared; SHARED_WRITE_BEGIN( input_shm, input_shm_t ) { reply->previous = shared->focus; @@ -3900,7 +3900,7 @@ DECL_HANDLER(set_active_window) { if (!req->handle || make_window_active( req->handle )) { - const input_shm_t *input_shm = queue->input->shared; + input_shm_t *input_shm = queue->input->shared; SHARED_WRITE_BEGIN( input_shm, input_shm_t ) { reply->previous = shared->active; @@ -3922,7 +3922,7 @@ DECL_HANDLER(set_capture_window) if (queue && check_queue_input_window( queue, req->handle )) { struct thread_input *input = queue->input; - const input_shm_t *input_shm = input->shared; + input_shm_t *input_shm = input->shared; /* if in menu mode, reject all requests to change focus, except if the menu bit is set */ if (input_shm->menu_owner && !(req->flags & CAPTURE_MENU)) @@ -3954,7 +3954,7 @@ DECL_HANDLER(set_caret_window) if (queue && check_queue_input_window( queue, req->handle )) { struct thread_input *input = queue->input; - const input_shm_t *input_shm = input->shared; + input_shm_t *input_shm = input->shared; user_handle_t caret = get_user_full_handle(req->handle); reply->previous = input_shm->caret; @@ -3977,7 +3977,7 @@ DECL_HANDLER(set_caret_window) DECL_HANDLER(set_caret_info) { struct msg_queue *queue = get_current_queue(); - const input_shm_t *input_shm; + input_shm_t *input_shm; struct thread_input *input; if (!queue) return; @@ -4036,9 +4036,9 @@ DECL_HANDLER(set_cursor) struct msg_queue *queue = get_current_queue(); user_handle_t prev_cursor, new_cursor; struct thread_input *input; - const input_shm_t *input_shm; + input_shm_t *input_shm; struct desktop *desktop; - const desktop_shm_t *desktop_shm; + desktop_shm_t *desktop_shm; if (!queue) return; input = queue->input; diff --git a/server/user.h b/server/user.h index ce463b9395d..3040dffee75 100644 --- a/server/user.h +++ b/server/user.h @@ -94,7 +94,7 @@ struct desktop struct key_repeat key_repeat; /* key auto-repeat */ unsigned int clip_flags; /* last cursor clip flags */ user_handle_t cursor_win; /* window that contains the cursor */ - const desktop_shm_t *shared; /* desktop session shared memory */ + desktop_shm_t *shared; /* desktop session shared memory */ }; /* user handles functions */ -- GitLab https://gitlab.winehq.org/wine/wine/-/merge_requests/7610
From: Rémi Bernon <rbernon(a)codeweavers.com> --- dlls/win32u/ntuser_private.h | 8 ++++---- dlls/win32u/window.c | 10 ++++++---- server/hook.c | 6 +++--- server/protocol.def | 2 ++ server/queue.c | 4 ++-- server/user.c | 30 ++++++++++++++++++++++-------- server/user.h | 17 +++++------------ server/window.c | 24 ++++++++++++------------ 8 files changed, 56 insertions(+), 45 deletions(-) diff --git a/dlls/win32u/ntuser_private.h b/dlls/win32u/ntuser_private.h index fbc3c0d6d64..ae2a8b04d22 100644 --- a/dlls/win32u/ntuser_private.h +++ b/dlls/win32u/ntuser_private.h @@ -231,11 +231,11 @@ extern BOOL vulkan_init(void); extern void vulkan_detach_surfaces( struct list *surfaces ); /* window.c */ -HANDLE alloc_user_handle( struct user_object *ptr, unsigned int type ); -void *free_user_handle( HANDLE handle, unsigned int type ); -void *get_user_handle_ptr( HANDLE handle, unsigned int type ); +HANDLE alloc_user_handle( struct user_object *ptr, unsigned short type ); +void *free_user_handle( HANDLE handle, unsigned short type ); +void *get_user_handle_ptr( HANDLE handle, unsigned short type ); void release_user_handle_ptr( void *ptr ); -void *next_process_user_handle_ptr( HANDLE *handle, unsigned int type ); +void *next_process_user_handle_ptr( HANDLE *handle, unsigned short type ); UINT win_set_flags( HWND hwnd, UINT set_mask, UINT clear_mask ); static inline UINT win_get_flags( HWND hwnd ) diff --git a/dlls/win32u/window.c b/dlls/win32u/window.c index 9acb9350144..81396fb06d0 100644 --- a/dlls/win32u/window.c +++ b/dlls/win32u/window.c @@ -55,12 +55,13 @@ static void *user_handles[NB_USER_HANDLES]; /*********************************************************************** * alloc_user_handle */ -HANDLE alloc_user_handle( struct user_object *ptr, unsigned int type ) +HANDLE alloc_user_handle( struct user_object *ptr, unsigned short type ) { HANDLE handle = 0; SERVER_START_REQ( alloc_user_handle ) { + req->type = type; if (!wine_server_call_err( req )) handle = wine_server_ptr_handle( reply->handle ); } SERVER_END_REQ; @@ -80,7 +81,7 @@ HANDLE alloc_user_handle( struct user_object *ptr, unsigned int type ) /*********************************************************************** * get_user_handle_ptr */ -void *get_user_handle_ptr( HANDLE handle, unsigned int type ) +void *get_user_handle_ptr( HANDLE handle, unsigned short type ) { struct user_object *ptr; WORD index = USER_HANDLE_TO_INDEX( handle ); @@ -106,7 +107,7 @@ void *get_user_handle_ptr( HANDLE handle, unsigned int type ) * * user_lock must be held by caller. */ -void *next_process_user_handle_ptr( HANDLE *handle, unsigned int type ) +void *next_process_user_handle_ptr( HANDLE *handle, unsigned short type ) { struct user_object *ptr; WORD index = *handle ? USER_HANDLE_TO_INDEX( *handle ) + 1 : 0; @@ -143,7 +144,7 @@ void release_user_handle_ptr( void *ptr ) /*********************************************************************** * free_user_handle */ -void *free_user_handle( HANDLE handle, unsigned int type ) +void *free_user_handle( HANDLE handle, unsigned short type ) { struct user_object *ptr; WORD index = USER_HANDLE_TO_INDEX( handle ); @@ -152,6 +153,7 @@ void *free_user_handle( HANDLE handle, unsigned int type ) { SERVER_START_REQ( free_user_handle ) { + req->type = type; req->handle = wine_server_user_handle( handle ); if (wine_server_call( req )) ptr = NULL; else InterlockedCompareExchangePointer( &user_handles[index], NULL, ptr ); diff --git a/server/hook.c b/server/hook.c index ffe7206369e..bf2ad266e76 100644 --- a/server/hook.c +++ b/server/hook.c @@ -153,7 +153,7 @@ static struct hook *add_hook( struct desktop *desktop, struct process *process, } if (!(hook = mem_alloc( sizeof(*hook) ))) return NULL; - if (!(hook->handle = alloc_user_handle( hook, USER_HOOK ))) + if (!(hook->handle = alloc_user_handle( hook, NTUSER_OBJ_HOOK ))) { free( hook ); return NULL; @@ -502,7 +502,7 @@ DECL_HANDLER(remove_hook) if (req->handle) { - if (!(hook = get_user_object( req->handle, USER_HOOK ))) + if (!(hook = get_user_object( req->handle, NTUSER_OBJ_HOOK ))) { set_error( STATUS_INVALID_HANDLE ); return; @@ -589,7 +589,7 @@ DECL_HANDLER(get_hook_info) { struct hook *hook; - if (!(hook = get_user_object( req->handle, USER_HOOK ))) return; + if (!(hook = get_user_object( req->handle, NTUSER_OBJ_HOOK ))) return; if (hook->thread && (hook->thread != current)) { set_error( STATUS_INVALID_HANDLE ); diff --git a/server/protocol.def b/server/protocol.def index 8bfce724756..8ff35b6e401 100644 --- a/server/protocol.def +++ b/server/protocol.def @@ -3930,6 +3930,7 @@ struct handle_info /* Allocate an arbitrary user handle */ @REQ(alloc_user_handle) + unsigned short type; /* user object type */ @REPLY user_handle_t handle; /* allocated handle */ @END @@ -3937,6 +3938,7 @@ struct handle_info /* Free an arbitrary user handle */ @REQ(free_user_handle) + unsigned short type; /* user object type */ user_handle_t handle; /* handle to free*/ @END diff --git a/server/queue.c b/server/queue.c index cfbc9e6c89b..10c8b70f659 100644 --- a/server/queue.c +++ b/server/queue.c @@ -3337,7 +3337,7 @@ DECL_HANDLER(get_message) queue_shm_t *queue_shm; unsigned int filter; - if (get_win && get_win != 1 && get_win != -1 && !get_user_object( get_win, USER_WINDOW )) + if (get_win && get_win != 1 && get_win != -1 && !get_user_object( get_win, NTUSER_OBJ_WINDOW )) { set_win32_error( ERROR_INVALID_WINDOW_HANDLE ); return; @@ -4053,7 +4053,7 @@ DECL_HANDLER(set_cursor) reply->prev_y = desktop_shm->cursor.y; if ((req->flags & SET_CURSOR_HANDLE) && req->handle && - !get_user_object( req->handle, USER_CLIENT )) + !get_user_object( req->handle, NTUSER_OBJ_ICON )) { set_win32_error( ERROR_INVALID_CURSOR_HANDLE ); return; diff --git a/server/user.c b/server/user.c index 2d038a6ddbf..22d72c669e7 100644 --- a/server/user.c +++ b/server/user.c @@ -90,7 +90,7 @@ static inline void *free_user_entry( struct user_handle *ptr ) } /* allocate a user handle for a given object */ -user_handle_t alloc_user_handle( void *ptr, enum user_object type ) +user_handle_t alloc_user_handle( void *ptr, unsigned short type ) { struct user_handle *entry = alloc_user_entry(); if (!entry) return 0; @@ -101,7 +101,7 @@ user_handle_t alloc_user_handle( void *ptr, enum user_object type ) } /* return a pointer to a user object from its handle */ -void *get_user_object( user_handle_t handle, enum user_object type ) +void *get_user_object( user_handle_t handle, unsigned short type ) { struct user_handle *entry; @@ -120,7 +120,7 @@ user_handle_t get_user_full_handle( user_handle_t handle ) } /* same as get_user_object plus set the handle to the full 32-bit value */ -void *get_user_object_handle( user_handle_t *handle, enum user_object type ) +void *get_user_object_handle( user_handle_t *handle, unsigned short type ) { struct user_handle *entry; @@ -143,7 +143,7 @@ void *free_user_handle( user_handle_t handle ) } /* return the next user handle after 'handle' that is of a given type */ -void *next_user_handle( user_handle_t *handle, enum user_object type ) +void *next_user_handle( user_handle_t *handle, unsigned short type ) { struct user_handle *entry; @@ -172,14 +172,28 @@ void free_process_user_handles( struct process *process ) unsigned int i; for (i = 0; i < nb_handles; i++) - if (handles[i].type == USER_CLIENT && handles[i].ptr == process) - free_user_entry( &handles[i] ); + { + switch (handles[i].type) + { + case NTUSER_OBJ_MENU: + case NTUSER_OBJ_ICON: + case NTUSER_OBJ_WINPOS: + case NTUSER_OBJ_ACCEL: + case NTUSER_OBJ_IMC: + if (handles[i].ptr == process) free_user_entry( &handles[i] ); + break; + case NTUSER_OBJ_HOOK: + case NTUSER_OBJ_WINDOW: + default: + continue; + } + } } /* allocate an arbitrary user handle */ DECL_HANDLER(alloc_user_handle) { - reply->handle = alloc_user_handle( current->process, USER_CLIENT ); + reply->handle = alloc_user_handle( current->process, req->type ); } @@ -188,7 +202,7 @@ DECL_HANDLER(free_user_handle) { struct user_handle *entry; - if ((entry = handle_to_entry( req->handle )) && entry->type == USER_CLIENT) + if ((entry = handle_to_entry( req->handle )) && entry->type == req->type) free_user_entry( entry ); else set_error( STATUS_INVALID_HANDLE ); diff --git a/server/user.h b/server/user.h index 3040dffee75..23c2c338210 100644 --- a/server/user.h +++ b/server/user.h @@ -34,13 +34,6 @@ struct window_class; struct atom_table; struct clipboard; -enum user_object -{ - USER_WINDOW = 1, - USER_HOOK, - USER_CLIENT /* arbitrary client handle */ -}; - #define DESKTOP_ATOM ((atom_t)32769) #define MAX_USER_HANDLES ((LAST_USER_HANDLE - FIRST_USER_HANDLE + 1) >> 1) @@ -99,12 +92,12 @@ struct desktop /* user handles functions */ -extern user_handle_t alloc_user_handle( void *ptr, enum user_object type ); -extern void *get_user_object( user_handle_t handle, enum user_object type ); -extern void *get_user_object_handle( user_handle_t *handle, enum user_object type ); +extern user_handle_t alloc_user_handle( void *ptr, unsigned short type ); +extern void *get_user_object( user_handle_t handle, unsigned short type ); +extern void *get_user_object_handle( user_handle_t *handle, unsigned short type ); extern user_handle_t get_user_full_handle( user_handle_t handle ); extern void *free_user_handle( user_handle_t handle ); -extern void *next_user_handle( user_handle_t *handle, enum user_object type ); +extern void *next_user_handle( user_handle_t *handle, unsigned short type ); extern void free_process_user_handles( struct process *process ); /* clipboard functions */ @@ -314,7 +307,7 @@ static inline void union_rect( struct rectangle *dest, const struct rectangle *s /* validate a window handle and return the full handle */ static inline user_handle_t get_valid_window_handle( user_handle_t win ) { - if (get_user_object_handle( &win, USER_WINDOW )) return win; + if (get_user_object_handle( &win, NTUSER_OBJ_WINDOW )) return win; set_win32_error( ERROR_INVALID_WINDOW_HANDLE ); return 0; } diff --git a/server/window.c b/server/window.c index f7f9d5e517f..1eb815dfe3e 100644 --- a/server/window.c +++ b/server/window.c @@ -185,7 +185,7 @@ static void window_destroy( struct object *obj ) /* retrieve a pointer to a window from its handle */ static inline struct window *get_window( user_handle_t handle ) { - struct window *ret = get_user_object( handle, USER_WINDOW ); + struct window *ret = get_user_object( handle, NTUSER_OBJ_WINDOW ); if (!ret) set_win32_error( ERROR_INVALID_WINDOW_HANDLE ); return ret; } @@ -672,7 +672,7 @@ static struct window *create_window( struct window *parent, struct window *owner memset( win->extra_bytes, 0, extra_bytes ); win->nb_extra_bytes = extra_bytes; } - if (!(win->handle = alloc_user_handle( win, USER_WINDOW ))) goto failed; + if (!(win->handle = alloc_user_handle( win, NTUSER_OBJ_WINDOW ))) goto failed; win->last_active = win->handle; /* if parent belongs to a different thread and the window isn't */ @@ -728,7 +728,7 @@ void destroy_thread_windows( struct thread *thread ) user_handle_t handle = 0; struct window *win; - while ((win = next_user_handle( &handle, USER_WINDOW ))) + while ((win = next_user_handle( &handle, NTUSER_OBJ_WINDOW ))) { if (win->thread != thread) continue; if (is_desktop_window( win )) detach_window_thread( win ); @@ -751,8 +751,8 @@ static struct window *get_desktop_window( struct thread *thread ) /* check whether child is a descendant of parent */ int is_child_window( user_handle_t parent, user_handle_t child ) { - struct window *child_ptr = get_user_object( child, USER_WINDOW ); - struct window *parent_ptr = get_user_object( parent, USER_WINDOW ); + struct window *child_ptr = get_user_object( child, NTUSER_OBJ_WINDOW ); + struct window *parent_ptr = get_user_object( parent, NTUSER_OBJ_WINDOW ); if (!child_ptr || !parent_ptr) return 0; while (child_ptr->parent) @@ -766,7 +766,7 @@ int is_child_window( user_handle_t parent, user_handle_t child ) /* check if window can be set as foreground window */ int is_valid_foreground_window( user_handle_t window ) { - struct window *win = get_user_object( window, USER_WINDOW ); + struct window *win = get_user_object( window, NTUSER_OBJ_WINDOW ); return win && (win->style & (WS_POPUP|WS_CHILD)) != WS_CHILD; } @@ -782,7 +782,7 @@ int make_window_active( user_handle_t window ) while (owner) { owner->last_active = win->handle; - owner = get_user_object( owner->owner, USER_WINDOW ); + owner = get_user_object( owner->owner, NTUSER_OBJ_WINDOW ); } return 1; } @@ -860,14 +860,14 @@ static int is_visible( const struct window *win ) /* same as is_visible but takes a window handle */ int is_window_visible( user_handle_t window ) { - struct window *win = get_user_object( window, USER_WINDOW ); + struct window *win = get_user_object( window, NTUSER_OBJ_WINDOW ); if (!win) return 0; return is_visible( win ); } int is_window_transparent( user_handle_t window ) { - struct window *win = get_user_object( window, USER_WINDOW ); + struct window *win = get_user_object( window, NTUSER_OBJ_WINDOW ); if (!win) return 0; return (win->ex_style & (WS_EX_LAYERED|WS_EX_TRANSPARENT)) == (WS_EX_LAYERED|WS_EX_TRANSPARENT); } @@ -1026,7 +1026,7 @@ user_handle_t shallow_window_from_point( struct desktop *desktop, int x, int y ) /* return thread of top-most window containing point (in absolute raw coords) */ struct thread *window_thread_from_point( user_handle_t scope, int x, int y ) { - struct window *win = get_user_object( scope, USER_WINDOW ); + struct window *win = get_user_object( scope, NTUSER_OBJ_WINDOW ); if (!win) return NULL; @@ -1068,7 +1068,7 @@ static int all_windows_from_point( struct window *top, int x, int y, unsigned in /* return the thread owning a window */ struct thread *get_window_thread( user_handle_t handle ) { - struct window *win = get_user_object( handle, USER_WINDOW ); + struct window *win = get_user_object( handle, NTUSER_OBJ_WINDOW ); if (!win || !win->thread) return NULL; return (struct thread *)grab_object( win->thread ); } @@ -2326,7 +2326,7 @@ DECL_HANDLER(get_window_info) reply->is_unicode = win->is_unicode; reply->dpi_context = win->dpi_context; - if (get_user_object( win->last_active, USER_WINDOW )) reply->last_active = win->last_active; + if (get_user_object( win->last_active, NTUSER_OBJ_WINDOW )) reply->last_active = win->last_active; if (win->thread) { reply->tid = get_thread_id( win->thread ); -- GitLab https://gitlab.winehq.org/wine/wine/-/merge_requests/7610
From: Rémi Bernon <rbernon(a)codeweavers.com> --- include/winnt.h | 27 +++++++++++++++++++++++++++ 1 file changed, 27 insertions(+) diff --git a/include/winnt.h b/include/winnt.h index 31d836029f1..980ece57367 100644 --- a/include/winnt.h +++ b/include/winnt.h @@ -7117,6 +7117,22 @@ static FORCEINLINE LONG ReadAcquire( LONG const volatile *src ) return value; } +static FORCEINLINE LONG64 ReadAcquire64( LONG64 const volatile *src ) +{ + LONG64 value; +#if defined(__i386__) && _MSC_VER < 1700 + __asm { + mov eax, src + fild qword ptr [eax] + fistp value + } +#else + value = __WINE_LOAD64_NO_FENCE( (__int64 const volatile *)src ); + __wine_memory_barrier_acq_rel(); +#endif + return value; +} + static FORCEINLINE LONG ReadNoFence( LONG const volatile *src ) { LONG value = __WINE_LOAD32_NO_FENCE( (int const volatile *)src ); @@ -7331,6 +7347,17 @@ static FORCEINLINE LONG ReadAcquire( LONG const volatile *src ) return value; } +static FORCEINLINE LONG64 ReadAcquire64( LONG64 const volatile *src ) +{ + LONG64 value; +#ifdef __i386__ + __asm__ __volatile__( "fildq %1\n\tfistpq %0" : "=m" (value) : "m" (*src) : "memory", "st" ); +#else + __WINE_ATOMIC_LOAD_ACQUIRE( src, &value ); +#endif + return value; +} + static FORCEINLINE LONG ReadNoFence( LONG const volatile *src ) { LONG value; -- GitLab https://gitlab.winehq.org/wine/wine/-/merge_requests/7610
From: Rémi Bernon <rbernon(a)codeweavers.com> --- dlls/win32u/win32u_private.h | 7 ++++ dlls/win32u/window.c | 74 ++++++++++++++++++++++++++---------- dlls/win32u/winstation.c | 7 ---- 3 files changed, 60 insertions(+), 28 deletions(-) diff --git a/dlls/win32u/win32u_private.h b/dlls/win32u/win32u_private.h index 19c666928a8..a7bee5bd93a 100644 --- a/dlls/win32u/win32u_private.h +++ b/dlls/win32u/win32u_private.h @@ -212,6 +212,13 @@ struct object_lock }; #define OBJECT_LOCK_INIT {0} +#if defined(__i386__) || defined(__x86_64__) +/* this prevents compilers from incorrectly reordering non-volatile reads (e.g., memcpy) from shared memory */ +#define __SHARED_READ_FENCE do { __asm__ __volatile__( "" ::: "memory" ); } while (0) +#else +#define __SHARED_READ_FENCE __atomic_thread_fence( __ATOMIC_ACQUIRE ) +#endif + /* Get shared session object's data pointer, must be called in a loop while STATUS_PENDING * is returned, lock must be initialized with OBJECT_LOCK_INIT. * diff --git a/dlls/win32u/window.c b/dlls/win32u/window.c index 5143093b381..9611e855ff8 100644 --- a/dlls/win32u/window.c +++ b/dlls/win32u/window.c @@ -35,8 +35,9 @@ WINE_DEFAULT_DEBUG_CHANNEL(win); #define USER_HANDLE_TO_INDEX(hwnd) ((LOWORD(hwnd) - FIRST_USER_HANDLE) >> 1) +#define USER_HANDLE_FROM_INDEX(index, generation) UlongToHandle( (index << 1) + FIRST_USER_HANDLE + (generation << 16) ) -static void *user_handles[MAX_USER_HANDLES]; +static void *client_objects[MAX_USER_HANDLES]; #define SWP_AGG_NOGEOMETRYCHANGE \ (SWP_NOSIZE | SWP_NOCLIENTSIZE | SWP_NOZORDER) @@ -72,7 +73,7 @@ HANDLE alloc_user_handle( struct user_object *ptr, unsigned short type ) assert( index < MAX_USER_HANDLES ); ptr->handle = handle; ptr->type = type; - InterlockedExchangePointer( &user_handles[index], ptr ); + InterlockedExchangePointer( &client_objects[index], ptr ); } return handle; } @@ -91,27 +92,57 @@ static BOOL is_valid_entry( HANDLE handle, unsigned short type ) return is_valid_entry_uniq( handle, type, ReadAcquire64( (LONG64 *)&entries[index].uniq ) ); } +static BOOL read_acquire_user_entry( HANDLE handle, unsigned short type, const volatile struct user_entry *src, struct user_entry *dst ) +{ + UINT64 uniq = ReadAcquire64( (LONG64 *)&src->uniq ); + if (!is_valid_entry_uniq( handle, type, uniq )) return FALSE; + dst->offset = src->offset; + dst->tid = src->tid; + dst->pid = src->pid; + dst->padding = src->padding; + __SHARED_READ_FENCE; + dst->uniq = ReadNoFence64( &src->uniq ); + return dst->uniq == uniq; +} + +static BOOL get_user_entry( HANDLE handle, unsigned short type, struct user_entry *entry, HANDLE *full ) +{ + const volatile struct user_entry *entries = shared_session->user_entries; + WORD index = USER_HANDLE_TO_INDEX( handle ); + + if (index >= MAX_USER_HANDLES) return FALSE; + if (!read_acquire_user_entry( handle, type, entries + index, entry )) return FALSE; + *full = USER_HANDLE_FROM_INDEX( index, entry->generation ); + return TRUE; +} + +static BOOL get_user_entry_at( WORD index, unsigned short type, struct user_entry *entry, HANDLE *full ) +{ + const volatile struct user_entry *entries = shared_session->user_entries; + if (index >= MAX_USER_HANDLES) return FALSE; + if (!read_acquire_user_entry( 0, type, entries + index, entry )) return FALSE; + *full = USER_HANDLE_FROM_INDEX( index, entry->generation ); + return TRUE; +} + /*********************************************************************** * get_user_handle_ptr */ void *get_user_handle_ptr( HANDLE handle, unsigned short type ) { - struct user_object *ptr; WORD index = USER_HANDLE_TO_INDEX( handle ); + struct user_object *ptr = NULL; + struct user_entry entry; if (index >= MAX_USER_HANDLES) return NULL; user_lock(); - if ((ptr = user_handles[index])) - { - if (ptr->type == type && - ((UINT)(UINT_PTR)ptr->handle == (UINT)(UINT_PTR)handle || - !HIWORD(handle) || HIWORD(handle) == 0xffff)) - return ptr; - ptr = NULL; - } - else ptr = OBJ_OTHER_PROCESS; - user_unlock(); + + if (!get_user_entry( handle, type, &entry, &handle )) ptr = NULL; + else if (entry.pid != GetCurrentProcessId()) ptr = OBJ_OTHER_PROCESS; + else ptr = client_objects[index]; + + if (!ptr || ptr == OBJ_OTHER_PROCESS) user_unlock(); return ptr; } @@ -122,16 +153,17 @@ void *get_user_handle_ptr( HANDLE handle, unsigned short type ) */ void *next_process_user_handle_ptr( HANDLE *handle, unsigned short type ) { - struct user_object *ptr; WORD index = *handle ? USER_HANDLE_TO_INDEX( *handle ) + 1 : 0; + struct user_entry entry; + UINT i; - while (index < MAX_USER_HANDLES) + for (i = index; i < MAX_USER_HANDLES; i++) { - if (!(ptr = user_handles[index++])) continue; /* OBJ_OTHER_PROCESS */ - if (ptr->type != type) continue; - *handle = ptr->handle; - return ptr; + if (!get_user_entry_at( i, type, &entry, handle )) continue; + if (entry.pid != GetCurrentProcessId()) continue; + return client_objects[i]; } + return NULL; } @@ -142,7 +174,7 @@ static void set_user_handle_ptr( HANDLE handle, struct user_object *ptr ) { WORD index = USER_HANDLE_TO_INDEX(handle); assert( index < MAX_USER_HANDLES ); - InterlockedExchangePointer( &user_handles[index], ptr ); + InterlockedExchangePointer( &client_objects[index], ptr ); } /*********************************************************************** @@ -169,7 +201,7 @@ void *free_user_handle( HANDLE handle, unsigned short type ) req->type = type; req->handle = wine_server_user_handle( handle ); if (wine_server_call( req )) ptr = NULL; - else InterlockedCompareExchangePointer( &user_handles[index], NULL, ptr ); + else InterlockedCompareExchangePointer( &client_objects[index], NULL, ptr ); } SERVER_END_REQ; user_unlock(); diff --git a/dlls/win32u/winstation.c b/dlls/win32u/winstation.c index edef603308e..766043ce282 100644 --- a/dlls/win32u/winstation.c +++ b/dlls/win32u/winstation.c @@ -80,13 +80,6 @@ static struct session_thread_data *get_session_thread_data(void) return thread_info->session_data; } -#if defined(__i386__) || defined(__x86_64__) -/* this prevents compilers from incorrectly reordering non-volatile reads (e.g., memcpy) from shared memory */ -#define __SHARED_READ_FENCE do { __asm__ __volatile__( "" ::: "memory" ); } while (0) -#else -#define __SHARED_READ_FENCE __atomic_thread_fence( __ATOMIC_ACQUIRE ) -#endif - static void shared_object_acquire_seqlock( const shared_object_t *object, UINT64 *seq ) { while ((*seq = ReadNoFence64( &object->seq )) & 1) YieldProcessor(); -- GitLab https://gitlab.winehq.org/wine/wine/-/merge_requests/7610
From: Rémi Bernon <rbernon(a)codeweavers.com> --- dlls/win32u/window.c | 37 +++++++++++++++++++------------------ 1 file changed, 19 insertions(+), 18 deletions(-) diff --git a/dlls/win32u/window.c b/dlls/win32u/window.c index cccf14bed20..5143093b381 100644 --- a/dlls/win32u/window.c +++ b/dlls/win32u/window.c @@ -77,6 +77,20 @@ HANDLE alloc_user_handle( struct user_object *ptr, unsigned short type ) return handle; } +static BOOL is_valid_entry_uniq( HANDLE handle, unsigned short type, UINT64 uniq ) +{ + if (!HIWORD(handle) || HIWORD(handle) == 0xffff) return LOWORD(uniq) == type; + return uniq == MAKELONG(type, HIWORD(handle)); +} + +static BOOL is_valid_entry( HANDLE handle, unsigned short type ) +{ + const volatile struct user_entry *entries = shared_session->user_entries; + WORD index = USER_HANDLE_TO_INDEX( handle ); + if (index >= MAX_USER_HANDLES) return FALSE; + return is_valid_entry_uniq( handle, type, ReadAcquire64( (LONG64 *)&entries[index].uniq ) ); +} + /*********************************************************************** * get_user_handle_ptr */ @@ -290,26 +304,13 @@ HWND is_current_process_window( HWND hwnd ) /* see IsWindow */ BOOL is_window( HWND hwnd ) { - WND *win; - BOOL ret; - - if (!(win = get_win_ptr( hwnd ))) return FALSE; - if (win == WND_DESKTOP) return TRUE; - - if (win != WND_OTHER_PROCESS) - { - release_win_ptr( win ); - return TRUE; - } - - /* check other processes */ - SERVER_START_REQ( get_window_info ) + if (!hwnd) return FALSE; + if (!is_valid_entry( hwnd, NTUSER_OBJ_WINDOW )) { - req->handle = wine_server_user_handle( hwnd ); - ret = !wine_server_call_err( req ); + RtlSetLastWin32Error( ERROR_INVALID_WINDOW_HANDLE ); + return FALSE; } - SERVER_END_REQ; - return ret; + return TRUE; } /* see GetWindowThreadProcessId */ -- GitLab https://gitlab.winehq.org/wine/wine/-/merge_requests/7610
From: Rémi Bernon <rbernon(a)codeweavers.com> --- dlls/win32u/window.c | 11 ++- include/ntuser.h | 19 ++++++ server/protocol.def | 2 +- server/user.c | 155 +++++++++++++++++++++++++------------------ server/user.h | 2 - 5 files changed, 116 insertions(+), 73 deletions(-) diff --git a/dlls/win32u/window.c b/dlls/win32u/window.c index 81396fb06d0..cccf14bed20 100644 --- a/dlls/win32u/window.c +++ b/dlls/win32u/window.c @@ -34,10 +34,9 @@ WINE_DEFAULT_DEBUG_CHANNEL(win); -#define NB_USER_HANDLES ((LAST_USER_HANDLE - FIRST_USER_HANDLE + 1) >> 1) #define USER_HANDLE_TO_INDEX(hwnd) ((LOWORD(hwnd) - FIRST_USER_HANDLE) >> 1) -static void *user_handles[NB_USER_HANDLES]; +static void *user_handles[MAX_USER_HANDLES]; #define SWP_AGG_NOGEOMETRYCHANGE \ (SWP_NOSIZE | SWP_NOCLIENTSIZE | SWP_NOZORDER) @@ -70,7 +69,7 @@ HANDLE alloc_user_handle( struct user_object *ptr, unsigned short type ) { UINT index = USER_HANDLE_TO_INDEX( handle ); - assert( index < NB_USER_HANDLES ); + assert( index < MAX_USER_HANDLES ); ptr->handle = handle; ptr->type = type; InterlockedExchangePointer( &user_handles[index], ptr ); @@ -86,7 +85,7 @@ void *get_user_handle_ptr( HANDLE handle, unsigned short type ) struct user_object *ptr; WORD index = USER_HANDLE_TO_INDEX( handle ); - if (index >= NB_USER_HANDLES) return NULL; + if (index >= MAX_USER_HANDLES) return NULL; user_lock(); if ((ptr = user_handles[index])) @@ -112,7 +111,7 @@ void *next_process_user_handle_ptr( HANDLE *handle, unsigned short type ) struct user_object *ptr; WORD index = *handle ? USER_HANDLE_TO_INDEX( *handle ) + 1 : 0; - while (index < NB_USER_HANDLES) + while (index < MAX_USER_HANDLES) { if (!(ptr = user_handles[index++])) continue; /* OBJ_OTHER_PROCESS */ if (ptr->type != type) continue; @@ -128,7 +127,7 @@ void *next_process_user_handle_ptr( HANDLE *handle, unsigned short type ) static void set_user_handle_ptr( HANDLE handle, struct user_object *ptr ) { WORD index = USER_HANDLE_TO_INDEX(handle); - assert( index < NB_USER_HANDLES ); + assert( index < MAX_USER_HANDLES ); InterlockedExchangePointer( &user_handles[index], ptr ); } diff --git a/include/ntuser.h b/include/ntuser.h index 9922c1da4b2..0647efe7082 100644 --- a/include/ntuser.h +++ b/include/ntuser.h @@ -46,6 +46,25 @@ typedef enum MONITOR_DPI_TYPE typedef NTSTATUS (WINAPI *ntuser_callback)( void *args, ULONG len ); NTSYSAPI NTSTATUS KeUserModeCallback( ULONG id, const void *args, ULONG len, void **ret_ptr, ULONG *ret_len ); +struct user_entry +{ + ULONG64 offset; /* shared user object offset */ + ULONG tid; /* owner thread id */ + ULONG pid; /* owner process id */ + ULONG64 padding; + union + { + struct + { + USHORT type; /* object type (0 if free) */ + USHORT generation; /* generation counter */ + }; + LONG64 uniq; + }; +}; + +#define MAX_USER_HANDLES ((LAST_USER_HANDLE - FIRST_USER_HANDLE + 1) >> 1) + /* KernelCallbackTable codes, not compatible with Windows. All of these functions must live inside user32.dll. Overwatch 2's KiUserCallbackDispatcher hook verifies this and prevents the callback from diff --git a/server/protocol.def b/server/protocol.def index e4c2694d606..5de40b1fc1d 100644 --- a/server/protocol.def +++ b/server/protocol.def @@ -1025,7 +1025,7 @@ typedef volatile struct typedef volatile struct { - unsigned __int64 placeholder; + struct user_entry user_entries[MAX_USER_HANDLES]; } session_shm_t; struct obj_locator diff --git a/server/user.c b/server/user.c index 22d72c669e7..2f7970e95b6 100644 --- a/server/user.c +++ b/server/user.c @@ -18,101 +18,122 @@ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA */ +#include "ntstatus.h" +#define WIN32_NO_STATUS +#include "windef.h" +#include "winternl.h" + #include "thread.h" +#include "file.h" #include "user.h" +#include "file.h" +#include "process.h" #include "request.h" -struct user_handle -{ - void *ptr; /* pointer to object */ - unsigned short type; /* object type (0 if free) */ - unsigned short generation; /* generation counter */ -}; +typedef volatile struct user_entry user_entry_t; -static struct user_handle *handles; -static struct user_handle *freelist; +static void *server_objects[MAX_USER_HANDLES]; +static mem_size_t freelist = -1; static int nb_handles; -static int allocated_handles; -static struct user_handle *handle_to_entry( user_handle_t handle ) +static void *get_server_object( user_entry_t *entry ) { - unsigned short generation; - int index = ((handle & 0xffff) - FIRST_USER_HANDLE) >> 1; + user_entry_t *handles = shared_session->user_entries; + return server_objects[entry - handles]; +} + +static void *set_server_object( user_entry_t *entry, void *ptr ) +{ + user_entry_t *handles = shared_session->user_entries; + void *prev = server_objects[entry - handles]; + server_objects[entry - handles] = ptr; + return prev; +} + +static user_entry_t *handle_to_entry( user_handle_t handle ) +{ + user_entry_t *entry, *handles = shared_session->user_entries; + unsigned short generation = handle >> 16; + int index; + + index = ((handle & 0xffff) - FIRST_USER_HANDLE) >> 1; if (index < 0 || index >= nb_handles) return NULL; - if (!handles[index].type) return NULL; - generation = handle >> 16; - if (generation == handles[index].generation || !generation || generation == 0xffff) - return &handles[index]; + entry = handles + index; + + if (!entry->type) return NULL; + if (!generation || generation == 0xffff) return entry; + if (generation == entry->generation) return entry; return NULL; } -static inline user_handle_t entry_to_handle( struct user_handle *ptr ) +static user_handle_t entry_to_handle( user_entry_t *entry ) { - unsigned int index = ptr - handles; - return (index << 1) + FIRST_USER_HANDLE + (ptr->generation << 16); + user_entry_t *handles = shared_session->user_entries; + unsigned int index = entry - handles; + return (index << 1) + FIRST_USER_HANDLE + (entry->generation << 16); } -static inline struct user_handle *alloc_user_entry(void) +static user_entry_t *alloc_user_entry( unsigned short type ) { - struct user_handle *handle; + user_entry_t *entry, *handles = shared_session->user_entries; + unsigned short generation; - if (freelist) + if (freelist != -1) { - handle = freelist; - freelist = handle->ptr; - return handle; + entry = handles + freelist; + generation = entry->generation + 1; + freelist = entry->offset; } - if (nb_handles >= allocated_handles) /* need to grow the array */ + else { - struct user_handle *new_handles; - /* grow array by 50% (but at minimum 32 entries) */ - int growth = max( 32, allocated_handles / 2 ); - int new_size = min( allocated_handles + growth, MAX_USER_HANDLES ); - if (new_size <= allocated_handles) return NULL; - if (!(new_handles = realloc( handles, new_size * sizeof(*handles) ))) - return NULL; - handles = new_handles; - allocated_handles = new_size; + entry = handles + nb_handles; + generation = 1; + nb_handles++; } - handle = &handles[nb_handles++]; - handle->generation = 0; - return handle; + + if (generation == 0 || generation == 0xffff) generation = 1; + + entry->offset = -1; + entry->tid = get_thread_id( current ); + entry->pid = get_process_id( current->process ); + entry->padding = -1; + WriteRelease64( &entry->uniq, MAKELONG(type, generation) ); + return entry; } -static inline void *free_user_entry( struct user_handle *ptr ) +static void free_user_entry( user_entry_t *entry ) { - void *ret; - ret = ptr->ptr; - ptr->ptr = freelist; - ptr->type = 0; - freelist = ptr; - return ret; + user_entry_t *handles = shared_session->user_entries; + size_t index = entry - handles; + + WriteRelease64( &entry->uniq, MAKELONG(0, entry->generation) ); + entry->offset = freelist; + freelist = index; } /* allocate a user handle for a given object */ user_handle_t alloc_user_handle( void *ptr, unsigned short type ) { - struct user_handle *entry = alloc_user_entry(); - if (!entry) return 0; - entry->ptr = ptr; - entry->type = type; - if (++entry->generation >= 0xffff) entry->generation = 1; + user_entry_t *entry; + + if (!(entry = alloc_user_entry( type ))) return 0; + set_server_object( entry, ptr ); return entry_to_handle( entry ); } /* return a pointer to a user object from its handle */ void *get_user_object( user_handle_t handle, unsigned short type ) { - struct user_handle *entry; + user_entry_t *entry; if (!(entry = handle_to_entry( handle )) || entry->type != type) return NULL; - return entry->ptr; + return get_server_object( entry ); } /* get the full handle for a possibly truncated handle */ user_handle_t get_user_full_handle( user_handle_t handle ) { - struct user_handle *entry; + user_entry_t *entry; if (handle >> 16) return handle; if (!(entry = handle_to_entry( handle ))) return handle; @@ -122,30 +143,34 @@ user_handle_t get_user_full_handle( user_handle_t handle ) /* same as get_user_object plus set the handle to the full 32-bit value */ void *get_user_object_handle( user_handle_t *handle, unsigned short type ) { - struct user_handle *entry; + user_entry_t *entry; if (!(entry = handle_to_entry( *handle )) || entry->type != type) return NULL; *handle = entry_to_handle( entry ); - return entry->ptr; + return get_server_object( entry ); } /* free a user handle and return a pointer to the object */ void *free_user_handle( user_handle_t handle ) { - struct user_handle *entry; + user_entry_t *entry; + void *ret; if (!(entry = handle_to_entry( handle ))) { set_error( STATUS_INVALID_HANDLE ); return NULL; } - return free_user_entry( entry ); + + ret = set_server_object( entry, NULL ); + free_user_entry( entry ); + return ret; } /* return the next user handle after 'handle' that is of a given type */ void *next_user_handle( user_handle_t *handle, unsigned short type ) { - struct user_handle *entry; + user_entry_t *entry, *handles = shared_session->user_entries; if (!*handle) entry = handles; else @@ -159,7 +184,7 @@ void *next_user_handle( user_handle_t *handle, unsigned short type ) if (!type || entry->type == type) { *handle = entry_to_handle( entry ); - return entry->ptr; + return get_server_object( entry ); } entry++; } @@ -169,18 +194,20 @@ void *next_user_handle( user_handle_t *handle, unsigned short type ) /* free client-side user handles managed by the process */ void free_process_user_handles( struct process *process ) { - unsigned int i; + user_entry_t *handles = shared_session->user_entries; + unsigned int i, pid = get_process_id( process ); for (i = 0; i < nb_handles; i++) { - switch (handles[i].type) + user_entry_t *entry = handles + i; + switch (entry->type) { case NTUSER_OBJ_MENU: case NTUSER_OBJ_ICON: case NTUSER_OBJ_WINPOS: case NTUSER_OBJ_ACCEL: case NTUSER_OBJ_IMC: - if (handles[i].ptr == process) free_user_entry( &handles[i] ); + if (entry->pid == pid) free_user_entry( entry ); break; case NTUSER_OBJ_HOOK: case NTUSER_OBJ_WINDOW: @@ -193,14 +220,14 @@ void free_process_user_handles( struct process *process ) /* allocate an arbitrary user handle */ DECL_HANDLER(alloc_user_handle) { - reply->handle = alloc_user_handle( current->process, req->type ); + reply->handle = alloc_user_handle( (void *)-1 /* never used */, req->type ); } /* free an arbitrary user handle */ DECL_HANDLER(free_user_handle) { - struct user_handle *entry; + user_entry_t *entry; if ((entry = handle_to_entry( req->handle )) && entry->type == req->type) free_user_entry( entry ); diff --git a/server/user.h b/server/user.h index 23c2c338210..50b275e4eb2 100644 --- a/server/user.h +++ b/server/user.h @@ -36,8 +36,6 @@ struct clipboard; #define DESKTOP_ATOM ((atom_t)32769) -#define MAX_USER_HANDLES ((LAST_USER_HANDLE - FIRST_USER_HANDLE + 1) >> 1) - struct winstation { struct object obj; /* object header */ -- GitLab https://gitlab.winehq.org/wine/wine/-/merge_requests/7610
From: Rémi Bernon <rbernon(a)codeweavers.com> --- dlls/win32u/class.c | 5 +++++ dlls/win32u/gdiobj.c | 2 -- dlls/win32u/ntgdi_private.h | 2 -- dlls/win32u/win32u_private.h | 3 +++ dlls/win32u/winstation.c | 12 ++++++++++++ server/file.h | 1 + server/mapping.c | 6 ++++-- server/protocol.def | 5 +++++ 8 files changed, 30 insertions(+), 6 deletions(-) diff --git a/dlls/win32u/class.c b/dlls/win32u/class.c index ea0d7efe74b..8c5f2819a67 100644 --- a/dlls/win32u/class.c +++ b/dlls/win32u/class.c @@ -36,6 +36,8 @@ WINE_DEFAULT_DEBUG_CHANNEL(class); WINE_DECLARE_DEBUG_CHANNEL(win); +SYSTEM_BASIC_INFORMATION system_info; + #define MAX_WINPROCS 4096 #define WINPROC_PROC16 ((void *)1) /* placeholder for 16-bit window procs */ @@ -248,6 +250,9 @@ DLGPROC get_dialog_proc( DLGPROC ret, BOOL ansi ) static void init_user(void) { + NtQuerySystemInformation( SystemBasicInformation, &system_info, sizeof(system_info), NULL ); + + shared_session_init(); gdi_init(); sysparams_init(); winstation_init(); diff --git a/dlls/win32u/gdiobj.c b/dlls/win32u/gdiobj.c index ec8b7d20ea2..ff354a0a529 100644 --- a/dlls/win32u/gdiobj.c +++ b/dlls/win32u/gdiobj.c @@ -48,7 +48,6 @@ static GDI_SHARED_MEMORY *gdi_shared; static GDI_HANDLE_ENTRY *next_free; static GDI_HANDLE_ENTRY *next_unused; static LONG debug_count; -SYSTEM_BASIC_INFORMATION system_info; static inline HGDIOBJ entry_to_handle( GDI_HANDLE_ENTRY *entry ) { @@ -1040,7 +1039,6 @@ void gdi_init(void) pthread_mutex_init( &gdi_lock, &attr ); pthread_mutexattr_destroy( &attr ); - NtQuerySystemInformation( SystemBasicInformation, &system_info, sizeof(system_info), NULL ); init_gdi_shared(); if (!gdi_shared) return; diff --git a/dlls/win32u/ntgdi_private.h b/dlls/win32u/ntgdi_private.h index 99ebb127d68..136921a211c 100644 --- a/dlls/win32u/ntgdi_private.h +++ b/dlls/win32u/ntgdi_private.h @@ -641,6 +641,4 @@ extern void free_heap_bits( struct gdi_image_bits *bits ); void set_gdi_client_ptr( HGDIOBJ handle, void *ptr ); -extern SYSTEM_BASIC_INFORMATION system_info; - #endif /* __WINE_NTGDI_PRIVATE_H */ diff --git a/dlls/win32u/win32u_private.h b/dlls/win32u/win32u_private.h index 80ca1058d97..19c666928a8 100644 --- a/dlls/win32u/win32u_private.h +++ b/dlls/win32u/win32u_private.h @@ -218,6 +218,7 @@ struct object_lock * The data read from the objects may be transient and no logic should be executed based * on it, within the loop, or after, unless the function has returned STATUS_SUCCESS. */ +extern const session_shm_t *shared_session; 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 NTSTATUS get_shared_input( UINT tid, struct object_lock *lock, const input_shm_t **input_shm ); @@ -279,6 +280,8 @@ static inline void release_win_ptr( struct tagWND *ptr ) user_unlock(); } +extern SYSTEM_BASIC_INFORMATION system_info; +extern void shared_session_init(void); extern void gdi_init(void); extern void winstation_init(void); extern void sysparams_init(void); diff --git a/dlls/win32u/winstation.c b/dlls/win32u/winstation.c index 9b9ea935a48..edef603308e 100644 --- a/dlls/win32u/winstation.c +++ b/dlls/win32u/winstation.c @@ -71,6 +71,7 @@ struct session_block static pthread_mutex_t session_lock = PTHREAD_MUTEX_INITIALIZER; static struct list session_blocks = LIST_INIT(session_blocks); +const session_shm_t *shared_session; static struct session_thread_data *get_session_thread_data(void) { @@ -195,6 +196,17 @@ static const shared_object_t *find_shared_session_object( struct obj_locator loc return NULL; } +void shared_session_init(void) +{ + struct session_block *block; + UINT status; + + if ((status = find_shared_session_block( 0, sizeof(*shared_session), &block ))) + ERR( "Failed to map initial shared session block, status %#x\n", status ); + else + shared_session = (const session_shm_t *)block->data; +} + NTSTATUS get_shared_desktop( struct object_lock *lock, const desktop_shm_t **desktop_shm ) { struct session_thread_data *data = get_session_thread_data(); diff --git a/server/file.h b/server/file.h index 8fc82a460ff..4510a8b4e88 100644 --- a/server/file.h +++ b/server/file.h @@ -193,6 +193,7 @@ extern struct mapping *create_session_mapping( struct object *root, const struct unsigned int attr, const struct security_descriptor *sd ); extern void set_session_mapping( struct mapping *mapping ); +extern session_shm_t *shared_session; extern volatile void *alloc_shared_object(void); extern void free_shared_object( volatile void *object_shm ); extern void invalidate_shared_object( volatile void *object_shm ); diff --git a/server/mapping.c b/server/mapping.c index a74573efe0e..83538831ea2 100644 --- a/server/mapping.c +++ b/server/mapping.c @@ -249,6 +249,7 @@ struct session object_id_t last_object_id; }; +session_shm_t *shared_session; static struct mapping *session_mapping; static struct session session = { @@ -1303,7 +1304,7 @@ struct mapping *create_session_mapping( struct object *root, const struct unicod unsigned int attr, const struct security_descriptor *sd ) { static const unsigned int access = FILE_READ_DATA | FILE_WRITE_DATA; - size_t size = max( sizeof(shared_object_t) * 512, 0x10000 ); + size_t size = max( sizeof(*shared_session) + sizeof(object_shm_t) * 512, 0x10000 ); size = round_size( size, host_page_mask ); return create_mapping( root, name, attr, size, SEC_COMMIT, 0, access, sd ); @@ -1325,9 +1326,10 @@ void set_session_mapping( struct mapping *mapping ) block->data = tmp; block->offset = 0; - block->used_size = 0; + block->used_size = sizeof(*shared_session); block->block_size = size; + shared_session = tmp; session_mapping = mapping; list_add_tail( &session.blocks, &block->entry ); } diff --git a/server/protocol.def b/server/protocol.def index 8ff35b6e401..e4c2694d606 100644 --- a/server/protocol.def +++ b/server/protocol.def @@ -1023,6 +1023,11 @@ typedef volatile struct object_shm_t shm; /* object shared data */ } shared_object_t; +typedef volatile struct +{ + unsigned __int64 placeholder; +} session_shm_t; + struct obj_locator { object_id_t id; /* object unique id, object data is valid if != 0 */ -- GitLab https://gitlab.winehq.org/wine/wine/-/merge_requests/7610
v6: Remove const qualifier from server shared memory pointers. -- https://gitlab.winehq.org/wine/wine/-/merge_requests/7610#note_102664
Tests failures don't seem related, `d3d10core:d3d10core` has been randomly crashing since 11/04, `ole32:marshal` broke from https://gitlab.winehq.org/wine/wine/-/merge_requests/7868, `user32:winstation` failure is a flaky failure from the recent window activation changes. -- https://gitlab.winehq.org/wine/wine/-/merge_requests/7610#note_102671
Jacek Caban (@jacek) commented about server/user.c:
- if (!entry) return 0; - entry->ptr = ptr; - entry->type = type; - if (++entry->generation >= 0xffff) entry->generation = 1; + user_entry_t *entry; + + if (!(entry = alloc_user_entry( type ))) return 0; + set_server_object( entry, ptr ); return entry_to_handle( entry ); }
/* return a pointer to a user object from its handle */ void *get_user_object( user_handle_t handle, unsigned short type ) { - struct user_handle *entry; + user_entry_t *entry; You could still keep const here and in similar places.
-- https://gitlab.winehq.org/wine/wine/-/merge_requests/7610#note_102740
Please move the new commit out of this MR. I'm not sure about it and, more importantly, it's unrelated and this MR is complex enough on its own. -- https://gitlab.winehq.org/wine/wine/-/merge_requests/7610#note_102741
participants (2)
-
Jacek Caban (@jacek) -
Rémi Bernon