First part of Proton shared memory series. The full branch can be seen at https://gitlab.winehq.org/rbernon/wine/-/commits/mr/shared-memories.
-- v42: win32u: Use the desktop shared data for GetCursorPos. server: Move the last cursor time to the desktop session object. server: Move the cursor position to the desktop session object. win32u: Open the desktop shared object in NtUserSetThreadDesktop. server: Return the desktop object locator in (get|set)_thread_desktop. server: Allocate shared session object for desktops. include: Add ReadNoFence64 inline helpers. server: Create a global session shared mapping.
From: Rémi Bernon rbernon@codeweavers.com
--- server/directory.c | 7 +++++++ server/file.h | 19 +++++++++++++++++++ server/mapping.c | 45 +++++++++++++++++++++++++++++++++++++++++++++ server/object.c | 13 ++++++++++++- server/object.h | 2 ++ server/protocol.def | 16 ++++++++++++++++ tools/make_requests | 1 + 7 files changed, 102 insertions(+), 1 deletion(-)
diff --git a/server/directory.c b/server/directory.c index 8a140309871..b3f055dfd01 100644 --- a/server/directory.c +++ b/server/directory.c @@ -439,11 +439,14 @@ void init_directories( struct fd *intl_fd ) /* mappings */ static const WCHAR intlW[] = {'N','l','s','S','e','c','t','i','o','n','L','A','N','G','_','I','N','T','L'}; static const WCHAR user_dataW[] = {'_','_','w','i','n','e','_','u','s','e','r','_','s','h','a','r','e','d','_','d','a','t','a'}; + static const WCHAR sessionW[] = {'_','_','w','i','n','e','_','s','e','s','s','i','o','n'}; static const struct unicode_str intl_str = {intlW, sizeof(intlW)}; static const struct unicode_str user_data_str = {user_dataW, sizeof(user_dataW)}; + static const struct unicode_str session_str = {sessionW, sizeof(sessionW)};
struct directory *dir_driver, *dir_device, *dir_global, *dir_kernel, *dir_nls; struct object *named_pipe_device, *mailslot_device, *null_device; + struct mapping *session_mapping; unsigned int i;
root_directory = create_directory( NULL, NULL, OBJ_PERMANENT, HASH_SIZE, NULL ); @@ -491,6 +494,10 @@ void init_directories( struct fd *intl_fd ) release_object( create_user_data_mapping( &dir_kernel->obj, &user_data_str, OBJ_PERMANENT, NULL )); release_object( intl_fd );
+ session_mapping = create_session_mapping( &dir_kernel->obj, &session_str, OBJ_PERMANENT, NULL ); + set_session_mapping( session_mapping ); + release_object( session_mapping ); + release_object( named_pipe_device ); release_object( mailslot_device ); release_object( null_device ); diff --git a/server/file.h b/server/file.h index 7f2d1637863..661e8f9d159 100644 --- a/server/file.h +++ b/server/file.h @@ -188,6 +188,25 @@ extern struct mapping *create_fd_mapping( struct object *root, const struct unic unsigned int attr, const struct security_descriptor *sd ); extern struct object *create_user_data_mapping( struct object *root, const struct unicode_str *name, unsigned int attr, const struct security_descriptor *sd ); +extern struct mapping *create_session_mapping( struct object *root, const struct unicode_str *name, + unsigned int attr, const struct security_descriptor *sd ); +extern void set_session_mapping( struct mapping *mapping ); + +#define SHARED_WRITE_BEGIN( object_shm, type ) \ + do { \ + const type *__shared = (object_shm); \ + type *shared = (type *)__shared; \ + shared_object_t *__obj = CONTAINING_RECORD( shared, shared_object_t, shm ); \ + LONG64 __seq = __obj->seq + 1, __end = __seq + 1; \ + assert( (__seq & 1) != 0 ); \ + __WINE_ATOMIC_STORE_RELEASE( &__obj->seq, &__seq ); \ + do + +#define SHARED_WRITE_END \ + while(0); \ + assert( __seq == __obj->seq ); \ + __WINE_ATOMIC_STORE_RELEASE( &__obj->seq, &__end ); \ + } while(0)
/* device functions */
diff --git a/server/mapping.c b/server/mapping.c index ff99b45ce51..6605c111beb 100644 --- a/server/mapping.c +++ b/server/mapping.c @@ -225,6 +225,23 @@ static const mem_size_t granularity_mask = 0xffff; static struct addr_range ranges32; static struct addr_range ranges64;
+struct session_block +{ + struct list entry; /* entry in the session block list */ + const char *data; /* base pointer for the mmaped data */ +}; + +struct session +{ + struct list blocks; +}; + +static struct mapping *session_mapping; +static struct session session = +{ + .blocks = LIST_INIT(session.blocks), +}; + #define ROUND_SIZE(size) (((size) + page_mask) & ~page_mask)
void init_memory(void) @@ -1256,6 +1273,34 @@ int get_page_size(void) return page_mask + 1; }
+struct mapping *create_session_mapping( struct object *root, const struct unicode_str *name, + unsigned int attr, const struct security_descriptor *sd ) +{ + static const unsigned int access = FILE_READ_DATA | FILE_WRITE_DATA; + mem_size_t size = max( sizeof(shared_object_t) * 512, 0x10000 ); + + return create_mapping( root, name, attr, size, SEC_COMMIT, 0, access, sd ); +} + +void set_session_mapping( struct mapping *mapping ) +{ + int unix_fd = get_unix_fd( mapping->fd ); + mem_size_t size = mapping->size; + struct session_block *block; + void *tmp; + + if (!(block = mem_alloc( sizeof(*block) ))) return; + if ((tmp = mmap( NULL, size, PROT_READ | PROT_WRITE, MAP_SHARED, unix_fd, 0 )) == MAP_FAILED) + { + free( block ); + return; + } + + block->data = tmp; + session_mapping = mapping; + list_add_tail( &session.blocks, &block->entry ); +} + struct object *create_user_data_mapping( struct object *root, const struct unicode_str *name, unsigned int attr, const struct security_descriptor *sd ) { diff --git a/server/object.c b/server/object.c index 459ead5f3a5..3b72b576d50 100644 --- a/server/object.c +++ b/server/object.c @@ -102,8 +102,19 @@ void close_objects(void)
/*****************************************************************/
+/* mark a block of memory as not accessible for debugging purposes */ +void mark_block_noaccess( void *ptr, size_t size ) +{ + memset( ptr, 0xfe, size ); +#if defined(VALGRIND_MAKE_MEM_NOACCESS) + VALGRIND_DISCARD( VALGRIND_MAKE_MEM_NOACCESS( ptr, size ) ); +#elif defined(VALGRIND_MAKE_NOACCESS) + VALGRIND_DISCARD( VALGRIND_MAKE_NOACCESS( ptr, size ) ); +#endif +} + /* mark a block of memory as uninitialized for debugging purposes */ -static inline void mark_block_uninitialized( void *ptr, size_t size ) +void mark_block_uninitialized( void *ptr, size_t size ) { memset( ptr, 0x55, size ); #if defined(VALGRIND_MAKE_MEM_UNDEFINED) diff --git a/server/object.h b/server/object.h index d4d66536b81..2337ee88231 100644 --- a/server/object.h +++ b/server/object.h @@ -139,6 +139,8 @@ struct wait_queue_entry struct thread_wait *wait; };
+extern void mark_block_noaccess( void *ptr, size_t size ); +extern void mark_block_uninitialized( void *ptr, size_t size ); extern void *mem_alloc( size_t size ) __WINE_ALLOC_SIZE(1) __WINE_DEALLOC(free) __WINE_MALLOC; extern void *memdup( const void *data, size_t len ) __WINE_ALLOC_SIZE(2) __WINE_DEALLOC(free); extern void *alloc_object( const struct object_ops *ops ); diff --git a/server/protocol.def b/server/protocol.def index 25184641082..832dfea752b 100644 --- a/server/protocol.def +++ b/server/protocol.def @@ -45,6 +45,7 @@ typedef unsigned __int64 mem_size_t; typedef unsigned __int64 file_pos_t; typedef unsigned __int64 client_ptr_t; typedef unsigned __int64 affinity_t; +typedef unsigned __int64 object_id_t; typedef client_ptr_t mod_handle_t;
struct request_header @@ -895,6 +896,21 @@ struct directory_entry /* VARARG(type,unicode_str,type_len); */ };
+/****************************************************************/ +/* shared session mapping structures */ + +typedef volatile union +{ + char placeholder; +} object_shm_t; + +typedef volatile struct +{ + LONG64 seq; /* sequence number - server updating if (seq & 1) != 0 */ + object_id_t id; /* object unique id, object data is valid if != 0 */ + object_shm_t shm; /* object shared data */ +} shared_object_t; + /****************************************************************/ /* Request declarations */
diff --git a/tools/make_requests b/tools/make_requests index 419b1264ea4..b20b53096ca 100755 --- a/tools/make_requests +++ b/tools/make_requests @@ -42,6 +42,7 @@ my %formats = "file_pos_t" => [ 8, 8, "&dump_uint64" ], "mem_size_t" => [ 8, 8, "&dump_uint64" ], "affinity_t" => [ 8, 8, "&dump_uint64" ], + "object_id_t" => [ 8, 8, "&dump_uint64" ], "timeout_t" => [ 8, 8, "&dump_timeout" ], "abstime_t" => [ 8, 8, "&dump_abstime" ], "rectangle_t" => [ 16, 4, "&dump_rectangle" ],
From: Rémi Bernon rbernon@codeweavers.com
--- include/winnt.h | 16 ++++++++++++++++ 1 file changed, 16 insertions(+)
diff --git a/include/winnt.h b/include/winnt.h index b18d255a79c..42f3dc05a28 100644 --- a/include/winnt.h +++ b/include/winnt.h @@ -7064,11 +7064,14 @@ static FORCEINLINE void MemoryBarrier(void) */ #if _MSC_VER >= 1700 #pragma intrinsic(__iso_volatile_load32) +#pragma intrinsic(__iso_volatile_load64) #pragma intrinsic(__iso_volatile_store32) #define __WINE_LOAD32_NO_FENCE(src) (__iso_volatile_load32(src)) +#define __WINE_LOAD64_NO_FENCE(src) (__iso_volatile_load64(src)) #define __WINE_STORE32_NO_FENCE(dest, value) (__iso_volatile_store32(dest, value)) #else /* _MSC_VER >= 1700 */ #define __WINE_LOAD32_NO_FENCE(src) (*(src)) +#define __WINE_LOAD64_NO_FENCE(src) (*(src)) #define __WINE_STORE32_NO_FENCE(dest, value) ((void)(*(dest) = (value))) #endif /* _MSC_VER >= 1700 */
@@ -7102,6 +7105,12 @@ static FORCEINLINE LONG ReadNoFence( LONG const volatile *src ) return value; }
+static FORCEINLINE LONG64 ReadNoFence64( LONG64 const volatile *src ) +{ + LONG64 value = __WINE_LOAD64_NO_FENCE( (__int64 const volatile *)src ); + return value; +} + static FORCEINLINE void WriteRelease( LONG volatile *dest, LONG value ) { __wine_memory_barrier_acq_rel(); @@ -7288,6 +7297,13 @@ static FORCEINLINE LONG ReadNoFence( LONG const volatile *src ) return value; }
+static FORCEINLINE LONG64 ReadNoFence64( LONG64 const volatile *src ) +{ + LONG64 value; + __WINE_ATOMIC_LOAD_RELAXED( src, &value ); + return value; +} + static FORCEINLINE void WriteRelease( LONG volatile *dest, LONG value ) { __WINE_ATOMIC_STORE_RELEASE( dest, &value );
From: Rémi Bernon rbernon@codeweavers.com
--- server/file.h | 3 ++ server/mapping.c | 106 ++++++++++++++++++++++++++++++++++++++++++++ server/protocol.def | 7 ++- server/user.h | 1 + server/winstation.c | 7 +++ 5 files changed, 123 insertions(+), 1 deletion(-)
diff --git a/server/file.h b/server/file.h index 661e8f9d159..abfc2f0a2ce 100644 --- a/server/file.h +++ b/server/file.h @@ -192,6 +192,9 @@ extern struct mapping *create_session_mapping( struct object *root, const struct unsigned int attr, const struct security_descriptor *sd ); extern void set_session_mapping( struct mapping *mapping );
+extern const volatile void *alloc_shared_object(void); +extern void free_shared_object( const volatile void *object_shm ); + #define SHARED_WRITE_BEGIN( object_shm, type ) \ do { \ const type *__shared = (object_shm); \ diff --git a/server/mapping.c b/server/mapping.c index 6605c111beb..f77de343f4f 100644 --- a/server/mapping.c +++ b/server/mapping.c @@ -229,17 +229,30 @@ struct session_block { struct list entry; /* entry in the session block list */ const char *data; /* base pointer for the mmaped data */ + mem_size_t offset; /* offset of data in the session shared mapping */ + mem_size_t used_size; /* used size for previously allocated objects */ + mem_size_t block_size; /* total size of the block */ +}; + +struct session_object +{ + struct list entry; /* entry in the session free object list */ + mem_size_t offset; /* offset of obj in the session shared mapping */ + shared_object_t obj; /* object actually shared with the client */ };
struct session { struct list blocks; + struct list free_objects; + object_id_t last_object_id; };
static struct mapping *session_mapping; static struct session session = { .blocks = LIST_INIT(session.blocks), + .free_objects = LIST_INIT(session.free_objects), };
#define ROUND_SIZE(size) (((size) + page_mask) & ~page_mask) @@ -1297,10 +1310,103 @@ void set_session_mapping( struct mapping *mapping ) }
block->data = tmp; + block->offset = 0; + block->used_size = 0; + block->block_size = size; + session_mapping = mapping; list_add_tail( &session.blocks, &block->entry ); }
+static struct session_block *grow_session_mapping( mem_size_t needed ) +{ + mem_size_t old_size = session_mapping->size, new_size; + struct session_block *block; + int unix_fd; + void *tmp; + + new_size = max( old_size * 3 / 2, old_size + max( needed, 0x10000 ) ); + new_size = (new_size + page_mask) & ~((mem_size_t)page_mask); + assert( new_size > old_size ); + + unix_fd = get_unix_fd( session_mapping->fd ); + if (!grow_file( unix_fd, new_size )) return NULL; + + if (!(block = mem_alloc( sizeof(*block) ))) return NULL; + if ((tmp = mmap( NULL, new_size - old_size, PROT_READ | PROT_WRITE, MAP_SHARED, unix_fd, old_size )) == MAP_FAILED) + { + file_set_error(); + free( block ); + return NULL; + } + + block->data = tmp; + block->offset = old_size; + block->used_size = 0; + block->block_size = new_size - old_size; + + session_mapping->size = new_size; + list_add_tail( &session.blocks, &block->entry ); + + return block; +} + +static struct session_block *find_free_session_block( mem_size_t size ) +{ + struct session_block *block; + + LIST_FOR_EACH_ENTRY( block, &session.blocks, struct session_block, entry ) + if (size < block->block_size && block->used_size < block->block_size - size) return block; + + return grow_session_mapping( size ); +} + +const volatile void *alloc_shared_object(void) +{ + struct session_object *object; + struct list *ptr; + + if ((ptr = list_head( &session.free_objects ))) + { + object = CONTAINING_RECORD( ptr, struct session_object, entry ); + list_remove( &object->entry ); + } + else + { + mem_size_t size = sizeof(*object); + struct session_block *block; + + if (!(block = find_free_session_block( size ))) return NULL; + object = (struct session_object *)(block->data + block->used_size); + object->offset = (char *)&object->obj - block->data; + block->used_size += size; + } + + SHARED_WRITE_BEGIN( &object->obj.shm, object_shm_t ) + { + /* mark the object data as uninitialized */ + mark_block_uninitialized( (void *)shared, sizeof(*shared) ); + CONTAINING_RECORD( shared, shared_object_t, shm )->id = ++session.last_object_id; + } + SHARED_WRITE_END; + + return &object->obj.shm; +} + +void free_shared_object( const volatile void *object_shm ) +{ + struct session_object *object = CONTAINING_RECORD( object_shm, struct session_object, obj.shm ); + + SHARED_WRITE_BEGIN( &object->obj.shm, object_shm_t ) + { + mark_block_noaccess( (void *)shared, sizeof(*shared) ); + CONTAINING_RECORD( shared, shared_object_t, shm )->id = 0; + } + SHARED_WRITE_END; + + list_add_tail( &session.free_objects, &object->entry ); +} + struct object *create_user_data_mapping( struct object *root, const struct unicode_str *name, unsigned int attr, const struct security_descriptor *sd ) { diff --git a/server/protocol.def b/server/protocol.def index 832dfea752b..aad5d1f2446 100644 --- a/server/protocol.def +++ b/server/protocol.def @@ -899,9 +899,14 @@ struct directory_entry /****************************************************************/ /* shared session mapping structures */
-typedef volatile union +typedef volatile struct { char placeholder; +} desktop_shm_t; + +typedef volatile union +{ + desktop_shm_t desktop; } object_shm_t;
typedef volatile struct diff --git a/server/user.h b/server/user.h index 8ff837a34bf..cb68e4fc314 100644 --- a/server/user.h +++ b/server/user.h @@ -93,6 +93,7 @@ struct desktop struct global_cursor cursor; /* global cursor information */ unsigned char keystate[256]; /* asynchronous key state */ struct key_repeat key_repeat; /* key auto-repeat */ + const desktop_shm_t *shared; /* desktop session shared memory */ };
/* user handles functions */ diff --git a/server/winstation.c b/server/winstation.c index 66fb6ad1e35..270720437b0 100644 --- a/server/winstation.c +++ b/server/winstation.c @@ -298,6 +298,12 @@ static struct desktop *create_desktop( const struct unicode_str *name, unsigned list_add_tail( &winstation->desktops, &desktop->entry ); list_init( &desktop->hotkeys ); list_init( &desktop->pointers ); + + if (!(desktop->shared = alloc_shared_object())) + { + release_object( desktop ); + return NULL; + } } else { @@ -368,6 +374,7 @@ static void desktop_destroy( struct object *obj ) if (desktop->close_timeout) remove_timeout_user( desktop->close_timeout ); if (desktop->key_repeat.timeout) remove_timeout_user( desktop->key_repeat.timeout ); release_object( desktop->winstation ); + if (desktop->shared) free_shared_object( desktop->shared ); }
/* retrieve the thread desktop, checking the handle access rights */
From: Rémi Bernon rbernon@codeweavers.com
--- server/file.h | 1 + server/mapping.c | 7 +++++++ server/protocol.def | 11 ++++++++++- server/trace.c | 8 ++++++++ server/winstation.c | 14 ++++++++++++++ tools/make_requests | 1 + 6 files changed, 41 insertions(+), 1 deletion(-)
diff --git a/server/file.h b/server/file.h index abfc2f0a2ce..89f91c52993 100644 --- a/server/file.h +++ b/server/file.h @@ -194,6 +194,7 @@ extern void set_session_mapping( struct mapping *mapping );
extern const volatile void *alloc_shared_object(void); extern void free_shared_object( const volatile void *object_shm ); +extern obj_locator_t get_shared_object_locator( const volatile void *object_shm );
#define SHARED_WRITE_BEGIN( object_shm, type ) \ do { \ diff --git a/server/mapping.c b/server/mapping.c index f77de343f4f..92eb0c9f076 100644 --- a/server/mapping.c +++ b/server/mapping.c @@ -1407,6 +1407,13 @@ void free_shared_object( const volatile void *object_shm ) list_add_tail( &session.free_objects, &object->entry ); }
+obj_locator_t get_shared_object_locator( const volatile void *object_shm ) +{ + struct session_object *object = CONTAINING_RECORD( object_shm, struct session_object, obj.shm ); + obj_locator_t locator = {.offset = object->offset, .id = object->obj.id}; + return locator; +} + struct object *create_user_data_mapping( struct object *root, const struct unicode_str *name, unsigned int attr, const struct security_descriptor *sd ) { diff --git a/server/protocol.def b/server/protocol.def index aad5d1f2446..b39a8441555 100644 --- a/server/protocol.def +++ b/server/protocol.def @@ -916,6 +916,12 @@ typedef volatile struct object_shm_t shm; /* object shared data */ } shared_object_t;
+typedef struct +{ + object_id_t id; /* object unique id, object data is valid if != 0 */ + mem_size_t offset; /* offset of the object in session shared memory */ +} obj_locator_t; + /****************************************************************/ /* Request declarations */
@@ -2815,13 +2821,16 @@ enum coords_relative @REQ(get_thread_desktop) thread_id_t tid; /* thread id */ @REPLY - obj_handle_t handle; /* handle to the desktop */ + obj_handle_t handle; /* handle to the desktop */ + obj_locator_t locator; /* locator for the shared session object */ @END
/* Set the thread current desktop */ @REQ(set_thread_desktop) obj_handle_t handle; /* handle to the desktop */ +@REPLY + obj_locator_t locator; /* locator for the shared session object */ @END
diff --git a/server/trace.c b/server/trace.c index 1aa0d5c1518..50899ec9224 100644 --- a/server/trace.c +++ b/server/trace.c @@ -467,6 +467,14 @@ static void dump_hw_input( const char *prefix, const hw_input_t *input ) } }
+static void dump_obj_locator( const char *prefix, const obj_locator_t *locator ) +{ + fprintf( stderr, "%s{", prefix ); + dump_uint64( "id=", &locator->id ); + dump_uint64( ",offset=", &locator->offset ); + fprintf( stderr, "}" ); +} + static void dump_luid( const char *prefix, const struct luid *luid ) { fprintf( stderr, "%s%d.%u", prefix, luid->high_part, luid->low_part ); diff --git a/server/winstation.c b/server/winstation.c index 270720437b0..770d0c43e0f 100644 --- a/server/winstation.c +++ b/server/winstation.c @@ -742,10 +742,21 @@ DECL_HANDLER(close_desktop) /* get the thread current desktop */ DECL_HANDLER(get_thread_desktop) { + struct desktop *desktop; struct thread *thread;
+ reply->locator.id = 0; + if (!(thread = get_thread_from_id( req->tid ))) return; reply->handle = thread->desktop; + + if (!(desktop = get_thread_desktop( thread, 0 ))) clear_error(); + else + { + if (desktop->shared) reply->locator = get_shared_object_locator( desktop->shared ); + release_object( desktop ); + } + release_object( thread ); }
@@ -756,6 +767,8 @@ DECL_HANDLER(set_thread_desktop) struct desktop *old_desktop, *new_desktop; struct winstation *winstation;
+ reply->locator.id = 0; + if (!(winstation = get_process_winstation( current->process, 0 /* FIXME: access rights? */ ))) return;
@@ -788,6 +801,7 @@ 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 ); }
if (!current->process->desktop) diff --git a/tools/make_requests b/tools/make_requests index b20b53096ca..36254faec40 100755 --- a/tools/make_requests +++ b/tools/make_requests @@ -53,6 +53,7 @@ my %formats = "generic_map_t" => [ 16, 4, "&dump_generic_map" ], "ioctl_code_t" => [ 4, 4, "&dump_ioctl_code" ], "hw_input_t" => [ 40, 8, "&dump_hw_input" ], + "obj_locator_t" => [ 16, 8, "&dump_obj_locator" ], # varargs-only structures "apc_call_t" => [ 64, 8 ], "context_t" => [ 1728, 8 ],
From: Rémi Bernon rbernon@codeweavers.com
--- dlls/win32u/ntuser_private.h | 1 + dlls/win32u/sysparams.c | 1 + dlls/win32u/win32u_private.h | 8 ++ dlls/win32u/winstation.c | 150 ++++++++++++++++++++++++++++++++++- 4 files changed, 158 insertions(+), 2 deletions(-)
diff --git a/dlls/win32u/ntuser_private.h b/dlls/win32u/ntuser_private.h index 020c98005df..67703cad356 100644 --- a/dlls/win32u/ntuser_private.h +++ b/dlls/win32u/ntuser_private.h @@ -123,6 +123,7 @@ struct user_thread_info UINT spy_indent; /* Current spy indent */ BOOL clipping_cursor; /* thread is currently clipping */ DWORD clipping_reset; /* time when clipping was last reset */ + struct session_thread_data *session_data; /* shared session thread data */ };
C_ASSERT( sizeof(struct user_thread_info) <= sizeof(((TEB *)0)->Win32ClientInfo) ); diff --git a/dlls/win32u/sysparams.c b/dlls/win32u/sysparams.c index 71e52b71719..34de10168e2 100644 --- a/dlls/win32u/sysparams.c +++ b/dlls/win32u/sysparams.c @@ -6340,6 +6340,7 @@ static void thread_detach(void)
cleanup_imm_thread(); NtClose( thread_info->server_queue ); + free( thread_info->session_data );
exiting_thread_id = 0; } diff --git a/dlls/win32u/win32u_private.h b/dlls/win32u/win32u_private.h index 96517ef081a..bc6f5aadc19 100644 --- a/dlls/win32u/win32u_private.h +++ b/dlls/win32u/win32u_private.h @@ -205,6 +205,14 @@ extern void free_vulkan_gpu( struct vulkan_gpu *gpu ); extern BOOL get_vulkan_uuid_from_luid( const LUID *luid, GUID *uuid );
/* winstation.c */ + +struct object_lock +{ + UINT64 id; + UINT64 seq; +}; +#define OBJECT_LOCK_INIT {0} + extern BOOL is_virtual_desktop(void);
/* window.c */ diff --git a/dlls/win32u/winstation.c b/dlls/win32u/winstation.c index 3e71218200a..11ca1a4468c 100644 --- a/dlls/win32u/winstation.c +++ b/dlls/win32u/winstation.c @@ -22,9 +22,14 @@ #pragma makedep unix #endif
+#include <assert.h> +#include <stdarg.h> +#include <stddef.h> + +#include <pthread.h> + #include "ntstatus.h" #define WIN32_NO_STATUS -#include <stdarg.h> #include "windef.h" #include "winbase.h" #include "ntuser.h" @@ -40,6 +45,145 @@ WINE_DECLARE_DEBUG_CHANNEL(win);
#define DESKTOP_ALL_ACCESS 0x01ff
+struct session_thread_data +{ + const shared_object_t *shared_desktop; /* thread desktop shared session cached object */ +}; + +struct session_block +{ + struct list entry; /* entry in the session block list */ + const char *data; /* base pointer for the mmaped data */ + SIZE_T offset; /* offset of data in the session shared mapping */ + SIZE_T size; /* size of the mmaped data */ +}; + +static pthread_mutex_t session_lock = PTHREAD_MUTEX_INITIALIZER; +static struct list session_blocks = LIST_INIT(session_blocks); + +static struct session_thread_data *get_session_thread_data(void) +{ + struct user_thread_info *thread_info = get_user_thread_info(); + if (!thread_info->session_data) thread_info->session_data = calloc(1, sizeof(*thread_info->session_data)); + return thread_info->session_data; +} + +#if defined(__i386__) || defined(__x86_64__) +/* this prevents compilers from incorrectly reordering non-volatile reads (e.g., memcpy) from shared memory */ +#define __SHARED_READ_FENCE do { __asm__ __volatile__( "" ::: "memory" ); } while (0) +#else +#define __SHARED_READ_FENCE __atomic_thread_fence( __ATOMIC_ACQUIRE ) +#endif + +static void shared_object_acquire_seqlock( const shared_object_t *object, UINT64 *seq ) +{ + while ((*seq = ReadNoFence64( &object->seq )) & 1) YieldProcessor(); + __SHARED_READ_FENCE; +} + +static BOOL shared_object_release_seqlock( const shared_object_t *object, UINT64 seq ) +{ + __SHARED_READ_FENCE; + return ReadNoFence64( &object->seq ) == seq; +} + +static object_id_t shared_object_get_id( const shared_object_t *object ) +{ + struct object_lock lock = OBJECT_LOCK_INIT; + do + { + shared_object_acquire_seqlock( object, &lock.seq ); + lock.id = object->id; + } while (!shared_object_release_seqlock( object, lock.seq )); + return lock.id; +} + +static NTSTATUS map_shared_session_block( SIZE_T offset, SIZE_T size, struct session_block **ret ) +{ + static const WCHAR nameW[] = + { + '\','K','e','r','n','e','l','O','b','j','e','c','t','s','\', + '_','_','w','i','n','e','_','s','e','s','s','i','o','n',0 + }; + UNICODE_STRING name = RTL_CONSTANT_STRING( nameW ); + LARGE_INTEGER off = {.QuadPart = offset - (offset % system_info.AllocationGranularity)}; + struct session_block *block; + OBJECT_ATTRIBUTES attr; + unsigned int status; + HANDLE handle; + + assert( offset + size > offset ); + + if (!(block = calloc( 1, sizeof(*block) ))) return STATUS_NO_MEMORY; + + InitializeObjectAttributes( &attr, &name, 0, NULL, NULL ); + if ((status = NtOpenSection( &handle, SECTION_MAP_READ, &attr ))) + WARN( "Failed to open shared session section, status %#x\n", status ); + else + { + if ((status = NtMapViewOfSection( handle, GetCurrentProcess(), (void **)&block->data, 0, 0, + &off, &block->size, ViewUnmap, 0, PAGE_READONLY ))) + WARN( "Failed to map shared session block, status %#x\n", status ); + else + { + list_add_tail( &session_blocks, &block->entry ); + block->offset = off.QuadPart; + assert( block->offset + block->size > block->offset ); + } + NtClose( handle ); + } + + if (status) free( block ); + else *ret = block; + return status; +} + +static NTSTATUS find_shared_session_block( SIZE_T offset, SIZE_T size, struct session_block **ret ) +{ + struct session_block *block; + UINT status; + + assert( offset + size > offset ); + + pthread_mutex_lock( &session_lock ); + + LIST_FOR_EACH_ENTRY( block, &session_blocks, struct session_block, entry ) + { + if (block->offset < offset && offset + size <= block->offset + block->size) + { + *ret = block; + pthread_mutex_unlock( &session_lock ); + return STATUS_SUCCESS; + } + } + + if ((status = map_shared_session_block( offset, size, ret ))) + { + WARN( "Failed to map session block for offset %s, size %s, status %#x\n", + wine_dbgstr_longlong(offset), wine_dbgstr_longlong(size), status ); + } + + pthread_mutex_unlock( &session_lock ); + + return status; +} + +static const shared_object_t *find_shared_session_object( obj_locator_t locator ) +{ + const shared_object_t *object; + struct session_block *block; + NTSTATUS status; + + if (locator.id && !(status = find_shared_session_block( locator.offset, sizeof(*object), &block ))) + { + object = (const shared_object_t *)(block->data + locator.offset - block->offset); + if (locator.id == shared_object_get_id( object )) return object; + WARN( "Session object id doesn't match expected id %s\n", wine_dbgstr_longlong(locator.id) ); + } + + return NULL; +} + BOOL is_virtual_desktop(void) { HANDLE desktop = NtUserGetThreadDesktop( GetCurrentThreadId() ); @@ -249,11 +393,12 @@ HDESK WINAPI NtUserGetThreadDesktop( DWORD thread ) BOOL WINAPI NtUserSetThreadDesktop( HDESK handle ) { BOOL ret, was_virtual_desktop = is_virtual_desktop(); + obj_locator_t locator = {0};
SERVER_START_REQ( set_thread_desktop ) { req->handle = wine_server_obj_handle( handle ); - ret = !wine_server_call_err( req ); + if ((ret = !wine_server_call_err( req ))) locator = reply->locator; } SERVER_END_REQ;
@@ -261,6 +406,7 @@ BOOL WINAPI NtUserSetThreadDesktop( HDESK handle ) { struct user_thread_info *thread_info = get_user_thread_info(); struct user_key_state_info *key_state_info = thread_info->key_state; + get_session_thread_data()->shared_desktop = find_shared_session_object( locator ); thread_info->client_info.top_window = 0; thread_info->client_info.msg_window = 0; if (key_state_info) key_state_info->time = 0;
From: Rémi Bernon rbernon@codeweavers.com
Based on a patch by Huw Davies huw@codeweavers.com. --- server/protocol.def | 8 ++++- server/queue.c | 78 ++++++++++++++++++++++++++++----------------- server/user.h | 2 -- server/winstation.c | 7 ++++ 4 files changed, 62 insertions(+), 33 deletions(-)
diff --git a/server/protocol.def b/server/protocol.def index b39a8441555..fc7ae3c0984 100644 --- a/server/protocol.def +++ b/server/protocol.def @@ -899,9 +899,15 @@ struct directory_entry /****************************************************************/ /* shared session mapping structures */
+struct shared_cursor +{ + int x; /* cursor position */ + int y; +}; + typedef volatile struct { - char placeholder; + struct shared_cursor cursor; /* global cursor information */ } desktop_shm_t;
typedef volatile union diff --git a/server/queue.c b/server/queue.c index 5a6f954bc4d..a1dbd133209 100644 --- a/server/queue.c +++ b/server/queue.c @@ -419,6 +419,7 @@ static void queue_cursor_message( struct desktop *desktop, user_handle_t win, un lparam_t wparam, lparam_t lparam ) { static const struct hw_msg_source source = { IMDT_UNAVAILABLE, IMO_SYSTEM }; + const desktop_shm_t *desktop_shm = desktop->shared; struct thread_input *input; struct message *msg;
@@ -427,8 +428,8 @@ static void queue_cursor_message( struct desktop *desktop, user_handle_t win, un msg->msg = message; msg->wparam = wparam; msg->lparam = lparam; - msg->x = desktop->cursor.x; - msg->y = desktop->cursor.y; + msg->x = desktop_shm->cursor.x; + msg->y = desktop_shm->cursor.y; if (!(msg->win = win) && (input = desktop->foreground_input)) msg->win = input->active; queue_hardware_message( desktop, msg, 1 ); } @@ -466,13 +467,20 @@ static int update_desktop_cursor_window( struct desktop *desktop, user_handle_t
static int update_desktop_cursor_pos( struct desktop *desktop, user_handle_t win, int x, int y ) { + const desktop_shm_t *desktop_shm = desktop->shared; int updated;
x = max( min( x, desktop->cursor.clip.right - 1 ), desktop->cursor.clip.left ); y = max( min( y, desktop->cursor.clip.bottom - 1 ), desktop->cursor.clip.top ); - updated = (desktop->cursor.x != x || desktop->cursor.y != y); - desktop->cursor.x = x; - desktop->cursor.y = y; + + SHARED_WRITE_BEGIN( desktop_shm, desktop_shm_t ) + { + updated = shared->cursor.x != x || shared->cursor.y != y; + shared->cursor.x = x; + shared->cursor.y = y; + } + SHARED_WRITE_END; + desktop->cursor.last_change = get_tick_count();
if (!win || !is_window_visible( win ) || is_window_transparent( win )) @@ -518,15 +526,17 @@ static void set_cursor_pos( struct desktop *desktop, int x, int y ) static void get_message_defaults( struct msg_queue *queue, int *x, int *y, unsigned int *time ) { struct desktop *desktop = queue->input->desktop; + const desktop_shm_t *desktop_shm = desktop->shared;
- *x = desktop->cursor.x; - *y = desktop->cursor.y; + *x = desktop_shm->cursor.x; + *y = desktop_shm->cursor.y; *time = get_tick_count(); }
/* set the cursor clip rectangle */ void set_clip_rectangle( struct desktop *desktop, const rectangle_t *rect, unsigned int flags, int reset ) { + const desktop_shm_t *desktop_shm = desktop->shared; rectangle_t top_rect; unsigned int old_flags; int x, y; @@ -548,9 +558,9 @@ void set_clip_rectangle( struct desktop *desktop, const rectangle_t *rect, unsig desktop->cursor.clip_flags = flags;
/* warp the mouse to be inside the clip rect */ - x = max( min( desktop->cursor.x, desktop->cursor.clip.right - 1 ), desktop->cursor.clip.left ); - y = max( min( desktop->cursor.y, desktop->cursor.clip.bottom - 1 ), desktop->cursor.clip.top ); - if (x != desktop->cursor.x || y != desktop->cursor.y) set_cursor_pos( desktop, x, y ); + x = max( min( desktop_shm->cursor.x, desktop->cursor.clip.right - 1 ), desktop->cursor.clip.left ); + y = max( min( desktop_shm->cursor.y, desktop->cursor.clip.bottom - 1 ), desktop->cursor.clip.top ); + if (x != desktop_shm->cursor.x || y != desktop_shm->cursor.y) set_cursor_pos( desktop, x, y );
/* request clip cursor rectangle reset to the desktop thread */ if (reset) post_desktop_message( desktop, WM_WINE_CLIPCURSOR, flags, FALSE ); @@ -1672,6 +1682,7 @@ static unsigned int get_rawinput_device_flags( struct process *process, struct m /* queue a hardware message into a given thread input */ static void queue_hardware_message( struct desktop *desktop, struct message *msg, int always_queue ) { + const desktop_shm_t *desktop_shm = desktop->shared; user_handle_t win; struct thread *thread; struct thread_input *input; @@ -1705,8 +1716,8 @@ static void queue_hardware_message( struct desktop *desktop, struct message *msg if (desktop->keystate[VK_XBUTTON2] & 0x80) msg->wparam |= MK_XBUTTON2; break; } - msg->x = desktop->cursor.x; - msg->y = desktop->cursor.y; + msg->x = desktop_shm->cursor.x; + msg->y = desktop_shm->cursor.y;
if (msg->win && (thread = get_window_thread( msg->win ))) { @@ -1982,6 +1993,7 @@ static void dispatch_rawinput_message( struct desktop *desktop, struct rawinput_ static int queue_mouse_message( struct desktop *desktop, user_handle_t win, const hw_input_t *input, unsigned int origin, struct msg_queue *sender ) { + const desktop_shm_t *desktop_shm = desktop->shared; struct hardware_msg_data *msg_data; struct rawinput_message raw_msg; struct message *msg; @@ -2020,19 +2032,19 @@ static int queue_mouse_message( struct desktop *desktop, user_handle_t win, cons x = input->mouse.x; y = input->mouse.y; if (flags & ~(MOUSEEVENTF_MOVE | MOUSEEVENTF_ABSOLUTE) && - x == desktop->cursor.x && y == desktop->cursor.y) + x == desktop_shm->cursor.x && y == desktop_shm->cursor.y) flags &= ~MOUSEEVENTF_MOVE; } else { - x = desktop->cursor.x + input->mouse.x; - y = desktop->cursor.y + input->mouse.y; + x = desktop_shm->cursor.x + input->mouse.x; + y = desktop_shm->cursor.y + input->mouse.y; } } else { - x = desktop->cursor.x; - y = desktop->cursor.y; + x = desktop_shm->cursor.x; + y = desktop_shm->cursor.y; }
if ((foreground = get_foreground_thread( desktop, win ))) @@ -2043,7 +2055,7 @@ static int queue_mouse_message( struct desktop *desktop, user_handle_t win, cons raw_msg.time = time; raw_msg.message = WM_INPUT; raw_msg.flags = flags; - rawmouse_init( &raw_msg.rawinput, &raw_msg.data.mouse, x - desktop->cursor.x, y - desktop->cursor.y, + rawmouse_init( &raw_msg.rawinput, &raw_msg.data.mouse, x - desktop_shm->cursor.x, y - desktop_shm->cursor.y, raw_msg.flags, input->mouse.data, input->mouse.info );
dispatch_rawinput_message( desktop, &raw_msg ); @@ -2293,6 +2305,7 @@ static void queue_pointer_message( struct pointer *pointer, int repeated ) }; struct hw_msg_source source = { IMDT_UNAVAILABLE, IMDT_TOUCH }; struct desktop *desktop = pointer->desktop; + const desktop_shm_t *desktop_shm = desktop->shared; const hw_input_t *input = &pointer->input; unsigned int i, wparam = input->hw.wparam; timeout_t time = get_tick_count(); @@ -2315,8 +2328,8 @@ static void queue_pointer_message( struct pointer *pointer, int repeated ) msg->msg = messages[input->hw.msg - WM_POINTERUPDATE][i]; msg->wparam = wparam; msg->lparam = MAKELONG(x, y); - msg->x = desktop->cursor.x; - msg->y = desktop->cursor.y; + msg->x = desktop_shm->cursor.x; + msg->y = desktop_shm->cursor.y;
queue_hardware_message( desktop, msg, 1 ); } @@ -2371,6 +2384,7 @@ static struct pointer *find_pointer_from_id( struct desktop *desktop, unsigned i static void queue_custom_hardware_message( struct desktop *desktop, user_handle_t win, unsigned int origin, const hw_input_t *input ) { + const desktop_shm_t *desktop_shm = desktop->shared; struct hw_msg_source source = { IMDT_UNAVAILABLE, origin }; struct thread *foreground; struct pointer *pointer; @@ -2415,8 +2429,8 @@ static void queue_custom_hardware_message( struct desktop *desktop, user_handle_ msg->msg = input->hw.msg; msg->wparam = input->hw.wparam; msg->lparam = input->hw.lparam; - msg->x = desktop->cursor.x; - msg->y = desktop->cursor.y; + msg->x = desktop_shm->cursor.x; + msg->y = desktop_shm->cursor.y;
queue_hardware_message( desktop, msg, 1 ); } @@ -2964,6 +2978,7 @@ DECL_HANDLER(send_hardware_message) struct desktop *desktop; unsigned int origin = (req->flags & SEND_HWMSG_INJECTED ? IMO_INJECTED : IMO_HARDWARE); struct msg_queue *sender = req->flags & SEND_HWMSG_INJECTED ? get_current_queue() : NULL; + const desktop_shm_t *desktop_shm; int wait = 0;
if (!(desktop = get_hardware_input_desktop( req->win ))) return; @@ -2974,9 +2989,10 @@ DECL_HANDLER(send_hardware_message) set_error( STATUS_ACCESS_DENIED ); return; } + desktop_shm = desktop->shared;
- reply->prev_x = desktop->cursor.x; - reply->prev_y = desktop->cursor.y; + reply->prev_x = desktop_shm->cursor.x; + reply->prev_y = desktop_shm->cursor.y;
switch (req->input.type) { @@ -2994,8 +3010,8 @@ DECL_HANDLER(send_hardware_message) }
reply->wait = sender ? wait : 0; - reply->new_x = desktop->cursor.x; - reply->new_y = desktop->cursor.y; + reply->new_x = desktop_shm->cursor.x; + reply->new_y = desktop_shm->cursor.y; release_object( desktop ); }
@@ -3688,16 +3704,18 @@ DECL_HANDLER(set_cursor) user_handle_t prev_cursor, new_cursor; struct thread_input *input; struct desktop *desktop; + const desktop_shm_t *desktop_shm;
if (!queue) return; input = queue->input; desktop = input->desktop; + desktop_shm = desktop->shared; prev_cursor = input->cursor_count < 0 ? 0 : input->cursor;
reply->prev_handle = input->cursor; reply->prev_count = input->cursor_count; - reply->prev_x = desktop->cursor.x; - reply->prev_y = desktop->cursor.y; + reply->prev_x = desktop_shm->cursor.x; + reply->prev_y = desktop_shm->cursor.y;
if (req->flags & SET_CURSOR_HANDLE) { @@ -3720,8 +3738,8 @@ DECL_HANDLER(set_cursor) new_cursor = input->cursor_count < 0 ? 0 : input->cursor; if (prev_cursor != new_cursor) update_desktop_cursor_handle( desktop, input, new_cursor );
- reply->new_x = desktop->cursor.x; - reply->new_y = desktop->cursor.y; + reply->new_x = desktop_shm->cursor.x; + reply->new_y = desktop_shm->cursor.y; reply->new_clip = desktop->cursor.clip; reply->last_change = desktop->cursor.last_change; } diff --git a/server/user.h b/server/user.h index cb68e4fc314..e6f8a39e5ea 100644 --- a/server/user.h +++ b/server/user.h @@ -56,8 +56,6 @@ struct winstation
struct global_cursor { - int x; /* cursor position */ - int y; rectangle_t clip; /* cursor clip rectangle */ unsigned int clip_flags; /* last cursor clip flags */ unsigned int last_change; /* time of last position change */ diff --git a/server/winstation.c b/server/winstation.c index 770d0c43e0f..c78a17f0343 100644 --- a/server/winstation.c +++ b/server/winstation.c @@ -304,6 +304,13 @@ static struct desktop *create_desktop( const struct unicode_str *name, unsigned release_object( desktop ); return NULL; } + + SHARED_WRITE_BEGIN( desktop->shared, desktop_shm_t ) + { + shared->cursor.x = 0; + shared->cursor.y = 0; + } + SHARED_WRITE_END; } else {
From: Rémi Bernon rbernon@codeweavers.com
Based on a patch by Huw Davies huw@codeweavers.com. --- server/protocol.def | 1 + server/queue.c | 17 +++++++++++------ server/user.h | 1 - server/winstation.c | 1 + 4 files changed, 13 insertions(+), 7 deletions(-)
diff --git a/server/protocol.def b/server/protocol.def index fc7ae3c0984..41e732e8994 100644 --- a/server/protocol.def +++ b/server/protocol.def @@ -903,6 +903,7 @@ struct shared_cursor { int x; /* cursor position */ int y; + unsigned int last_change; /* time of last position change */ };
typedef volatile struct diff --git a/server/queue.c b/server/queue.c index a1dbd133209..c2e957cfd21 100644 --- a/server/queue.c +++ b/server/queue.c @@ -469,6 +469,7 @@ static int update_desktop_cursor_pos( struct desktop *desktop, user_handle_t win { const desktop_shm_t *desktop_shm = desktop->shared; int updated; + unsigned int time = get_tick_count();
x = max( min( x, desktop->cursor.clip.right - 1 ), desktop->cursor.clip.left ); y = max( min( y, desktop->cursor.clip.bottom - 1 ), desktop->cursor.clip.top ); @@ -478,11 +479,10 @@ static int update_desktop_cursor_pos( struct desktop *desktop, user_handle_t win updated = shared->cursor.x != x || shared->cursor.y != y; shared->cursor.x = x; shared->cursor.y = y; + shared->cursor.last_change = time; } SHARED_WRITE_END;
- desktop->cursor.last_change = get_tick_count(); - if (!win || !is_window_visible( win ) || is_window_transparent( win )) win = shallow_window_from_point( desktop, x, y ); if (update_desktop_cursor_window( desktop, win )) updated = 1; @@ -1998,7 +1998,7 @@ static int queue_mouse_message( struct desktop *desktop, user_handle_t win, cons struct rawinput_message raw_msg; struct message *msg; struct thread *foreground; - unsigned int i, time, flags; + unsigned int i, time = get_tick_count(), flags; struct hw_msg_source source = { IMDT_MOUSE, origin }; lparam_t wparam = input->mouse.data << 16; int wait = 0, x, y; @@ -2020,10 +2020,15 @@ static int queue_mouse_message( struct desktop *desktop, user_handle_t win, cons WM_MOUSEHWHEEL /* 0x1000 = MOUSEEVENTF_HWHEEL */ };
- desktop->cursor.last_change = get_tick_count(); + SHARED_WRITE_BEGIN( desktop_shm, desktop_shm_t ) + { + shared->cursor.last_change = time; + } + SHARED_WRITE_END; + flags = input->mouse.flags; time = input->mouse.time; - if (!time) time = desktop->cursor.last_change; + if (!time) time = desktop_shm->cursor.last_change;
if (flags & MOUSEEVENTF_MOVE) { @@ -3741,7 +3746,7 @@ DECL_HANDLER(set_cursor) reply->new_x = desktop_shm->cursor.x; reply->new_y = desktop_shm->cursor.y; reply->new_clip = desktop->cursor.clip; - reply->last_change = desktop->cursor.last_change; + reply->last_change = desktop_shm->cursor.last_change; }
/* Get the history of the 64 last cursor positions */ diff --git a/server/user.h b/server/user.h index e6f8a39e5ea..a20aff99284 100644 --- a/server/user.h +++ b/server/user.h @@ -58,7 +58,6 @@ struct global_cursor { rectangle_t clip; /* cursor clip rectangle */ unsigned int clip_flags; /* last cursor clip flags */ - unsigned int last_change; /* time of last position change */ user_handle_t win; /* window that contains the cursor */ };
diff --git a/server/winstation.c b/server/winstation.c index c78a17f0343..84abfe9f682 100644 --- a/server/winstation.c +++ b/server/winstation.c @@ -309,6 +309,7 @@ static struct desktop *create_desktop( const struct unicode_str *name, unsigned { shared->cursor.x = 0; shared->cursor.y = 0; + shared->cursor.last_change = 0; } SHARED_WRITE_END; }
From: Rémi Bernon rbernon@codeweavers.com
Based on a patch by Huw Davies huw@codeweavers.com. --- dlls/win32u/input.c | 18 +++++++++--------- dlls/win32u/win32u_private.h | 8 ++++++++ dlls/win32u/winstation.c | 34 ++++++++++++++++++++++++++++++++++ 3 files changed, 51 insertions(+), 9 deletions(-)
diff --git a/dlls/win32u/input.c b/dlls/win32u/input.c index 5b25086cb6f..2fbe21e56af 100644 --- a/dlls/win32u/input.c +++ b/dlls/win32u/input.c @@ -740,22 +740,22 @@ BOOL WINAPI NtUserSetCursorPos( INT x, INT y ) */ BOOL get_cursor_pos( POINT *pt ) { + struct object_lock lock = OBJECT_LOCK_INIT; + const desktop_shm_t *desktop_shm; BOOL ret; - DWORD last_change; + DWORD last_change = 0; + NTSTATUS status; UINT dpi;
if (!pt) return FALSE;
- SERVER_START_REQ( set_cursor ) + while ((status = get_shared_desktop( &lock, &desktop_shm )) == STATUS_PENDING) { - if ((ret = !wine_server_call( req ))) - { - pt->x = reply->new_x; - pt->y = reply->new_y; - last_change = reply->last_change; - } + pt->x = desktop_shm->cursor.x; + pt->y = desktop_shm->cursor.y; + last_change = desktop_shm->cursor.last_change; } - SERVER_END_REQ; + ret = !status;
/* query new position from graphics driver if we haven't updated recently */ if (ret && NtGetTickCount() - last_change > 100) ret = user_driver->pGetCursorPos( pt ); diff --git a/dlls/win32u/win32u_private.h b/dlls/win32u/win32u_private.h index bc6f5aadc19..f7ba2c1a423 100644 --- a/dlls/win32u/win32u_private.h +++ b/dlls/win32u/win32u_private.h @@ -213,6 +213,14 @@ struct object_lock }; #define OBJECT_LOCK_INIT {0}
+/* Get shared session object's data pointer, must be called in a loop while STATUS_PENDING + * is returned, lock must be initialized with OBJECT_LOCK_INIT. + * + * 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_desktop( struct object_lock *lock, const desktop_shm_t **desktop_shm ); + extern BOOL is_virtual_desktop(void);
/* window.c */ diff --git a/dlls/win32u/winstation.c b/dlls/win32u/winstation.c index 11ca1a4468c..b9722f5444d 100644 --- a/dlls/win32u/winstation.c +++ b/dlls/win32u/winstation.c @@ -184,6 +184,40 @@ static const shared_object_t *find_shared_session_object( obj_locator_t locator return NULL; }
+NTSTATUS get_shared_desktop( struct object_lock *lock, const desktop_shm_t **desktop_shm ) +{ + struct session_thread_data *data = get_session_thread_data(); + const shared_object_t *object; + + TRACE( "lock %p, desktop_shm %p\n", lock, desktop_shm ); + + if (!(object = data->shared_desktop)) + { + obj_locator_t locator = {0}; + + SERVER_START_REQ( get_thread_desktop ) + { + req->tid = GetCurrentThreadId(); + if (!wine_server_call( req )) locator = reply->locator; + } + SERVER_END_REQ; + + data->shared_desktop = find_shared_session_object( locator ); + if (!(object = data->shared_desktop)) 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 ); + *desktop_shm = &object->shm.desktop; + lock->id = object->id; + return STATUS_PENDING; + } + + return STATUS_SUCCESS; +} + BOOL is_virtual_desktop(void) { HANDLE desktop = NtUserGetThreadDesktop( GetCurrentThreadId() );
On Tue Jun 18 16:57:20 2024 +0000, Rémi Bernon wrote:
Rebased.
@rbernon in `wip/shared-memories` you have a typo in `win32u: Use the session objects for every thread in NtUserGetGUIThreadInfo` https://gitlab.winehq.org/rbernon/wine/-/commit/85e5a0b960f6b07861bec6da46fb... . `input_shm->rect` doesn't exist, should probably be `input_shm->caret_rect`.
https://gitlab.winehq.org/rbernon/wine/-/blob/wip/shared-memories/dlls/win32... https://gitlab.winehq.org/rbernon/wine/-/blob/wip/shared-memories/server/pro...
Thanks for rebase.