For https://gitlab.winehq.org/wine/wine/-/merge_requests/7512 to use it to locate window shared objects.
-- v9: 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: Use NTUSER_OBJ constants for user object types. server: Create a shared memory object for the global session. include: Implement ReadAcquire64.
From: Rémi Bernon rbernon@codeweavers.com
--- include/winnt.h | 27 +++++++++++++++++++++++++++ 1 file changed, 27 insertions(+)
diff --git a/include/winnt.h b/include/winnt.h index 722d2c3a542..0f4243ab75f 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;
From: Rémi Bernon rbernon@codeweavers.com
--- dlls/win32u/win32u_private.h | 1 + dlls/win32u/winstation.c | 18 ++++++++++++++++-- server/protocol.def | 13 +++++++++++-- server/user.c | 23 +++++++++++++++++++++++ server/user.h | 1 + server/winstation.c | 3 +++ 6 files changed, 55 insertions(+), 4 deletions(-)
diff --git a/dlls/win32u/win32u_private.h b/dlls/win32u/win32u_private.h index b4738ed6b16..dad7a12880e 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 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 ); diff --git a/dlls/win32u/winstation.c b/dlls/win32u/winstation.c index b350b706454..25eea73dbd4 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,13 @@ static const shared_object_t *find_shared_session_object( struct obj_locator loc return NULL; }
+static void init_shared_session( struct obj_locator locator ) +{ + const shared_object_t *object; + if (shared_session || !(object = find_shared_session_object( locator ))) return; + shared_session = &object->shm.session; +} + NTSTATUS get_shared_desktop( struct object_lock *lock, const desktop_shm_t **desktop_shm ) { struct session_thread_data *data = get_session_thread_data(); @@ -409,14 +417,17 @@ BOOL WINAPI NtUserCloseWindowStation( HWINSTA handle ) */ HWINSTA WINAPI NtUserGetProcessWindowStation(void) { + struct obj_locator session_locator; HWINSTA ret = 0;
SERVER_START_REQ( get_process_winstation ) { - if (!wine_server_call_err( req )) - ret = wine_server_ptr_handle( reply->handle ); + if (!wine_server_call_err( req )) ret = wine_server_ptr_handle( reply->handle ); + session_locator = reply->session_locator; } SERVER_END_REQ; + + init_shared_session( session_locator ); return ret; }
@@ -425,15 +436,18 @@ HWINSTA WINAPI NtUserGetProcessWindowStation(void) */ BOOL WINAPI NtUserSetProcessWindowStation( HWINSTA handle ) { + struct obj_locator session_locator; BOOL ret;
SERVER_START_REQ( set_process_winstation ) { req->handle = wine_server_obj_handle( handle ); ret = !wine_server_call_err( req ); + session_locator = reply->session_locator; } SERVER_END_REQ;
+ init_shared_session( session_locator ); reset_monitor_update_serial(); return ret; } diff --git a/server/protocol.def b/server/protocol.def index 871c3909e8c..1931be9a41c 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; @@ -2894,13 +2900,16 @@ enum coords_relative /* Get the process current window station */ @REQ(get_process_winstation) @REPLY - obj_handle_t handle; /* handle to the window station */ + struct obj_locator session_locator; /* locator for the shared session object */ + obj_handle_t handle; /* handle to the window station */ @END
/* Set the process current window station */ @REQ(set_process_winstation) - obj_handle_t handle; /* handle to the window station */ + obj_handle_t handle; /* handle to the window station */ +@REPLY + struct obj_locator session_locator; /* locator for the shared session 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..06c2706f1a2 100644 --- a/server/winstation.c +++ b/server/winstation.c @@ -680,6 +680,7 @@ DECL_HANDLER(set_winstation_monitors) /* get the process current window station */ DECL_HANDLER(get_process_winstation) { + reply->session_locator = get_shared_object_locator( get_session_shm() ); reply->handle = current->process->winstation; }
@@ -696,6 +697,8 @@ DECL_HANDLER(set_process_winstation) current->process->winstation = req->handle; release_object( winstation ); } + + reply->session_locator = get_shared_object_locator( get_session_shm() ); }
/* create a 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 1931be9a41c..297e187d35f 100644 --- a/server/protocol.def +++ b/server/protocol.def @@ -3933,6 +3933,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 @@ -3940,6 +3941,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
--- dlls/win32u/window.c | 11 ++- server/protocol.def | 21 ++++- server/user.c | 187 ++++++++++++++++++++++++++++--------------- server/user.h | 2 - 4 files changed, 146 insertions(+), 75 deletions(-)
diff --git a/dlls/win32u/window.c b/dlls/win32u/window.c index 3c3161acdd1..ba79cdc11dd 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/server/protocol.def b/server/protocol.def index 297e187d35f..9bb018adc20 100644 --- a/server/protocol.def +++ b/server/protocol.def @@ -976,9 +976,28 @@ 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 __int64 padding; + union + { + struct + { + unsigned short type; /* object type (0 if free) */ + unsigned short generation; /* generation counter */ + }; + unsigned __int64 uniq; + }; +}; + +#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]; } session_shm_t;
typedef volatile struct diff --git a/server/user.c b/server/user.c index b660b91ef7f..4ada806e2a5 100644 --- a/server/user.c +++ b/server/user.c @@ -26,19 +26,41 @@ #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 void atomic_store_u32(volatile unsigned int *ptr, unsigned int value) +{ + /* on x86 there should be total store order guarantees, so volatile is + * enough to ensure the stores aren't reordered by the compiler, and then + * they will always be seen in-order from other CPUs. On other archs, we + * need atomic intrinsics to guarantee that. */ +#if defined(__i386__) || defined(__x86_64__) + *ptr = value; +#else + __atomic_store_n(ptr, value, __ATOMIC_SEQ_CST); +#endif +} + +static void atomic_store_u64(volatile unsigned __int64 *ptr, unsigned __int64 value) +{ + /* on x86 there should be total store order guarantees, so volatile is + * enough to ensure the stores aren't reordered by the compiler, and then + * they will always be seen in-order from other CPUs. On other archs, we + * need atomic intrinsics to guarantee that. */ +#if defined(__i386__) || defined(__x86_64__) + *ptr = value; +#else + __atomic_store_n(ptr, value, __ATOMIC_SEQ_CST); +#endif +}
const session_shm_t *get_session_shm(void) { @@ -49,7 +71,7 @@ const session_shm_t *get_session_shm(void) { SHARED_WRITE_BEGIN( session, session_shm_t ) { - shared->placeholder = 0; + memset( (void *)shared->user_entries, 0, sizeof(shared->user_entries) ); } SHARED_WRITE_END; } @@ -57,85 +79,110 @@ const session_shm_t *get_session_shm(void) return session; }
-static struct user_handle *handle_to_entry( user_handle_t handle ) +static void *get_server_object( const user_entry_t *entry ) { - unsigned short generation; - int index = ((handle & 0xffff) - FIRST_USER_HANDLE) >> 1; + const session_shm_t *session = get_session_shm(); + const user_entry_t *handles = session->user_entries; + return server_objects[entry - handles]; +} + +static void *set_server_object( const user_entry_t *entry, void *ptr ) +{ + const session_shm_t *session = get_session_shm(); + const user_entry_t *handles = session->user_entries; + void *prev = server_objects[entry - handles]; + server_objects[entry - handles] = 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 *handles = session->user_entries; + unsigned short generation = handle >> 16; + const user_entry_t *entry; + 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( 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(); + const user_entry_t *handles = 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 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 *handles = session->user_entries; + unsigned short generation; + user_entry_t *entry;
- if (freelist) + if (freelist != -1) { - handle = freelist; - freelist = handle->ptr; - return handle; + entry = (user_entry_t *)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 = (user_entry_t *)handles + nb_handles; + generation = 1; + nb_handles++; } - handle = &handles[nb_handles++]; - handle->generation = 0; - return handle; + + if (generation == 0 || generation == 0xffff) generation = 1; + + atomic_store_u32( &entry->tid, get_thread_id( current ) ); + atomic_store_u32( &entry->pid, get_process_id( current->process ) ); + atomic_store_u64( &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; + const session_shm_t *session = get_session_shm(); + const user_entry_t *handles = session->user_entries; + size_t index = entry - handles; + + atomic_store_u64( &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; + 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,30 +192,35 @@ 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( (user_entry_t *)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, *handles = session->user_entries;
if (!*handle) entry = handles; else @@ -182,7 +234,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++; } @@ -192,18 +244,21 @@ 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(); + const user_entry_t *handles = session->user_entries; + unsigned int i, pid = get_process_id( process );
for (i = 0; i < nb_handles; i++) { - switch (handles[i].type) + const 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( (user_entry_t *)entry ); break; case NTUSER_OBJ_HOOK: case NTUSER_OBJ_WINDOW: @@ -216,17 +271,17 @@ 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 ); + free_user_entry( (user_entry_t *)entry ); else set_error( STATUS_INVALID_HANDLE ); } 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 | 36 ++++++++++++++++++------------------ 1 file changed, 18 insertions(+), 18 deletions(-)
diff --git a/dlls/win32u/window.c b/dlls/win32u/window.c index ba79cdc11dd..fddd7aea516 100644 --- a/dlls/win32u/window.c +++ b/dlls/win32u/window.c @@ -77,6 +77,19 @@ 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)) return LOWORD(uniq) == type; + return uniq == MAKELONG(type, HIWORD(handle)); +} + +static BOOL is_valid_entry( HANDLE handle, unsigned short type ) +{ + UINT index = USER_HANDLE_TO_INDEX(handle); + const volatile struct user_entry *entry = shared_session->user_entries + index; + return is_valid_entry_uniq( handle, type, ReadAcquire64( (LONG64 *)&entry->uniq )); +} + /*********************************************************************** * get_user_handle_ptr */ @@ -290,26 +303,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 */
From: Rémi Bernon rbernon@codeweavers.com
--- dlls/win32u/window.c | 70 +++++++++++++++++++++++++++++++------------- 1 file changed, 49 insertions(+), 21 deletions(-)
diff --git a/dlls/win32u/window.c b/dlls/win32u/window.c index fddd7aea516..3e9dfb63e1d 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; } @@ -90,27 +91,53 @@ static BOOL is_valid_entry( HANDLE handle, unsigned short type ) return is_valid_entry_uniq( handle, type, ReadAcquire64( (LONG64 *)&entry->uniq )); }
+static BOOL read_acquire_user_entry( HANDLE handle, unsigned short type, const volatile struct user_entry *src, struct user_entry *dst ) +{ + if (!is_valid_entry_uniq( handle, type, ReadAcquire64( (LONG64 *)&src->uniq ) )) return FALSE; + dst->offset = ReadAcquire64( (LONG64 *)&src->offset ); + dst->tid = ReadAcquire( (LONG *)&src->tid ); + dst->pid = ReadAcquire( (LONG *)&src->pid ); + dst->padding = ReadAcquire64( (LONG64 *)&src->padding ); + dst->uniq = ReadAcquire64( (LONG64 *)&src->uniq ); + return is_valid_entry_uniq( handle, type, dst->uniq ); +} + +static BOOL get_user_entry( HANDLE handle, unsigned short type, struct user_entry *ret, HANDLE *full ) +{ + UINT index = USER_HANDLE_TO_INDEX( handle ); + const volatile struct user_entry *entry = shared_session->user_entries + index; + + if (!read_acquire_user_entry( handle, type, entry, ret )) return FALSE; + *full = USER_HANDLE_FROM_INDEX( index, ret->generation ); + return TRUE; +} + +static BOOL get_user_entry_at( UINT index, unsigned short type, struct user_entry *ret, HANDLE *full ) +{ + const volatile struct user_entry *entry = shared_session->user_entries + index; + if (!read_acquire_user_entry( 0, type, entry, ret )) return FALSE; + *full = USER_HANDLE_FROM_INDEX( index, ret->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; }
@@ -121,16 +148,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; }
@@ -141,7 +169,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 ); }
/*********************************************************************** @@ -168,7 +196,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();