For https://gitlab.winehq.org/wine/wine/-/merge_requests/7512 to use it to locate window shared objects.
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 | 24 ++++++++++++++++-------- server/user.h | 17 +++++------------ server/window.c | 24 ++++++++++++------------ 8 files changed, 50 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..0f72b851770 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,22 @@ 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_HOOK: continue; + case NTUSER_OBJ_WINDOW: continue; + default: + if (handles[i].ptr == process) free_user_entry( &handles[i] ); + break; + } + } }
/* 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 +219,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 0f72b851770..43f314cb6aa 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,16 +223,18 @@ 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_HOOK: continue; case NTUSER_OBJ_WINDOW: continue; default: - if (handles[i].ptr == process) free_user_entry( &handles[i] ); + if (entry->pid == pid) free_user_entry( entry ); break; } } @@ -210,14 +243,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( NULL, 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 | 84 +++++++++++++++++++++++++++++++------------- 1 file changed, 59 insertions(+), 25 deletions(-)
diff --git a/dlls/win32u/window.c b/dlls/win32u/window.c index 3c3161acdd1..19fcfc09b77 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->generation || entry->generation == 0xffff) return NULL; + if (entry_to_handle( session_shm, entry ) != handle) return NULL; + + return entry; +} + /*********************************************************************** * get_user_handle_ptr */ void *get_user_handle_ptr( HANDLE handle, unsigned short type ) { - struct user_object *ptr; + UINT status, pid = GetCurrentProcessId(), tid = GetCurrentThreadId(); 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 || entry->tid != tid) 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,29 @@ 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(), tid = GetCurrentThreadId(), 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; + const user_entry_t *entry = session_shm->user_entries; + + for (i = index, ptr = NULL; i < session_shm->user_entry_count; i++) + { + if (entry->pid != pid || entry->tid != tid || entry->type != type) continue; + ptr = client_objects[entry - session_shm->user_entries]; + next = entry_to_handle( session_shm, entry ); + break; + } } - return NULL; + if (status) next = ptr = NULL; + + *handle = next; + return ptr; }
/*********************************************************************** @@ -128,8 +163,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 ); }
/*********************************************************************** @@ -147,7 +182,6 @@ void release_user_handle_ptr( void *ptr ) void *free_user_handle( HANDLE handle, unsigned short type ) { struct user_object *ptr; - WORD index = USER_HANDLE_TO_INDEX( handle );
if ((ptr = get_user_handle_ptr( handle, type )) && ptr != OBJ_OTHER_PROCESS) { @@ -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 set_user_handle_ptr( handle, NULL ); } 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 19fcfc09b77..a06b9bc8d6e 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; }
The entry layout is roughly similar (though in this MR it misses 64bit unknown field before object type, which will be added later and used for our own purpose) to some of the recent win64 layout, although I don't think that's very useful as the layout has changed multiple time and differs between 32bit/64bit kernels.
The Windows layout also doesn't include the pid, but I think we kind of need it.