First part of Proton shared memory series. The full branch can be seen at https://gitlab.winehq.org/rbernon/wine/-/commits/mr/shared-memories.
-- v6: user32: Use the desktop shared data for GetCursorPos(). server: Add a sequence number to the shared data. server: Move the cursor position and last change time to the shared data. server: Use the helper to update the cursor last change time. server: Create a desktop shared mapping.
From: Rémi Bernon rbernon@codeweavers.com
Based on a patch by Huw Davies huw@codeweavers.com. --- server/directory.c | 17 +++++++++++++++++ server/file.h | 6 ++++++ server/mapping.c | 29 +++++++++++++++++++++++++++++ server/protocol.def | 6 ++++++ server/user.h | 2 ++ server/winstation.c | 24 ++++++++++++++++++++++++ 6 files changed, 84 insertions(+)
diff --git a/server/directory.c b/server/directory.c index 23d7eb0a2b7..5c8671d6146 100644 --- a/server/directory.c +++ b/server/directory.c @@ -37,6 +37,7 @@ #include "process.h" #include "file.h" #include "unicode.h" +#include "user.h"
#define HASH_SIZE 7 /* default hash size */
@@ -277,6 +278,22 @@ struct object *get_directory_obj( struct process *process, obj_handle_t handle ) return get_handle_obj( process, handle, 0, &directory_ops ); }
+struct object *create_desktop_map_directory( struct winstation *winstation ) +{ + static const WCHAR dir_desktop_mapsW[] = {'_','_','w','i','n','e','_','d','e','s','k','t','o','p','_','m','a','p','p','i','n','g','s'}; + static const struct unicode_str dir_desktop_maps_str = {dir_desktop_mapsW, sizeof(dir_desktop_mapsW)}; + struct object *root; + struct directory *mapping_root, *ret; + const struct unicode_str winsta_name = {winstation->obj.name->name, winstation->obj.name->len}; + + root = winstation->obj.name->parent; + mapping_root = create_directory( root, &dir_desktop_maps_str, OBJ_OPENIF, HASH_SIZE, NULL ); + ret = create_directory( &mapping_root->obj, &winsta_name, OBJ_OPENIF, HASH_SIZE, NULL ); + release_object( &mapping_root->obj ); + + return &ret->obj; +} + /* Global initialization */
static void create_session( unsigned int id ) diff --git a/server/file.h b/server/file.h index a43b4afad08..85aba366847 100644 --- a/server/file.h +++ b/server/file.h @@ -156,6 +156,10 @@ extern struct timeout_user *add_timeout_user( timeout_t when, timeout_callback f extern void remove_timeout_user( struct timeout_user *user ); extern const char *get_timeout_str( timeout_t timeout );
+/* directory functions */ + +extern struct object *create_desktop_map_directory( struct winstation *winstation ); + /* file functions */
extern struct file *get_file_obj( struct process *process, obj_handle_t handle, @@ -182,6 +186,8 @@ extern void free_mapped_views( struct process *process ); extern int get_page_size(void); extern struct mapping *create_fd_mapping( struct object *root, const struct unicode_str *name, struct fd *fd, unsigned int attr, const struct security_descriptor *sd ); +extern struct object *create_shared_mapping( struct object *root, const struct unicode_str *name, mem_size_t size, + unsigned int attr, const struct security_descriptor *sd, void **ptr ); extern 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/mapping.c b/server/mapping.c index 5d4df2050e4..e01b9b781d7 100644 --- a/server/mapping.c +++ b/server/mapping.c @@ -29,6 +29,7 @@ #include <sys/stat.h> #include <sys/mman.h> #include <unistd.h> +#include <errno.h>
#include "ntstatus.h" #define WIN32_NO_STATUS @@ -161,6 +162,7 @@ struct mapping pe_image_info_t image; /* image info (for PE image mapping) */ struct ranges *committed; /* list of committed ranges in this mapping */ struct shared_map *shared; /* temp file for shared PE mapping */ + void *shared_ptr; /* mmaped pointer for shared mappings */ };
static void mapping_dump( struct object *obj, int verbose ); @@ -896,6 +898,7 @@ static struct mapping *create_mapping( struct object *root, const struct unicode mapping->fd = NULL; mapping->shared = NULL; mapping->committed = NULL; + mapping->shared_ptr = MAP_FAILED;
if (!(mapping->flags = get_mapping_flags( handle, flags ))) goto error;
@@ -1096,6 +1099,7 @@ static void mapping_destroy( struct object *obj ) if (mapping->fd) release_object( mapping->fd ); if (mapping->committed) release_object( mapping->committed ); if (mapping->shared) release_object( mapping->shared ); + if (mapping->shared_ptr != MAP_FAILED) munmap( mapping->shared_ptr, mapping->size ); }
static enum server_fd_type mapping_get_fd_type( struct fd *fd ) @@ -1109,6 +1113,31 @@ int get_page_size(void) return page_mask + 1; }
+struct object *create_shared_mapping( struct object *root, const struct unicode_str *name, mem_size_t size, + unsigned int attr, const struct security_descriptor *sd, void **ptr ) +{ + static unsigned int access = FILE_READ_DATA | FILE_WRITE_DATA; + struct mapping *mapping; + + if (!(mapping = create_mapping( root, name, attr, size, SEC_COMMIT, 0, access, sd ))) return NULL; + + if (mapping->shared_ptr == MAP_FAILED) + { + int fd = get_unix_fd( mapping->fd ); + + mapping->shared_ptr = mmap( NULL, mapping->size, PROT_WRITE, MAP_SHARED, fd, 0 ); + if (mapping->shared_ptr == MAP_FAILED) + { + fprintf( stderr, "wine: Failed to map shared memory: %u %m\n", errno ); + release_object( &mapping->obj ); + return NULL; + } + } + + *ptr = mapping->shared_ptr; + return &mapping->obj; +} + 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 919297c818c..d6cfd8e9f72 100644 --- a/server/protocol.def +++ b/server/protocol.def @@ -890,6 +890,12 @@ typedef struct lparam_t info; } cursor_pos_t;
+struct desktop_shared_memory +{ + int placeholder; +}; +typedef volatile struct desktop_shared_memory desktop_shm_t; + /****************************************************************/ /* Request declarations */
diff --git a/server/user.h b/server/user.h index b6f47bcac1c..20b7acb6fdc 100644 --- a/server/user.h +++ b/server/user.h @@ -77,6 +77,8 @@ struct desktop unsigned int users; /* processes and threads using this desktop */ struct global_cursor cursor; /* global cursor information */ unsigned char keystate[256]; /* asynchronous key state */ + struct object *shared_mapping; /* desktop shared memory mapping */ + const desktop_shm_t *shared; /* desktop shared memory */ };
/* user handles functions */ diff --git a/server/winstation.c b/server/winstation.c index 5903497d61e..524ee753f90 100644 --- a/server/winstation.c +++ b/server/winstation.c @@ -217,6 +217,22 @@ struct desktop *get_desktop_obj( struct process *process, obj_handle_t handle, u return (struct desktop *)get_handle_obj( process, handle, access, &desktop_ops ); }
+static int init_desktop_mapping( struct desktop *desktop, const struct unicode_str *name ) +{ + struct object *dir; + + desktop->shared = NULL; + desktop->shared_mapping = NULL; + + if (!(dir = create_desktop_map_directory( desktop->winstation ))) return 0; + if ((desktop->shared_mapping = create_shared_mapping( dir, name, sizeof(struct desktop_shared_memory), + 0, NULL, (void **)&desktop->shared ))) + memset( (void *)desktop->shared, 0, sizeof(*desktop->shared) ); + release_object( dir ); + + return !!desktop->shared; +} + /* create a desktop object */ static struct desktop *create_desktop( const struct unicode_str *name, unsigned int attr, unsigned int flags, struct winstation *winstation ) @@ -240,6 +256,11 @@ static struct desktop *create_desktop( const struct unicode_str *name, unsigned memset( desktop->keystate, 0, sizeof(desktop->keystate) ); list_add_tail( &winstation->desktops, &desktop->entry ); list_init( &desktop->hotkeys ); + if (!init_desktop_mapping( desktop, name )) + { + release_object( desktop ); + return NULL; + } } else { @@ -297,6 +318,8 @@ static void desktop_destroy( struct object *obj ) if (desktop->global_hooks) release_object( desktop->global_hooks ); if (desktop->close_timeout) remove_timeout_user( desktop->close_timeout ); list_remove( &desktop->entry ); + if (desktop->shared_mapping) release_object( desktop->shared_mapping ); + desktop->shared_mapping = NULL; release_object( desktop->winstation ); }
@@ -312,6 +335,7 @@ static void close_desktop_timeout( void *private )
desktop->close_timeout = NULL; unlink_named_object( &desktop->obj ); /* make sure no other process can open it */ + unlink_named_object( desktop->shared_mapping ); post_desktop_message( desktop, WM_CLOSE, 0, 0 ); /* and signal the owner to quit */ }
From: Rémi Bernon rbernon@codeweavers.com
Based on a patch by Huw Davies huw@codeweavers.com. --- server/queue.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-)
diff --git a/server/queue.c b/server/queue.c index fcc946ff0cb..51e01a471bf 100644 --- a/server/queue.c +++ b/server/queue.c @@ -1873,7 +1873,9 @@ 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(); + /* update last desktop cursor change time */ + update_desktop_cursor_pos( desktop, desktop->cursor.win, desktop->cursor.x, desktop->cursor.y ); + flags = input->mouse.flags; time = input->mouse.time; if (!time) time = desktop->cursor.last_change;
From: Rémi Bernon rbernon@codeweavers.com
Based on a patch by Huw Davies huw@codeweavers.com. --- server/protocol.def | 9 ++++- server/queue.c | 82 +++++++++++++++++++++++++++------------------ server/user.h | 3 -- 3 files changed, 57 insertions(+), 37 deletions(-)
diff --git a/server/protocol.def b/server/protocol.def index d6cfd8e9f72..f8216d57e25 100644 --- a/server/protocol.def +++ b/server/protocol.def @@ -890,9 +890,16 @@ typedef struct lparam_t info; } cursor_pos_t;
+struct shared_cursor +{ + int x; /* cursor position */ + int y; + unsigned int last_change; /* time of last position change */ +}; + struct desktop_shared_memory { - int placeholder; + struct shared_cursor cursor; /* global cursor information */ }; typedef volatile struct desktop_shared_memory desktop_shm_t;
diff --git a/server/queue.c b/server/queue.c index 51e01a471bf..d9a7cd2be2c 100644 --- a/server/queue.c +++ b/server/queue.c @@ -232,6 +232,16 @@ static unsigned int last_input_time; static cursor_pos_t cursor_history[64]; static unsigned int cursor_history_latest;
+#define SHARED_WRITE_BEGIN( object, type ) \ + do { \ + const type *__shared = (object)->shared; \ + type *shared = (type *)__shared; \ + do + +#define SHARED_WRITE_END \ + while(0); \ + } while(0); + static void queue_hardware_message( struct desktop *desktop, struct message *msg, int always_queue ); static void free_message( struct message *msg );
@@ -423,8 +433,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->shared->cursor.x; + msg->y = desktop->shared->cursor.y; if (!(msg->win = win) && (input = desktop->foreground_input)) msg->win = input->active; queue_hardware_message( desktop, msg, 1 ); } @@ -447,13 +457,19 @@ static int update_desktop_cursor_pos( struct desktop *desktop, user_handle_t win { struct thread_input *input; 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 ); - updated = (desktop->cursor.x != x || desktop->cursor.y != y); - desktop->cursor.x = x; - desktop->cursor.y = y; - desktop->cursor.last_change = get_tick_count(); + updated = (desktop->shared->cursor.x != x || desktop->shared->cursor.y != y); + + SHARED_WRITE_BEGIN( desktop, desktop_shm_t ) + { + shared->cursor.x = x; + shared->cursor.y = y; + shared->cursor.last_change = time; + } + SHARED_WRITE_END
if (!win && (input = desktop->foreground_input)) win = input->capture; if (!win || !is_window_visible( win ) || is_window_transparent( win )) @@ -502,8 +518,8 @@ static void get_message_defaults( struct msg_queue *queue, int *x, int *y, unsig { struct desktop *desktop = queue->input->desktop;
- *x = desktop->cursor.x; - *y = desktop->cursor.y; + *x = desktop->shared->cursor.x; + *y = desktop->shared->cursor.y; *time = get_tick_count(); }
@@ -527,9 +543,9 @@ void set_clip_rectangle( struct desktop *desktop, const rectangle_t *rect, unsig else desktop->cursor.clip = top_rect;
/* 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->shared->cursor.x, desktop->cursor.clip.right - 1 ), desktop->cursor.clip.left ); + y = max( min( desktop->shared->cursor.y, desktop->cursor.clip.bottom - 1 ), desktop->cursor.clip.top ); + if (x != desktop->shared->cursor.x || y != desktop->shared->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 ); @@ -1682,8 +1698,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->shared->cursor.x; + msg->y = desktop->shared->cursor.y;
if (msg->win && (thread = get_window_thread( msg->win ))) { @@ -1874,11 +1890,11 @@ static int queue_mouse_message( struct desktop *desktop, user_handle_t win, cons };
/* update last desktop cursor change time */ - update_desktop_cursor_pos( desktop, desktop->cursor.win, desktop->cursor.x, desktop->cursor.y ); + update_desktop_cursor_pos( desktop, desktop->cursor.win, desktop->shared->cursor.x, desktop->shared->cursor.y );
flags = input->mouse.flags; time = input->mouse.time; - if (!time) time = desktop->cursor.last_change; + if (!time) time = desktop->shared->cursor.last_change;
if (flags & MOUSEEVENTF_MOVE) { @@ -1887,19 +1903,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->shared->cursor.x && y == desktop->shared->cursor.y) flags &= ~MOUSEEVENTF_MOVE; } else { - x = desktop->cursor.x + input->mouse.x; - y = desktop->cursor.y + input->mouse.y; + x = desktop->shared->cursor.x + input->mouse.x; + y = desktop->shared->cursor.y + input->mouse.y; } } else { - x = desktop->cursor.x; - y = desktop->cursor.y; + x = desktop->shared->cursor.x; + y = desktop->shared->cursor.y; }
if ((foreground = get_foreground_thread( desktop, win ))) @@ -1916,8 +1932,8 @@ static int queue_mouse_message( struct desktop *desktop, user_handle_t win, cons msg_data->size = sizeof(*msg_data); msg_data->flags = flags; msg_data->rawinput.type = RIM_TYPEMOUSE; - msg_data->rawinput.mouse.x = x - desktop->cursor.x; - msg_data->rawinput.mouse.y = y - desktop->cursor.y; + msg_data->rawinput.mouse.x = x - desktop->shared->cursor.x; + msg_data->rawinput.mouse.y = y - desktop->shared->cursor.y; msg_data->rawinput.mouse.data = input->mouse.data;
enum_processes( queue_rawinput_message, &raw_msg ); @@ -2144,8 +2160,8 @@ static void queue_custom_hardware_message( struct desktop *desktop, user_handle_ msg->msg = input->hw.msg; msg->wparam = 0; msg->lparam = input->hw.lparam; - msg->x = desktop->cursor.x; - msg->y = desktop->cursor.y; + msg->x = desktop->shared->cursor.x; + msg->y = desktop->shared->cursor.y;
queue_hardware_message( desktop, msg, 1 ); } @@ -2660,8 +2676,8 @@ DECL_HANDLER(send_hardware_message) } }
- reply->prev_x = desktop->cursor.x; - reply->prev_y = desktop->cursor.y; + reply->prev_x = desktop->shared->cursor.x; + reply->prev_y = desktop->shared->cursor.y;
switch (req->input.type) { @@ -2679,8 +2695,8 @@ DECL_HANDLER(send_hardware_message) } if (thread) release_object( thread );
- reply->new_x = desktop->cursor.x; - reply->new_y = desktop->cursor.y; + reply->new_x = desktop->shared->cursor.x; + reply->new_y = desktop->shared->cursor.y; release_object( desktop ); }
@@ -3367,8 +3383,8 @@ DECL_HANDLER(set_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->shared->cursor.x; + reply->prev_y = desktop->shared->cursor.y;
if (req->flags & SET_CURSOR_HANDLE) { @@ -3394,10 +3410,10 @@ DECL_HANDLER(set_cursor) else update_desktop_cursor_handle( desktop, input->cursor ); }
- reply->new_x = desktop->cursor.x; - reply->new_y = desktop->cursor.y; + reply->new_x = desktop->shared->cursor.x; + reply->new_y = desktop->shared->cursor.y; reply->new_clip = desktop->cursor.clip; - reply->last_change = desktop->cursor.last_change; + reply->last_change = desktop->shared->cursor.last_change; }
/* Get the history of the 64 last cursor positions */ diff --git a/server/user.h b/server/user.h index 20b7acb6fdc..9c3e2b1381c 100644 --- a/server/user.h +++ b/server/user.h @@ -54,10 +54,7 @@ struct winstation
struct global_cursor { - int x; /* cursor position */ - int y; rectangle_t clip; /* cursor clip rectangle */ - unsigned int last_change; /* time of last position change */ user_handle_t win; /* window that contains the cursor */ user_handle_t handle; /* last set cursor handle */ };
From: Rémi Bernon rbernon@codeweavers.com
The client should check that the lower SEQUENCE_MASK_BITS are zero before reading the data and confirm that the number is unchanged when it's finished.
Based on a patch by Huw Davies huw@codeweavers.com. --- server/protocol.def | 1 + server/queue.c | 10 ++++++++++ 2 files changed, 11 insertions(+)
diff --git a/server/protocol.def b/server/protocol.def index f8216d57e25..e7c267b4148 100644 --- a/server/protocol.def +++ b/server/protocol.def @@ -899,6 +899,7 @@ struct shared_cursor
struct desktop_shared_memory { + unsigned int seq; /* sequence number - server updating if (seq & 1) != 0 */ struct shared_cursor cursor; /* global cursor information */ }; typedef volatile struct desktop_shared_memory desktop_shm_t; diff --git a/server/queue.c b/server/queue.c index d9a7cd2be2c..3750c849073 100644 --- a/server/queue.c +++ b/server/queue.c @@ -232,14 +232,24 @@ static unsigned int last_input_time; static cursor_pos_t cursor_history[64]; static unsigned int cursor_history_latest;
+#if defined(__i386__) || defined(__x86_64__) +#define __SHARED_WRITE_FENCE( x ) ++(x) +#else +#define __SHARED_WRITE_FENCE( x ) __atomic_add_fetch( &(x), 1, __ATOMIC_RELEASE ) +#endif + #define SHARED_WRITE_BEGIN( object, type ) \ do { \ const type *__shared = (object)->shared; \ type *shared = (type *)__shared; \ + unsigned int __seq = __SHARED_WRITE_FENCE( shared->seq ); \ + assert( (__seq & 1) != 0 ); \ do
#define SHARED_WRITE_END \ while(0); \ + __seq = __SHARED_WRITE_FENCE( shared->seq ); \ + assert( (__seq & 1) == 0 ); \ } while(0);
static void queue_hardware_message( struct desktop *desktop, struct message *msg, int always_queue );
From: Rémi Bernon rbernon@codeweavers.com
Based on a patch by Huw Davies huw@codeweavers.com. --- dlls/win32u/input.c | 20 +++++------ dlls/win32u/ntuser_private.h | 27 +++++++++++++++ dlls/win32u/sysparams.c | 6 ++++ dlls/win32u/winstation.c | 65 ++++++++++++++++++++++++++++++++++++ 4 files changed, 107 insertions(+), 11 deletions(-)
diff --git a/dlls/win32u/input.c b/dlls/win32u/input.c index 1f9e48423fc..dfb484066cd 100644 --- a/dlls/win32u/input.c +++ b/dlls/win32u/input.c @@ -740,25 +740,23 @@ BOOL WINAPI NtUserSetCursorPos( INT x, INT y ) */ BOOL get_cursor_pos( POINT *pt ) { - BOOL ret; + const desktop_shm_t *shared = get_desktop_shared_memory(); DWORD last_change; + BOOL ret = TRUE; UINT dpi;
- if (!pt) return FALSE; + if (!pt || !shared) return FALSE;
- SERVER_START_REQ( set_cursor ) + SHARED_READ_BEGIN( shared, desktop_shm_t ) { - if ((ret = !wine_server_call( req ))) - { - pt->x = reply->new_x; - pt->y = reply->new_y; - last_change = reply->last_change; - } + pt->x = shared->cursor.x; + pt->y = shared->cursor.y; + last_change = shared->cursor.last_change; } - SERVER_END_REQ; + SHARED_READ_END
/* query new position from graphics driver if we haven't updated recently */ - if (ret && NtGetTickCount() - last_change > 100) ret = user_driver->pGetCursorPos( pt ); + if (NtGetTickCount() - last_change > 100) ret = user_driver->pGetCursorPos( pt ); if (ret && (dpi = get_thread_dpi())) { HMONITOR monitor = monitor_from_point( *pt, MONITOR_DEFAULTTOPRIMARY, 0 ); diff --git a/dlls/win32u/ntuser_private.h b/dlls/win32u/ntuser_private.h index b39e38db5d6..638e5950ad6 100644 --- a/dlls/win32u/ntuser_private.h +++ b/dlls/win32u/ntuser_private.h @@ -132,6 +132,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 */ + const desktop_shm_t *desktop_shm; /* Ptr to server's desktop shared memory */ };
C_ASSERT( sizeof(struct user_thread_info) <= sizeof(((TEB *)0)->Win32ClientInfo) ); @@ -250,6 +251,9 @@ void release_user_handle_ptr( void *ptr ) DECLSPEC_HIDDEN; void *next_process_user_handle_ptr( HANDLE *handle, unsigned int type ) DECLSPEC_HIDDEN; UINT win_set_flags( HWND hwnd, UINT set_mask, UINT clear_mask ) DECLSPEC_HIDDEN;
+/* winstation.c */ +extern const desktop_shm_t *get_desktop_shared_memory(void) DECLSPEC_HIDDEN; + static inline UINT win_get_flags( HWND hwnd ) { return win_set_flags( hwnd, 0, 0 ); @@ -259,4 +263,27 @@ WND *get_win_ptr( HWND hwnd ) DECLSPEC_HIDDEN; BOOL is_child( HWND parent, HWND child ) DECLSPEC_HIDDEN; BOOL is_window( HWND hwnd ) DECLSPEC_HIDDEN;
+#if defined(__i386__) || defined(__x86_64__) +#define __SHARED_READ_SEQ( x ) (x) +#define __SHARED_READ_FENCE do {} while(0) +#else +#define __SHARED_READ_SEQ( x ) __atomic_load_n( &(x), __ATOMIC_RELAXED ) +#define __SHARED_READ_FENCE __atomic_thread_fence( __ATOMIC_ACQUIRE ) +#endif + +#define SHARED_READ_BEGIN( ptr, type ) \ + do { \ + const type *__shared = (ptr); \ + unsigned int __seq; \ + do { \ + while ((__seq = __SHARED_READ_SEQ( __shared->seq )) & 1) NtYieldExecution(); \ + __SHARED_READ_FENCE; \ + do + +#define SHARED_READ_END \ + while (0); \ + __SHARED_READ_FENCE; \ + } while (__SHARED_READ_SEQ( __shared->seq ) != __seq); \ + } while(0); + #endif /* __WINE_NTUSER_PRIVATE_H */ diff --git a/dlls/win32u/sysparams.c b/dlls/win32u/sysparams.c index fed309ff3d8..0319be584f8 100644 --- a/dlls/win32u/sysparams.c +++ b/dlls/win32u/sysparams.c @@ -6185,6 +6185,12 @@ static void thread_detach(void) cleanup_imm_thread(); NtClose( thread_info->server_queue );
+ if (thread_info->desktop_shm) + { + NtUnmapViewOfSection( GetCurrentProcess(), (void *)thread_info->desktop_shm ); + thread_info->desktop_shm = NULL; + } + exiting_thread_id = 0; }
diff --git a/dlls/win32u/winstation.c b/dlls/win32u/winstation.c index 5d1d5254ae1..e7aa8ce0d68 100644 --- a/dlls/win32u/winstation.c +++ b/dlls/win32u/winstation.c @@ -265,6 +265,11 @@ BOOL WINAPI NtUserSetThreadDesktop( HDESK handle ) thread_info->client_info.msg_window = 0; if (key_state_info) key_state_info->time = 0; if (was_virtual_desktop != is_virtual_desktop()) update_display_cache( TRUE ); + if (thread_info->desktop_shm) + { + NtUnmapViewOfSection( GetCurrentProcess(), (void *)thread_info->desktop_shm ); + thread_info->desktop_shm = NULL; + } } return ret; } @@ -606,6 +611,66 @@ static const WCHAR *get_default_desktop( void *buf, size_t buf_size ) return defaultW; }
+static volatile void *map_shared_memory_section( const WCHAR *name, SIZE_T size, HANDLE root ) +{ + OBJECT_ATTRIBUTES attr; + UNICODE_STRING section_str; + HANDLE handle; + UINT status; + void *ptr; + + RtlInitUnicodeString( §ion_str, name ); + InitializeObjectAttributes( &attr, §ion_str, 0, root, NULL ); + if (!(status = NtOpenSection( &handle, SECTION_ALL_ACCESS, &attr ))) + { + ptr = NULL; + status = NtMapViewOfSection( handle, GetCurrentProcess(), &ptr, 0, 0, NULL, + &size, ViewUnmap, 0, PAGE_READONLY ); + NtClose( handle ); + } + + if (status) + { + WARN( "Failed to map view of section %s, status %#x\n", debugstr_w(name), status ); + return NULL; + } + + return ptr; +} + +const desktop_shm_t *get_desktop_shared_memory(void) +{ + static const WCHAR dir_desktop_maps[] = + { + '_','_','w','i','n','e','_','d','e','s','k','t','o','p','_','m','a','p','p','i','n','g','s','\',0 + }; + struct user_thread_info *thread_info = get_user_thread_info(); + HANDLE root, handles[2]; + WCHAR buf[MAX_PATH], *ptr; + DWORD i, needed; + + if (thread_info->desktop_shm) return thread_info->desktop_shm; + + handles[0] = NtUserGetProcessWindowStation(); + handles[1] = NtUserGetThreadDesktop( GetCurrentThreadId() ); + + memcpy( buf, dir_desktop_maps, wcslen(dir_desktop_maps) * sizeof(WCHAR) ); + ptr = buf + wcslen(dir_desktop_maps); + + for (i = 0; i < 2; i++) + { + NtUserGetObjectInformation( handles[i], UOI_NAME, (void *)ptr, sizeof(buf) - (ptr - buf) * sizeof(WCHAR), &needed ); + ptr += needed / sizeof(WCHAR); + if (i == 0) *(ptr - 1) = '\'; + } + + root = get_winstations_dir_handle(); + thread_info->desktop_shm = map_shared_memory_section( buf, sizeof(*thread_info->desktop_shm), root ); + NtClose( root ); + + return thread_info->desktop_shm; +} + /*********************************************************************** * winstation_init *
v5: Restore seq asserts and type checking. Update SHARED_READ macros to look and be used similarly as SHARED_WRITE.
Jinoh Kang (@iamahuman) commented about server/queue.c:
static cursor_pos_t cursor_history[64]; static unsigned int cursor_history_latest;
+#if defined(__i386__) || defined(__x86_64__) +#define __SHARED_WRITE_FENCE( x ) ++(x) +#else +#define __SHARED_WRITE_FENCE( x ) __atomic_add_fetch( &(x), 1, __ATOMIC_RELEASE ) +#endif
Unlike `__SHARED_READ_FENCE`, this is not a pure fence instruction.
```suggestion:-4+0 #if defined(__i386__) || defined(__x86_64__) #define __INCR_SHARED_WRITE_SEQ( x ) ++(x) #else #define __INCR_SHARED_WRITE_SEQ( x ) __atomic_add_fetch( &(x), 1, __ATOMIC_RELEASE ) #endif ```
Jinoh Kang (@iamahuman) commented about server/queue.c:
+#else +#define __SHARED_WRITE_FENCE( x ) __atomic_add_fetch( &(x), 1, __ATOMIC_RELEASE ) +#endif
+#define SHARED_WRITE_BEGIN( object, type ) \
- do { \
const type *__shared = (object)->shared; \
type *shared = (type *)__shared; \
unsigned int __seq = __SHARED_WRITE_FENCE( shared->seq ); \
assert( (__seq & 1) != 0 ); \
do
+#define SHARED_WRITE_END \
while(0); \
__seq = __SHARED_WRITE_FENCE( shared->seq ); \
assert( (__seq & 1) == 0 ); \
How about a more strict check?
```suggestion:-1+0 __seq = __INCR_SHARED_WRITE_SEQ( shared->seq ) - __seq; \ assert( __seq == 1 ); \ ```
On Fri Aug 4 14:49:07 2023 +0000, Jinoh Kang wrote:
If the desktop object was a directory, we could use it as a RootDirectory and avoid the name aliasing problem above.
thread_info->desktop_shm = map_shared_memory_section( wine_desktop_mapping_str, sizeof(*thread_info->desktop_shm), NtUserGetThreadDesktop( GetCurrentThreadId() ) );
Maybe, but this is also solved otherwise by unlinking the mapping when the desktop is unlinked.
Making the desktop work as a directory feels to me like a change to the way the object desktop behaves, which is more risky than having a wine-specific directory in the WindowsStations directory. It also suggests that desktop is supposed to contain other objects on Windows, whereas it would only be a Wine-specific thing.
which is more risky
It may be less risky since intra-object namespace does not have to be enumerable (it can only implement `lookup_name`), in contrast to directory object which has to be *always* enumerable by contract.
than having a wine-specific directory in the WindowsStations directory.
I think it's more likely for an app to mistake `__wine_desktop_mappings` for an actual window station. Currently `user32!EnumWindowStationsW` is implemented as a direct server call in Wine. Windows might as well implement it with `NtQueryDirectoryObject` instead.
It also suggests that desktop is supposed to contain other objects on Windows
I think it's okay since the distinction between leaf objects and directories are a blurry on NT. Previously leaf objects can always become a namespace without breaking the ABI.
whereas it would only be a Wine-specific thing.
As long as we keep returning `STATUS_OBJECT_TYPE_MISMATCH` other than `__wine_desktop_mapping`, we should be fine.
Torge Matthies (@tmatthies) commented about dlls/win32u/ntuser_private.h:
BOOL is_window( HWND hwnd ) DECLSPEC_HIDDEN;
+#if defined(__i386__) || defined(__x86_64__) +#define __SHARED_READ_SEQ( x ) (x) +#define __SHARED_READ_FENCE do {} while(0) +#else +#define __SHARED_READ_SEQ( x ) __atomic_load_n( &(x), __ATOMIC_RELAXED ) +#define __SHARED_READ_FENCE __atomic_thread_fence( __ATOMIC_ACQUIRE ) +#endif
+#define SHARED_READ_BEGIN( ptr, type ) \
- do { \
const type *__shared = (ptr); \
unsigned int __seq; \
do { \
while ((__seq = __SHARED_READ_SEQ( __shared->seq )) & 1) NtYieldExecution(); \
I think this `NtYieldExecution` should not be here, the lock is unlikely to be held for long enough to make a full `sched_yield` syscall worthwile. ```suggestion:-0+0 while ((__seq = __SHARED_READ_SEQ( __shared->seq )) & 1) \ __asm__ __volatile__ ("":"+m"(__shared->seq)); \ ```