For https://gitlab.winehq.org/wine/wine/-/merge_requests/7512 to use it to locate window shared objects.
-- v6: win32u: Use the session shared object to implement is_window. win32u: Use the session shared object for user handle entries. server: Move the user object handle table to the shared memory. server: Use NTUSER_OBJ constants for user object types. server: Create a shared memory object for the global session.
From: Rémi Bernon rbernon@codeweavers.com
--- dlls/win32u/win32u_private.h | 1 + dlls/win32u/winstation.c | 46 ++++++++++++++++++++++++++++++++---- server/protocol.def | 14 ++++++++--- server/user.c | 23 ++++++++++++++++++ server/user.h | 1 + server/winstation.c | 6 +++-- 6 files changed, 82 insertions(+), 9 deletions(-)
diff --git a/dlls/win32u/win32u_private.h b/dlls/win32u/win32u_private.h index b4738ed6b16..128a95b5bf5 100644 --- a/dlls/win32u/win32u_private.h +++ b/dlls/win32u/win32u_private.h @@ -219,6 +219,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 NTSTATUS get_shared_session( struct object_lock *lock, const session_shm_t **session_shm ); 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 ); diff --git a/dlls/win32u/winstation.c b/dlls/win32u/winstation.c index b350b706454..a14dc0a01ee 100644 --- a/dlls/win32u/winstation.c +++ b/dlls/win32u/winstation.c @@ -54,6 +54,7 @@ struct shared_input_cache
struct session_thread_data { + const shared_object_t *shared_session; /* shared session cached object */ 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 shared_input_cache shared_input; /* current thread input shared session cached object */ @@ -195,6 +196,41 @@ static const shared_object_t *find_shared_session_object( struct obj_locator loc return NULL; }
+NTSTATUS get_shared_session( struct object_lock *lock, const session_shm_t **session_shm ) +{ + struct session_thread_data *data = get_session_thread_data(); + const shared_object_t *object; + + TRACE( "lock %p, session_shm %p\n", lock, session_shm ); + + if (!(object = data->shared_session)) + { + struct obj_locator locator; + + SERVER_START_REQ( get_thread_desktop ) + { + req->tid = GetCurrentThreadId(); + wine_server_call( req ); + locator = reply->session_locator; + } + SERVER_END_REQ; + + data->shared_session = find_shared_session_object( locator ); + if (!(object = data->shared_session)) 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 ); + *session_shm = &object->shm.session; + lock->id = object->id; + return STATUS_PENDING; + } + + return STATUS_SUCCESS; +} + NTSTATUS get_shared_desktop( struct object_lock *lock, const desktop_shm_t **desktop_shm ) { struct session_thread_data *data = get_session_thread_data(); @@ -210,7 +246,7 @@ NTSTATUS get_shared_desktop( struct object_lock *lock, const desktop_shm_t **des { req->tid = GetCurrentThreadId(); wine_server_call( req ); - locator = reply->locator; + locator = reply->desktop_locator; } SERVER_END_REQ;
@@ -547,13 +583,14 @@ HDESK WINAPI NtUserGetThreadDesktop( DWORD thread ) BOOL WINAPI NtUserSetThreadDesktop( HDESK handle ) { BOOL ret, was_virtual_desktop = is_virtual_desktop(); - struct obj_locator locator; + struct obj_locator session_locator, desktop_locator;
SERVER_START_REQ( set_thread_desktop ) { req->handle = wine_server_obj_handle( handle ); ret = !wine_server_call_err( req ); - locator = reply->locator; + session_locator = reply->session_locator; + desktop_locator = reply->desktop_locator; } SERVER_END_REQ;
@@ -561,7 +598,8 @@ BOOL WINAPI NtUserSetThreadDesktop( HDESK handle ) { struct user_thread_info *thread_info = get_user_thread_info(); struct session_thread_data *data = get_session_thread_data(); - data->shared_desktop = find_shared_session_object( locator ); + data->shared_session = find_shared_session_object( session_locator ); + data->shared_desktop = find_shared_session_object( desktop_locator ); memset( &data->shared_foreground, 0, sizeof(data->shared_foreground) ); thread_info->client_info.top_window = 0; thread_info->client_info.msg_window = 0; diff --git a/server/protocol.def b/server/protocol.def index 871c3909e8c..9ce2257e821 100644 --- a/server/protocol.def +++ b/server/protocol.def @@ -976,6 +976,11 @@ struct shared_cursor struct rectangle clip; /* cursor clip rectangle */ };
+typedef volatile struct +{ + int placeholder; +} session_shm_t; + typedef volatile struct { unsigned int flags; /* desktop flags */ @@ -1011,6 +1016,7 @@ typedef volatile struct
typedef volatile union { + session_shm_t session; desktop_shm_t desktop; queue_shm_t queue; input_shm_t input; @@ -2963,8 +2969,9 @@ enum coords_relative @REQ(get_thread_desktop) thread_id_t tid; /* thread id */ @REPLY - struct obj_locator locator; /* locator for the shared session object */ - obj_handle_t handle; /* handle to the desktop */ + struct obj_locator session_locator; /* locator for the shared session object */ + struct obj_locator desktop_locator; /* locator for the shared session desktop object */ + obj_handle_t handle; /* handle to the desktop */ @END
@@ -2972,7 +2979,8 @@ enum coords_relative @REQ(set_thread_desktop) obj_handle_t handle; /* handle to the desktop */ @REPLY - struct obj_locator locator; /* locator for the shared session object */ + struct obj_locator session_locator; /* locator for the shared session object */ + struct obj_locator desktop_locator; /* locator for the shared session desktop object */ @END
diff --git a/server/user.c b/server/user.c index 2d038a6ddbf..86f5c810933 100644 --- a/server/user.c +++ b/server/user.c @@ -18,7 +18,13 @@ * 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 "request.h"
@@ -34,6 +40,23 @@ static struct user_handle *freelist; static int nb_handles; static int allocated_handles;
+const session_shm_t *get_session_shm(void) +{ + static const session_shm_t *session; + C_ASSERT( sizeof(*session) <= 1024 * 1024 ); + + if (!session && (session = alloc_shared_object())) + { + SHARED_WRITE_BEGIN( session, session_shm_t ) + { + shared->placeholder = 0; + } + SHARED_WRITE_END; + } + + return session; +} + static struct user_handle *handle_to_entry( user_handle_t handle ) { unsigned short generation; diff --git a/server/user.h b/server/user.h index ce463b9395d..c77bc030fad 100644 --- a/server/user.h +++ b/server/user.h @@ -99,6 +99,7 @@ struct desktop
/* user handles functions */
+extern const session_shm_t *get_session_shm(void); 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 ); diff --git a/server/winstation.c b/server/winstation.c index b3746090ccf..19eab070d4d 100644 --- a/server/winstation.c +++ b/server/winstation.c @@ -816,7 +816,8 @@ DECL_HANDLER(get_thread_desktop) if (!(desktop = get_thread_desktop( thread, 0 ))) clear_error(); else { - if (desktop->shared) reply->locator = get_shared_object_locator( desktop->shared ); + reply->session_locator = get_shared_object_locator( get_session_shm() ); + if (desktop->shared) reply->desktop_locator = get_shared_object_locator( desktop->shared ); release_object( desktop ); }
@@ -862,7 +863,8 @@ DECL_HANDLER(set_thread_desktop) if (old_desktop) remove_desktop_thread( old_desktop, current ); add_desktop_thread( new_desktop, current ); } - reply->locator = get_shared_object_locator( new_desktop->shared ); + reply->session_locator = get_shared_object_locator( get_session_shm() ); + reply->desktop_locator = get_shared_object_locator( new_desktop->shared ); }
if (!current->process->desktop)
From: Rémi Bernon rbernon@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 2f3bbdf91c0..4dd7d49cb22 100644 --- a/dlls/win32u/ntuser_private.h +++ b/dlls/win32u/ntuser_private.h @@ -230,11 +230,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 0a3d6b28e47..3c3161acdd1 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 9ce2257e821..1abe0fb0861 100644 --- a/server/protocol.def +++ b/server/protocol.def @@ -3932,6 +3932,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 @@ -3939,6 +3940,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 520659d377c..df3258a5158 100644 --- a/server/queue.c +++ b/server/queue.c @@ -3331,7 +3331,7 @@ DECL_HANDLER(get_message) const 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; @@ -4047,7 +4047,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 86f5c810933..b660b91ef7f 100644 --- a/server/user.c +++ b/server/user.c @@ -113,7 +113,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; @@ -124,7 +124,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;
@@ -143,7 +143,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;
@@ -166,7 +166,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;
@@ -195,14 +195,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 ); }
@@ -211,7 +225,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 c77bc030fad..473ff0ce820 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) @@ -100,12 +93,12 @@ struct desktop /* user handles functions */
extern const session_shm_t *get_session_shm(void); -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 */ @@ -315,7 +308,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 );
From: Rémi Bernon rbernon@codeweavers.com
--- server/protocol.def | 17 ++++- server/user.c | 181 ++++++++++++++++++++++++++------------------ server/user.h | 2 - 3 files changed, 123 insertions(+), 77 deletions(-)
diff --git a/server/protocol.def b/server/protocol.def index 1abe0fb0861..c3304d8b82b 100644 --- a/server/protocol.def +++ b/server/protocol.def @@ -976,9 +976,24 @@ struct shared_cursor struct rectangle clip; /* cursor clip rectangle */ };
+struct user_entry +{ + mem_size_t offset; /* shared user object offset */ + thread_id_t tid; /* owner thread id */ + process_id_t pid; /* owner process id */ + unsigned short type; /* object type (0 if free) */ + unsigned short generation; /* generation counter */ + unsigned int __pad; +}; +typedef volatile struct user_entry user_entry_t; + +#define MAX_USER_HANDLES ((LAST_USER_HANDLE - FIRST_USER_HANDLE + 1) >> 1) + typedef volatile struct { - int placeholder; + struct user_entry user_entries[MAX_USER_HANDLES]; + unsigned int user_entry_count; + unsigned int user_entry_next; } session_shm_t;
typedef volatile struct diff --git a/server/user.c b/server/user.c index b660b91ef7f..60000e67995 100644 --- a/server/user.c +++ b/server/user.c @@ -26,20 +26,10 @@ #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 */ -}; - -static struct user_handle *handles; -static struct user_handle *freelist; -static int nb_handles; -static int allocated_handles; - const session_shm_t *get_session_shm(void) { static const session_shm_t *session; @@ -49,7 +39,8 @@ const session_shm_t *get_session_shm(void) { SHARED_WRITE_BEGIN( session, session_shm_t ) { - shared->placeholder = 0; + shared->user_entry_count = 0; + shared->user_entry_next = -1; } SHARED_WRITE_END; } @@ -57,85 +48,120 @@ const session_shm_t *get_session_shm(void) return session; }
-static struct user_handle *handle_to_entry( user_handle_t handle ) +static void *server_objects[MAX_USER_HANDLES]; + +static void *get_server_object( const user_entry_t *entry ) { + const session_shm_t *session = get_session_shm(); + return server_objects[entry - session->user_entries]; +} + +static void *set_server_object( const user_entry_t *entry, void *ptr ) +{ + const session_shm_t *session = get_session_shm(); + void *prev = server_objects[entry - session->user_entries]; + server_objects[entry - session->user_entries] = ptr; + return prev; +} + +static const user_entry_t *handle_to_entry( user_handle_t handle ) +{ + const session_shm_t *session = get_session_shm(); + const user_entry_t *entry; unsigned short generation; - int index = ((handle & 0xffff) - FIRST_USER_HANDLE) >> 1; - if (index < 0 || index >= nb_handles) return NULL; - if (!handles[index].type) return NULL; + int index; + + index = ((handle & 0xffff) - FIRST_USER_HANDLE) >> 1; + if (index < 0 || index >= session->user_entry_count) return NULL; + + entry = session->user_entries + index; + if (!entry->type) return NULL; + generation = handle >> 16; - if (generation == handles[index].generation || !generation || generation == 0xffff) - return &handles[index]; + if (generation == entry->generation || !generation || generation == 0xffff) return entry; return NULL; }
-static inline user_handle_t entry_to_handle( struct user_handle *ptr ) +static user_handle_t entry_to_handle( const user_entry_t *entry ) { - unsigned int index = ptr - handles; - return (index << 1) + FIRST_USER_HANDLE + (ptr->generation << 16); + const session_shm_t *session = get_session_shm(); + unsigned int index = entry - session->user_entries; + return (index << 1) + FIRST_USER_HANDLE + (entry->generation << 16); }
-static inline struct user_handle *alloc_user_entry(void) +static const user_entry_t *alloc_user_entry( unsigned short type ) { - struct user_handle *handle; + const session_shm_t *session = get_session_shm(); + const user_entry_t *ret;
- if (freelist) - { - handle = freelist; - freelist = handle->ptr; - return handle; - } - if (nb_handles >= allocated_handles) /* need to grow the array */ + SHARED_WRITE_BEGIN( session, session_shm_t ) { - 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; + user_entry_t *entry; + + if (shared->user_entry_next != -1) + { + entry = shared->user_entries + shared->user_entry_next; + shared->user_entry_next = entry->offset; + if (++entry->generation >= 0xffff) entry->generation = 1; + } + else + { + entry = shared->user_entries + shared->user_entry_count; + shared->user_entry_count++; + entry->generation = 1; + } + + entry->offset = -1; + entry->tid = get_thread_id( current ); + entry->pid = get_process_id( current->process ); + entry->type = type; + + ret = entry; } - handle = &handles[nb_handles++]; - handle->generation = 0; - return handle; + SHARED_WRITE_END; + + return ret; }
-static inline void *free_user_entry( struct user_handle *ptr ) +static void free_user_entry( const user_entry_t *entry ) { - void *ret; - ret = ptr->ptr; - ptr->ptr = freelist; - ptr->type = 0; - freelist = ptr; - return ret; + const session_shm_t *session = get_session_shm(); + size_t index = entry - session->user_entries; + + SHARED_WRITE_BEGIN( session, session_shm_t ) + { + shared->user_entries[index].offset = shared->user_entry_next; + shared->user_entries[index].pid = 0; + shared->user_entries[index].tid = 0; + shared->user_entries[index].type = 0; + shared->user_entry_next = index; + } + SHARED_WRITE_END; }
/* 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; + const 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; + const 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; + const user_entry_t *entry;
if (handle >> 16) return handle; if (!(entry = handle_to_entry( handle ))) return handle; @@ -145,44 +171,49 @@ 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; + const 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; + const 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; + const session_shm_t *session = get_session_shm(); + const user_entry_t *entry;
- if (!*handle) entry = handles; + if (!*handle) entry = session->user_entries; else { int index = ((*handle & 0xffff) - FIRST_USER_HANDLE) >> 1; - if (index < 0 || index >= nb_handles) return NULL; - entry = handles + index + 1; /* start from the next one */ + if (index < 0 || index >= session->user_entry_count) return NULL; + entry = session->user_entries + index + 1; /* start from the next one */ } - while (entry < handles + nb_handles) + while (entry < session->user_entries + session->user_entry_count) { if (!type || entry->type == type) { *handle = entry_to_handle( entry ); - return entry->ptr; + return get_server_object( entry ); } entry++; } @@ -192,18 +223,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; + const session_shm_t *session = get_session_shm(); + unsigned int i, pid = get_process_id( process );
- for (i = 0; i < nb_handles; i++) + for (i = 0; i < session->user_entry_count; i++) { - switch (handles[i].type) + const user_entry_t *entry = session->user_entries + 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: @@ -216,14 +249,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; + const 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 473ff0ce820..06541ff8ec3 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 */
From: Rémi Bernon rbernon@codeweavers.com
--- dlls/win32u/window.c | 82 +++++++++++++++++++++++++++++++------------- 1 file changed, 58 insertions(+), 24 deletions(-)
diff --git a/dlls/win32u/window.c b/dlls/win32u/window.c index 3c3161acdd1..235b3a69234 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 *client_objects[MAX_USER_HANDLES];
#define SWP_AGG_NOGEOMETRYCHANGE \ (SWP_NOSIZE | SWP_NOCLIENTSIZE | SWP_NOZORDER) @@ -52,6 +51,12 @@ static void *user_handles[NB_USER_HANDLES]; #define PLACE_MAX 0x0002 #define PLACE_RECT 0x0004
+static HANDLE entry_to_handle( const session_shm_t *session, const user_entry_t *entry ) +{ + unsigned int index = entry - session->user_entries; + return UlongToHandle( (index << 1) + FIRST_USER_HANDLE + (entry->generation << 16) ); +} + /*********************************************************************** * alloc_user_handle */ @@ -70,35 +75,53 @@ 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 ); + InterlockedExchangePointer( &client_objects[index], ptr ); } return handle; }
+/* must be called within a session_shm read loop */ +static const user_entry_t *get_session_entry( const session_shm_t *session_shm, HANDLE handle, unsigned short type ) +{ + const user_entry_t *entry, *begin = session_shm->user_entries, *end = begin + session_shm->user_entry_count; + unsigned short index = USER_HANDLE_TO_INDEX( handle ); + + entry = session_shm->user_entries + index; + if (entry < begin || entry >= end || entry->type != type) return NULL; + if (entry_to_handle( session_shm, entry ) == handle) return entry; + if (!HIWORD(handle) || HIWORD(handle) == 0xffff) return entry; + + return NULL; +} + /*********************************************************************** * get_user_handle_ptr */ void *get_user_handle_ptr( HANDLE handle, unsigned short type ) { - struct user_object *ptr; + UINT status, pid = GetCurrentProcessId(); WORD index = USER_HANDLE_TO_INDEX( handle ); + struct object_lock lock = OBJECT_LOCK_INIT; + const session_shm_t *session_shm; + struct user_object *ptr = NULL;
- if (index >= NB_USER_HANDLES) return NULL; + if (index >= MAX_USER_HANDLES) return NULL;
user_lock(); - if ((ptr = user_handles[index])) + + while ((status = get_shared_session( &lock, &session_shm )) == STATUS_PENDING) { - if (ptr->type == type && - ((UINT)(UINT_PTR)ptr->handle == (UINT)(UINT_PTR)handle || - !HIWORD(handle) || HIWORD(handle) == 0xffff)) - return ptr; - ptr = NULL; + const user_entry_t *entry; + if (!(entry = get_session_entry( session_shm, handle, type ))) ptr = NULL; + else if (entry->pid != pid) ptr = OBJ_OTHER_PROCESS; + else ptr = client_objects[entry - session_shm->user_entries]; } - else ptr = OBJ_OTHER_PROCESS; - user_unlock(); + if (status) ptr = NULL; + + if (!ptr || ptr == OBJ_OTHER_PROCESS) user_unlock(); return ptr; }
@@ -109,17 +132,28 @@ 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; + struct user_object *ptr = NULL; + UINT status, pid = GetCurrentProcessId(), i; WORD index = *handle ? USER_HANDLE_TO_INDEX( *handle ) + 1 : 0; + struct object_lock lock = OBJECT_LOCK_INIT; + const session_shm_t *session_shm; + HANDLE next = NULL;
- while (index < NB_USER_HANDLES) + while ((status = get_shared_session( &lock, &session_shm )) == STATUS_PENDING) { - if (!(ptr = user_handles[index++])) continue; /* OBJ_OTHER_PROCESS */ - if (ptr->type != type) continue; - *handle = ptr->handle; - return ptr; + for (i = index, ptr = next = NULL; i < session_shm->user_entry_count; i++) + { + const user_entry_t *entry = session_shm->user_entries + i; + if (entry->pid != pid || entry->type != type) continue; + next = entry_to_handle( session_shm, entry ); + ptr = client_objects[i]; + break; + } } - return NULL; + if (status) next = ptr = NULL; + + *handle = next; + return ptr; }
/*********************************************************************** @@ -128,8 +162,8 @@ 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 ); - InterlockedExchangePointer( &user_handles[index], ptr ); + assert( index < MAX_USER_HANDLES ); + InterlockedExchangePointer( &client_objects[index], ptr ); }
/*********************************************************************** @@ -156,7 +190,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();
From: Rémi Bernon rbernon@codeweavers.com
--- dlls/win32u/window.c | 25 ++++++++----------------- 1 file changed, 8 insertions(+), 17 deletions(-)
diff --git a/dlls/win32u/window.c b/dlls/win32u/window.c index 235b3a69234..503235cc10a 100644 --- a/dlls/win32u/window.c +++ b/dlls/win32u/window.c @@ -325,25 +325,16 @@ 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; + struct object_lock lock = OBJECT_LOCK_INIT; + const session_shm_t *session_shm; + BOOL ret = FALSE; + UINT status;
- if (win != WND_OTHER_PROCESS) - { - release_win_ptr( win ); - return TRUE; - } + while ((status = get_shared_session( &lock, &session_shm )) == STATUS_PENDING) + ret = !!get_session_entry( session_shm, hwnd, NTUSER_OBJ_WINDOW ); + if (status) ret = FALSE;
- /* check other processes */ - SERVER_START_REQ( get_window_info ) - { - req->handle = wine_server_user_handle( hwnd ); - ret = !wine_server_call_err( req ); - } - SERVER_END_REQ; + if (!ret) RtlSetLastWin32Error( ERROR_INVALID_WINDOW_HANDLE ); return ret; }