First part of Proton shared memory series. The full branch can be seen at https://gitlab.winehq.org/rbernon/wine/-/commits/mr/shared-memories.
-- v14: user32: Use the desktop shared data for GetCursorPos(). server: Expose the desktop shared mapping to clients. server: Add a sequence number to the shared data. server: Move the cursor position and last change time to the shared data. server: Create a desktop shared mapping.
From: Rémi Bernon rbernon@codeweavers.com
Based on a patch by Huw Davies huw@codeweavers.com. --- server/file.h | 1 + server/mapping.c | 17 +++++++++++++++++ server/protocol.def | 6 ++++++ server/user.h | 2 ++ server/winstation.c | 12 ++++++++++++ 5 files changed, 38 insertions(+)
diff --git a/server/file.h b/server/file.h index 39a833cd105..9dc9740c85f 100644 --- a/server/file.h +++ b/server/file.h @@ -188,6 +188,7 @@ 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 object *create_object_mapping( struct object *object, mem_size_t size, void **ptr );
/* device functions */
diff --git a/server/mapping.c b/server/mapping.c index f754078acf7..fb6cdd8b2dc 100644 --- a/server/mapping.c +++ b/server/mapping.c @@ -1222,6 +1222,23 @@ int get_page_size(void) return page_mask + 1; }
+struct object *create_object_mapping( struct object *object, mem_size_t size, void **ptr ) +{ + static const unsigned int access = FILE_READ_DATA | FILE_WRITE_DATA; + struct mapping *mapping; + void *tmp; + + if (!(mapping = create_mapping( object, NULL, 0, size, SEC_COMMIT, 0, access, NULL ))) return NULL; + if ((tmp = mmap( NULL, size, PROT_READ | PROT_WRITE, MAP_SHARED, get_unix_fd( mapping->fd ), 0 )) == MAP_FAILED) + { + release_object( &mapping->obj ); + return NULL; + } + + *ptr = tmp; + 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 5d60e7fcda3..db039f45255 100644 --- a/server/protocol.def +++ b/server/protocol.def @@ -893,6 +893,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 8fa55e09b0f..446e06ebb0c 100644 --- a/server/user.h +++ b/server/user.h @@ -76,6 +76,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..cedda7d5470 100644 --- a/server/winstation.c +++ b/server/winstation.c @@ -23,6 +23,7 @@ #include <stdio.h> #include <stdarg.h> #include <sys/types.h> +#include <sys/mman.h>
#include "ntstatus.h" #define WIN32_NO_STATUS @@ -240,6 +241,15 @@ 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 ); + desktop->shared_mapping = NULL; + desktop->shared = NULL; + + if (!(desktop->shared_mapping = create_object_mapping( &desktop->obj, sizeof(*desktop->shared), + (void **)&desktop->shared ))) + { + release_object( desktop ); + return NULL; + } } else { @@ -298,6 +308,8 @@ static void desktop_destroy( struct object *obj ) if (desktop->close_timeout) remove_timeout_user( desktop->close_timeout ); list_remove( &desktop->entry ); release_object( desktop->winstation ); + if (desktop->shared_mapping) release_object( desktop->shared_mapping ); + if (desktop->shared) munmap( (void *)desktop->shared, sizeof(*desktop->shared) ); }
/* retrieve the thread desktop, checking the handle access rights */
From: Rémi Bernon rbernon@codeweavers.com
Based on a patch by Huw Davies huw@codeweavers.com. --- server/protocol.def | 9 ++++- server/queue.c | 89 ++++++++++++++++++++++++++++----------------- server/user.h | 3 -- 3 files changed, 63 insertions(+), 38 deletions(-)
diff --git a/server/protocol.def b/server/protocol.def index db039f45255..1f56b8f0bf7 100644 --- a/server/protocol.def +++ b/server/protocol.def @@ -893,9 +893,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 cd913ae03e5..4090ca833bb 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 ); } @@ -463,13 +473,19 @@ 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 ) { 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(); + + SHARED_WRITE_BEGIN( desktop, desktop_shm_t ) + { + 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;
if (!win || !is_window_visible( win ) || is_window_transparent( win )) win = shallow_window_from_point( desktop, x, y ); @@ -515,8 +531,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(); }
@@ -540,9 +556,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 ); @@ -1695,8 +1711,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 ))) { @@ -1866,7 +1882,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 }; int wait = 0, x, y;
@@ -1887,10 +1903,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, 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->shared->cursor.last_change;
if (flags & MOUSEEVENTF_MOVE) { @@ -1899,19 +1920,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 ))) @@ -1928,8 +1949,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 ); @@ -2156,8 +2177,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 ); } @@ -2678,8 +2699,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) { @@ -2697,8 +2718,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 ); }
@@ -3390,8 +3411,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) { @@ -3414,10 +3435,10 @@ DECL_HANDLER(set_cursor) if (req->flags & (SET_CURSOR_HANDLE | SET_CURSOR_COUNT)) update_desktop_cursor_handle( desktop, input );
- 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 446e06ebb0c..6a0e3d65ab7 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 */ };
From: Rémi Bernon rbernon@codeweavers.com
Based on a patch by Huw Davies huw@codeweavers.com. --- server/protocol.def | 1 + server/queue.c | 22 ++++++++++++++++------ 2 files changed, 17 insertions(+), 6 deletions(-)
diff --git a/server/protocol.def b/server/protocol.def index 1f56b8f0bf7..a82ffe90e5e 100644 --- a/server/protocol.def +++ b/server/protocol.def @@ -902,6 +902,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 4090ca833bb..831c16c93ed 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;
-#define SHARED_WRITE_BEGIN( object, type ) \ - do { \ - const type *__shared = (object)->shared; \ - type *shared = (type *)__shared; \ +#if defined(__i386__) || defined(__x86_64__) +#define __SHARED_INCREMENT_SEQ( x ) ++(x) +#else +#define __SHARED_INCREMENT_SEQ( 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_INCREMENT_SEQ( shared->seq ); \ + assert( (__seq & 1) != 0 ); \ do
-#define SHARED_WRITE_END \ - while(0); \ +#define SHARED_WRITE_END \ + while(0); \ + __seq = __SHARED_INCREMENT_SEQ( shared->seq ) - __seq; \ + assert( __seq == 1 ); \ } while(0)
static void queue_hardware_message( struct desktop *desktop, struct message *msg, int always_queue );
From: Rémi Bernon rbernon@codeweavers.com
Through a generic object mapping mechanism using __wine_mapping name. --- server/async.c | 2 ++ server/atom.c | 1 + server/change.c | 1 + server/clipboard.c | 1 + server/completion.c | 1 + server/console.c | 7 +++++++ server/debugger.c | 2 ++ server/device.c | 9 +++++++++ server/directory.c | 2 ++ server/event.c | 2 ++ server/fd.c | 4 ++++ server/file.c | 1 + server/handle.c | 1 + server/hook.c | 1 + server/mailslot.c | 4 ++++ server/mapping.c | 28 ++++++++++++++++++++++++++++ server/mutex.c | 1 + server/named_pipe.c | 5 +++++ server/object.h | 3 +++ server/process.c | 3 +++ server/queue.c | 2 ++ server/registry.c | 1 + server/request.c | 1 + server/semaphore.c | 1 + server/serial.c | 1 + server/signal.c | 1 + server/sock.c | 3 +++ server/symlink.c | 1 + server/thread.c | 3 +++ server/timer.c | 1 + server/token.c | 1 + server/window.c | 1 + server/winstation.c | 10 ++++++++++ 33 files changed, 106 insertions(+)
diff --git a/server/async.c b/server/async.c index 9cb251df5ce..84504dfdf9e 100644 --- a/server/async.c +++ b/server/async.c @@ -89,6 +89,7 @@ static const struct object_ops async_ops = NULL, /* unlink_name */ no_open_file, /* open_file */ no_kernel_obj_list, /* get_kernel_obj_list */ + no_object_mapping, /* get_object_mapping */ no_close_handle, /* close_handle */ async_destroy /* destroy */ }; @@ -688,6 +689,7 @@ static const struct object_ops iosb_ops = NULL, /* unlink_name */ no_open_file, /* open_file */ no_kernel_obj_list, /* get_kernel_obj_list */ + no_object_mapping, /* get_object_mapping */ no_close_handle, /* close_handle */ iosb_destroy /* destroy */ }; diff --git a/server/atom.c b/server/atom.c index ff0799f5880..b2f3105138f 100644 --- a/server/atom.c +++ b/server/atom.c @@ -91,6 +91,7 @@ static const struct object_ops atom_table_ops = NULL, /* unlink_name */ no_open_file, /* open_file */ no_kernel_obj_list, /* get_kernel_obj_list */ + no_object_mapping, /* get_object_mapping */ no_close_handle, /* close_handle */ atom_table_destroy /* destroy */ }; diff --git a/server/change.c b/server/change.c index 843e495411c..8cf3c960bf3 100644 --- a/server/change.c +++ b/server/change.c @@ -124,6 +124,7 @@ static const struct object_ops dir_ops = NULL, /* unlink_name */ no_open_file, /* open_file */ no_kernel_obj_list, /* get_kernel_obj_list */ + no_object_mapping, /* get_object_mapping */ dir_close_handle, /* close_handle */ dir_destroy /* destroy */ }; diff --git a/server/clipboard.c b/server/clipboard.c index 8118a467dd8..bc12a150cd7 100644 --- a/server/clipboard.c +++ b/server/clipboard.c @@ -88,6 +88,7 @@ static const struct object_ops clipboard_ops = NULL, /* unlink_name */ no_open_file, /* open_file */ no_kernel_obj_list, /* get_kernel_obj_list */ + no_object_mapping, /* get_object_mapping */ no_close_handle, /* close_handle */ clipboard_destroy /* destroy */ }; diff --git a/server/completion.c b/server/completion.c index 6933195e72d..8a67a1cbfd8 100644 --- a/server/completion.c +++ b/server/completion.c @@ -87,6 +87,7 @@ static const struct object_ops completion_ops = default_unlink_name, /* unlink_name */ no_open_file, /* open_file */ no_kernel_obj_list, /* get_kernel_obj_list */ + no_object_mapping, /* get_object_mapping */ no_close_handle, /* close_handle */ completion_destroy /* destroy */ }; diff --git a/server/console.c b/server/console.c index b64283baf4a..b9837c169aa 100644 --- a/server/console.c +++ b/server/console.c @@ -93,6 +93,7 @@ static const struct object_ops console_ops = NULL, /* unlink_name */ console_open_file, /* open_file */ no_kernel_obj_list, /* get_kernel_obj_list */ + no_object_mapping, /* get_object_mapping */ no_close_handle, /* close_handle */ console_destroy /* destroy */ }; @@ -170,6 +171,7 @@ static const struct object_ops console_server_ops = NULL, /* unlink_name */ console_server_open_file, /* open_file */ no_kernel_obj_list, /* get_kernel_obj_list */ + no_object_mapping, /* get_object_mapping */ no_close_handle, /* close_handle */ console_server_destroy /* destroy */ }; @@ -239,6 +241,7 @@ static const struct object_ops screen_buffer_ops = NULL, /* unlink_name */ screen_buffer_open_file, /* open_file */ no_kernel_obj_list, /* get_kernel_obj_list */ + no_object_mapping, /* get_object_mapping */ no_close_handle, /* close_handle */ screen_buffer_destroy /* destroy */ }; @@ -288,6 +291,7 @@ static const struct object_ops console_device_ops = default_unlink_name, /* unlink_name */ console_device_open_file, /* open_file */ no_kernel_obj_list, /* get_kernel_obj_list */ + no_object_mapping, /* get_object_mapping */ no_close_handle, /* close_handle */ no_destroy /* destroy */ }; @@ -325,6 +329,7 @@ static const struct object_ops console_input_ops = default_unlink_name, /* unlink_name */ console_input_open_file, /* open_file */ no_kernel_obj_list, /* get_kernel_obj_list */ + no_object_mapping, /* get_object_mapping */ no_close_handle, /* close_handle */ console_input_destroy /* destroy */ }; @@ -382,6 +387,7 @@ static const struct object_ops console_output_ops = default_unlink_name, /* unlink_name */ console_output_open_file, /* open_file */ no_kernel_obj_list, /* get_kernel_obj_list */ + no_object_mapping, /* get_object_mapping */ no_close_handle, /* close_handle */ console_output_destroy /* destroy */ }; @@ -440,6 +446,7 @@ static const struct object_ops console_connection_ops = default_unlink_name, /* unlink_name */ console_connection_open_file, /* open_file */ no_kernel_obj_list, /* get_kernel_obj_list */ + no_object_mapping, /* get_object_mapping */ console_connection_close_handle, /* close_handle */ console_connection_destroy /* destroy */ }; diff --git a/server/debugger.c b/server/debugger.c index 48adb244b09..9ce6bbd94cc 100644 --- a/server/debugger.c +++ b/server/debugger.c @@ -98,6 +98,7 @@ static const struct object_ops debug_event_ops = NULL, /* unlink_name */ no_open_file, /* open_file */ no_kernel_obj_list, /* get_kernel_obj_list */ + no_object_mapping, /* get_object_mapping */ no_close_handle, /* close_handle */ debug_event_destroy /* destroy */ }; @@ -126,6 +127,7 @@ static const struct object_ops debug_obj_ops = default_unlink_name, /* unlink_name */ no_open_file, /* open_file */ no_kernel_obj_list, /* get_kernel_obj_list */ + no_object_mapping, /* get_object_mapping */ no_close_handle, /* close_handle */ debug_obj_destroy /* destroy */ }; diff --git a/server/device.c b/server/device.c index 436dac6bfe9..2730d457816 100644 --- a/server/device.c +++ b/server/device.c @@ -78,6 +78,7 @@ static const struct object_ops irp_call_ops = NULL, /* unlink_name */ no_open_file, /* open_file */ no_kernel_obj_list, /* get_kernel_obj_list */ + no_object_mapping, /* get_object_mapping */ no_close_handle, /* close_handle */ irp_call_destroy /* destroy */ }; @@ -118,6 +119,7 @@ static const struct object_ops device_manager_ops = NULL, /* unlink_name */ no_open_file, /* open_file */ no_kernel_obj_list, /* get_kernel_obj_list */ + no_object_mapping, /* get_object_mapping */ no_close_handle, /* close_handle */ device_manager_destroy /* destroy */ }; @@ -175,6 +177,7 @@ static const struct object_ops device_ops = default_unlink_name, /* unlink_name */ device_open_file, /* open_file */ device_get_kernel_obj_list, /* get_kernel_obj_list */ + no_object_mapping, /* get_object_mapping */ no_close_handle, /* close_handle */ device_destroy /* destroy */ }; @@ -227,6 +230,7 @@ static const struct object_ops device_file_ops = NULL, /* unlink_name */ no_open_file, /* open_file */ device_file_get_kernel_obj_list, /* get_kernel_obj_list */ + no_object_mapping, /* get_object_mapping */ device_file_close_handle, /* close_handle */ device_file_destroy /* destroy */ }; @@ -253,6 +257,11 @@ struct list *no_kernel_obj_list( struct object *obj ) return NULL; }
+struct mapping *no_object_mapping( struct object *obj ) +{ + return NULL; +} + struct kernel_object { struct device_manager *manager; diff --git a/server/directory.c b/server/directory.c index 23d7eb0a2b7..b16527cee3b 100644 --- a/server/directory.c +++ b/server/directory.c @@ -81,6 +81,7 @@ static const struct object_ops object_type_ops = default_unlink_name, /* unlink_name */ no_open_file, /* open_file */ no_kernel_obj_list, /* get_kernel_obj_list */ + no_object_mapping, /* get_object_mapping */ no_close_handle, /* close_handle */ no_destroy /* destroy */ }; @@ -131,6 +132,7 @@ static const struct object_ops directory_ops = default_unlink_name, /* unlink_name */ no_open_file, /* open_file */ no_kernel_obj_list, /* get_kernel_obj_list */ + no_object_mapping, /* get_object_mapping */ no_close_handle, /* close_handle */ directory_destroy /* destroy */ }; diff --git a/server/event.c b/server/event.c index f1b79b1b35e..ce1adb5a9c5 100644 --- a/server/event.c +++ b/server/event.c @@ -84,6 +84,7 @@ static const struct object_ops event_ops = default_unlink_name, /* unlink_name */ no_open_file, /* open_file */ event_get_kernel_obj_list, /* get_kernel_obj_list */ + no_object_mapping, /* get_object_mapping */ no_close_handle, /* close_handle */ no_destroy /* destroy */ }; @@ -131,6 +132,7 @@ static const struct object_ops keyed_event_ops = default_unlink_name, /* unlink_name */ no_open_file, /* open_file */ no_kernel_obj_list, /* get_kernel_obj_list */ + no_object_mapping, /* get_object_mapping */ no_close_handle, /* close_handle */ no_destroy /* destroy */ }; diff --git a/server/fd.c b/server/fd.c index 8576882aaa9..85683ced951 100644 --- a/server/fd.c +++ b/server/fd.c @@ -181,6 +181,7 @@ static const struct object_ops fd_ops = NULL, /* unlink_name */ no_open_file, /* open_file */ no_kernel_obj_list, /* get_kernel_obj_list */ + no_object_mapping, /* get_object_mapping */ no_close_handle, /* close_handle */ fd_destroy /* destroy */ }; @@ -222,6 +223,7 @@ static const struct object_ops device_ops = NULL, /* unlink_name */ no_open_file, /* open_file */ no_kernel_obj_list, /* get_kernel_obj_list */ + no_object_mapping, /* get_object_mapping */ no_close_handle, /* close_handle */ device_destroy /* destroy */ }; @@ -262,6 +264,7 @@ static const struct object_ops inode_ops = NULL, /* unlink_name */ no_open_file, /* open_file */ no_kernel_obj_list, /* get_kernel_obj_list */ + no_object_mapping, /* get_object_mapping */ no_close_handle, /* close_handle */ inode_destroy /* destroy */ }; @@ -304,6 +307,7 @@ static const struct object_ops file_lock_ops = NULL, /* unlink_name */ no_open_file, /* open_file */ no_kernel_obj_list, /* get_kernel_obj_list */ + no_object_mapping, /* get_object_mapping */ no_close_handle, /* close_handle */ no_destroy /* destroy */ }; diff --git a/server/file.c b/server/file.c index 76c687833c9..d93b47a0b97 100644 --- a/server/file.c +++ b/server/file.c @@ -106,6 +106,7 @@ static const struct object_ops file_ops = NULL, /* unlink_name */ file_open_file, /* open_file */ file_get_kernel_obj_list, /* get_kernel_obj_list */ + no_object_mapping, /* get_object_mapping */ no_close_handle, /* close_handle */ file_destroy /* destroy */ }; diff --git a/server/handle.c b/server/handle.c index 0595fdb403b..3319d3b2b9c 100644 --- a/server/handle.c +++ b/server/handle.c @@ -138,6 +138,7 @@ static const struct object_ops handle_table_ops = NULL, /* unlink_name */ no_open_file, /* open_file */ no_kernel_obj_list, /* get_kernel_obj_list */ + no_object_mapping, /* get_object_mapping */ no_close_handle, /* close_handle */ handle_table_destroy /* destroy */ }; diff --git a/server/hook.c b/server/hook.c index 5abdf39ad37..fd4f5a01224 100644 --- a/server/hook.c +++ b/server/hook.c @@ -92,6 +92,7 @@ static const struct object_ops hook_table_ops = NULL, /* unlink_name */ no_open_file, /* open_file */ no_kernel_obj_list, /* get_kernel_obj_list */ + no_object_mapping, /* get_object_mapping */ no_close_handle, /* close_handle */ hook_table_destroy /* destroy */ }; diff --git a/server/mailslot.c b/server/mailslot.c index 2d8697ec9bd..9b856513fcf 100644 --- a/server/mailslot.c +++ b/server/mailslot.c @@ -86,6 +86,7 @@ static const struct object_ops mailslot_ops = default_unlink_name, /* unlink_name */ mailslot_open_file, /* open_file */ no_kernel_obj_list, /* get_kernel_obj_list */ + no_object_mapping, /* get_object_mapping */ no_close_handle, /* close_handle */ mailslot_destroy /* destroy */ }; @@ -145,6 +146,7 @@ static const struct object_ops mail_writer_ops = NULL, /* unlink_name */ no_open_file, /* open_file */ no_kernel_obj_list, /* get_kernel_obj_list */ + no_object_mapping, /* get_object_mapping */ no_close_handle, /* close_handle */ mail_writer_destroy /* destroy */ }; @@ -208,6 +210,7 @@ static const struct object_ops mailslot_device_ops = default_unlink_name, /* unlink_name */ mailslot_device_open_file, /* open_file */ no_kernel_obj_list, /* get_kernel_obj_list */ + no_object_mapping, /* get_object_mapping */ no_close_handle, /* close_handle */ mailslot_device_destroy /* destroy */ }; @@ -238,6 +241,7 @@ static const struct object_ops mailslot_device_file_ops = NULL, /* unlink_name */ no_open_file, /* open_file */ no_kernel_obj_list, /* get_kernel_obj_list */ + no_object_mapping, /* get_object_mapping */ no_close_handle, /* close_handle */ mailslot_device_file_destroy /* destroy */ }; diff --git a/server/mapping.c b/server/mapping.c index fb6cdd8b2dc..63b7bfa3190 100644 --- a/server/mapping.c +++ b/server/mapping.c @@ -79,6 +79,7 @@ static const struct object_ops ranges_ops = NULL, /* unlink_name */ no_open_file, /* open_file */ no_kernel_obj_list, /* get_kernel_obj_list */ + no_object_mapping, /* get_object_mapping */ no_close_handle, /* close_handle */ ranges_destroy /* destroy */ }; @@ -115,6 +116,7 @@ static const struct object_ops shared_map_ops = NULL, /* unlink_name */ no_open_file, /* open_file */ no_kernel_obj_list, /* get_kernel_obj_list */ + no_object_mapping, /* get_object_mapping */ no_close_handle, /* close_handle */ shared_map_destroy /* destroy */ }; @@ -188,6 +190,7 @@ static const struct object_ops mapping_ops = default_unlink_name, /* unlink_name */ no_open_file, /* open_file */ no_kernel_obj_list, /* get_kernel_obj_list */ + no_object_mapping, /* get_object_mapping */ no_close_handle, /* close_handle */ mapping_destroy /* destroy */ }; @@ -1281,10 +1284,35 @@ DECL_HANDLER(create_mapping) if (root) release_object( root ); }
+static struct mapping *open_object_mapping( user_handle_t handle, struct unicode_str *name ) +{ + static const WCHAR object_mappingW[] = {'_','_','w','i','n','e','_','m','a','p','p','i','n','g'}; + struct mapping *mapping; + struct object *object; + + if (name->len != sizeof(object_mappingW) || memcmp( name->str, object_mappingW, name->len )) return NULL; + if (!(object = get_handle_obj( current->process, handle, 0, NULL ))) + { + clear_error(); + return NULL; + } + mapping = object->ops->get_object_mapping( object ); + release_object( object ); + return mapping; +} + /* open a handle to a mapping */ DECL_HANDLER(open_mapping) { struct unicode_str name = get_req_unicode_str(); + struct mapping *mapping; + + if (req->rootdir && (mapping = open_object_mapping( req->rootdir, &name ))) + { + reply->handle = alloc_handle( current->process, &mapping->obj, req->access, req->attributes ); + release_object( mapping ); + return; + }
reply->handle = open_object( current->process, req->rootdir, req->access, &mapping_ops, &name, req->attributes ); diff --git a/server/mutex.c b/server/mutex.c index af0efe72132..7d48fe9064e 100644 --- a/server/mutex.c +++ b/server/mutex.c @@ -85,6 +85,7 @@ static const struct object_ops mutex_ops = default_unlink_name, /* unlink_name */ no_open_file, /* open_file */ no_kernel_obj_list, /* get_kernel_obj_list */ + no_object_mapping, /* get_object_mapping */ no_close_handle, /* close_handle */ mutex_destroy /* destroy */ }; diff --git a/server/named_pipe.c b/server/named_pipe.c index f3404a33c3b..ffb6347cbd1 100644 --- a/server/named_pipe.c +++ b/server/named_pipe.c @@ -131,6 +131,7 @@ static const struct object_ops named_pipe_ops = default_unlink_name, /* unlink_name */ named_pipe_open_file, /* open_file */ no_kernel_obj_list, /* get_kernel_obj_list */ + no_object_mapping, /* get_object_mapping */ no_close_handle, /* close_handle */ named_pipe_destroy /* destroy */ }; @@ -179,6 +180,7 @@ static const struct object_ops pipe_server_ops = NULL, /* unlink_name */ pipe_server_open_file, /* open_file */ no_kernel_obj_list, /* get_kernel_obj_list */ + no_object_mapping, /* get_object_mapping */ async_close_obj_handle, /* close_handle */ pipe_server_destroy /* destroy */ }; @@ -223,6 +225,7 @@ static const struct object_ops pipe_client_ops = NULL, /* unlink_name */ no_open_file, /* open_file */ no_kernel_obj_list, /* get_kernel_obj_list */ + no_object_mapping, /* get_object_mapping */ async_close_obj_handle, /* close_handle */ pipe_end_destroy /* destroy */ }; @@ -270,6 +273,7 @@ static const struct object_ops named_pipe_device_ops = default_unlink_name, /* unlink_name */ named_pipe_device_open_file, /* open_file */ no_kernel_obj_list, /* get_kernel_obj_list */ + no_object_mapping, /* get_object_mapping */ no_close_handle, /* close_handle */ named_pipe_device_destroy /* destroy */ }; @@ -301,6 +305,7 @@ static const struct object_ops named_pipe_device_file_ops = NULL, /* unlink_name */ no_open_file, /* open_file */ no_kernel_obj_list, /* get_kernel_obj_list */ + no_object_mapping, /* get_object_mapping */ no_close_handle, /* close_handle */ named_pipe_device_file_destroy /* destroy */ }; diff --git a/server/object.h b/server/object.h index dfdd691601f..05f593fca85 100644 --- a/server/object.h +++ b/server/object.h @@ -103,6 +103,8 @@ struct object_ops unsigned int options); /* return list of kernel objects */ struct list *(*get_kernel_obj_list)(struct object *); + /* return the memory mapping for the object */ + struct mapping *(*get_object_mapping)(struct object *); /* close a handle to this object */ int (*close_handle)(struct object *,struct process *,obj_handle_t); /* destroy on refcount == 0 */ @@ -181,6 +183,7 @@ extern void default_unlink_name( struct object *obj, struct object_name *name ); extern struct object *no_open_file( struct object *obj, unsigned int access, unsigned int sharing, unsigned int options ); extern struct list *no_kernel_obj_list( struct object *obj ); +extern struct mapping *no_object_mapping( struct object *obj ); extern int no_close_handle( struct object *obj, struct process *process, obj_handle_t handle ); extern void no_destroy( struct object *obj ); #ifdef DEBUG_OBJECTS diff --git a/server/process.c b/server/process.c index a0d5ea64d97..a203bef0544 100644 --- a/server/process.c +++ b/server/process.c @@ -117,6 +117,7 @@ static const struct object_ops process_ops = NULL, /* unlink_name */ no_open_file, /* open_file */ process_get_kernel_obj_list, /* get_kernel_obj_list */ + no_object_mapping, /* get_object_mapping */ no_close_handle, /* close_handle */ process_destroy /* destroy */ }; @@ -168,6 +169,7 @@ static const struct object_ops startup_info_ops = NULL, /* unlink_name */ no_open_file, /* open_file */ no_kernel_obj_list, /* get_kernel_obj_list */ + no_object_mapping, /* get_object_mapping */ no_close_handle, /* close_handle */ startup_info_destroy /* destroy */ }; @@ -229,6 +231,7 @@ static const struct object_ops job_ops = default_unlink_name, /* unlink_name */ no_open_file, /* open_file */ no_kernel_obj_list, /* get_kernel_obj_list */ + no_object_mapping, /* get_object_mapping */ job_close_handle, /* close_handle */ job_destroy /* destroy */ }; diff --git a/server/queue.c b/server/queue.c index 831c16c93ed..5e79a52a83b 100644 --- a/server/queue.c +++ b/server/queue.c @@ -185,6 +185,7 @@ static const struct object_ops msg_queue_ops = NULL, /* unlink_name */ no_open_file, /* open_file */ no_kernel_obj_list, /* get_kernel_obj_list */ + no_object_mapping, /* get_object_mapping */ no_close_handle, /* close_handle */ msg_queue_destroy /* destroy */ }; @@ -222,6 +223,7 @@ static const struct object_ops thread_input_ops = NULL, /* unlink_name */ no_open_file, /* open_file */ no_kernel_obj_list, /* get_kernel_obj_list */ + no_object_mapping, /* get_object_mapping */ no_close_handle, /* close_handle */ thread_input_destroy /* destroy */ }; diff --git a/server/registry.c b/server/registry.c index da6a6d0982e..4e80af2d2ba 100644 --- a/server/registry.c +++ b/server/registry.c @@ -192,6 +192,7 @@ static const struct object_ops key_ops = key_unlink_name, /* unlink_name */ no_open_file, /* open_file */ no_kernel_obj_list, /* get_kernel_obj_list */ + no_object_mapping, /* get_object_mapping */ key_close_handle, /* close_handle */ key_destroy /* destroy */ }; diff --git a/server/request.c b/server/request.c index 7021741c765..d93e86e3eed 100644 --- a/server/request.c +++ b/server/request.c @@ -102,6 +102,7 @@ static const struct object_ops master_socket_ops = NULL, /* unlink_name */ no_open_file, /* open_file */ no_kernel_obj_list, /* get_kernel_obj_list */ + no_object_mapping, /* get_object_mapping */ no_close_handle, /* close_handle */ master_socket_destroy /* destroy */ }; diff --git a/server/semaphore.c b/server/semaphore.c index 53b42a886df..eaf909aa551 100644 --- a/server/semaphore.c +++ b/server/semaphore.c @@ -82,6 +82,7 @@ static const struct object_ops semaphore_ops = default_unlink_name, /* unlink_name */ no_open_file, /* open_file */ no_kernel_obj_list, /* get_kernel_obj_list */ + no_object_mapping, /* get_object_mapping */ no_close_handle, /* close_handle */ no_destroy /* destroy */ }; diff --git a/server/serial.c b/server/serial.c index d665eb7fa35..64af16d6a51 100644 --- a/server/serial.c +++ b/server/serial.c @@ -97,6 +97,7 @@ static const struct object_ops serial_ops = NULL, /* unlink_name */ no_open_file, /* open_file */ no_kernel_obj_list, /* get_kernel_obj_list */ + no_object_mapping, /* get_object_mapping */ no_close_handle, /* close_handle */ serial_destroy /* destroy */ }; diff --git a/server/signal.c b/server/signal.c index 19b76d44c16..45c6d77f552 100644 --- a/server/signal.c +++ b/server/signal.c @@ -74,6 +74,7 @@ static const struct object_ops handler_ops = NULL, /* unlink_name */ no_open_file, /* open_file */ no_kernel_obj_list, /* get_kernel_obj_list */ + no_object_mapping, /* get_object_mapping */ no_close_handle, /* close_handle */ handler_destroy /* destroy */ }; diff --git a/server/sock.c b/server/sock.c index c34fd3eb5eb..c9ea380e26f 100644 --- a/server/sock.c +++ b/server/sock.c @@ -465,6 +465,7 @@ static const struct object_ops sock_ops = NULL, /* unlink_name */ no_open_file, /* open_file */ no_kernel_obj_list, /* get_kernel_obj_list */ + no_object_mapping, /* get_object_mapping */ sock_close_handle, /* close_handle */ sock_destroy /* destroy */ }; @@ -3566,6 +3567,7 @@ static const struct object_ops ifchange_ops = NULL, /* unlink_name */ no_open_file, /* open_file */ no_kernel_obj_list, /* get_kernel_obj_list */ + no_object_mapping, /* get_object_mapping */ no_close_handle, /* close_handle */ ifchange_destroy /* destroy */ }; @@ -3787,6 +3789,7 @@ static const struct object_ops socket_device_ops = default_unlink_name, /* unlink_name */ socket_device_open_file, /* open_file */ no_kernel_obj_list, /* get_kernel_obj_list */ + no_object_mapping, /* get_object_mapping */ no_close_handle, /* close_handle */ no_destroy /* destroy */ }; diff --git a/server/symlink.c b/server/symlink.c index dd28efd3a75..0492b83172a 100644 --- a/server/symlink.c +++ b/server/symlink.c @@ -83,6 +83,7 @@ static const struct object_ops symlink_ops = default_unlink_name, /* unlink_name */ no_open_file, /* open_file */ no_kernel_obj_list, /* get_kernel_obj_list */ + no_object_mapping, /* get_object_mapping */ no_close_handle, /* close_handle */ symlink_destroy /* destroy */ }; diff --git a/server/thread.c b/server/thread.c index 56f57cefd8f..5673c9d4809 100644 --- a/server/thread.c +++ b/server/thread.c @@ -108,6 +108,7 @@ static const struct object_ops thread_apc_ops = NULL, /* unlink_name */ no_open_file, /* open_file */ no_kernel_obj_list, /* get_kernel_obj_list */ + no_object_mapping, /* get_object_mapping */ no_close_handle, /* close_handle */ thread_apc_destroy /* destroy */ }; @@ -150,6 +151,7 @@ static const struct object_ops context_ops = NULL, /* unlink_name */ no_open_file, /* open_file */ no_kernel_obj_list, /* get_kernel_obj_list */ + no_object_mapping, /* get_object_mapping */ no_close_handle, /* close_handle */ no_destroy /* destroy */ }; @@ -199,6 +201,7 @@ static const struct object_ops thread_ops = NULL, /* unlink_name */ no_open_file, /* open_file */ thread_get_kernel_obj_list, /* get_kernel_obj_list */ + no_object_mapping, /* get_object_mapping */ no_close_handle, /* close_handle */ destroy_thread /* destroy */ }; diff --git a/server/timer.c b/server/timer.c index 96dc9d00ca1..3f083db56b8 100644 --- a/server/timer.c +++ b/server/timer.c @@ -88,6 +88,7 @@ static const struct object_ops timer_ops = default_unlink_name, /* unlink_name */ no_open_file, /* open_file */ no_kernel_obj_list, /* get_kernel_obj_list */ + no_object_mapping, /* get_object_mapping */ no_close_handle, /* close_handle */ timer_destroy /* destroy */ }; diff --git a/server/token.c b/server/token.c index 4df8d2e0c6e..94e3fd0b121 100644 --- a/server/token.c +++ b/server/token.c @@ -155,6 +155,7 @@ static const struct object_ops token_ops = NULL, /* unlink_name */ no_open_file, /* open_file */ no_kernel_obj_list, /* get_kernel_obj_list */ + no_object_mapping, /* get_object_mapping */ no_close_handle, /* close_handle */ token_destroy /* destroy */ }; diff --git a/server/window.c b/server/window.c index 242e93f303a..8fb4162f9f4 100644 --- a/server/window.c +++ b/server/window.c @@ -119,6 +119,7 @@ static const struct object_ops window_ops = NULL, /* unlink_name */ no_open_file, /* open_file */ no_kernel_obj_list, /* get_kernel_obj_list */ + no_object_mapping, /* get_object_mapping */ no_close_handle, /* close_handle */ window_destroy /* destroy */ }; diff --git a/server/winstation.c b/server/winstation.c index cedda7d5470..905a560d8d6 100644 --- a/server/winstation.c +++ b/server/winstation.c @@ -52,6 +52,7 @@ static struct object *winstation_lookup_name( struct object *obj, struct unicode static void winstation_destroy( struct object *obj ); static void desktop_dump( struct object *obj, int verbose ); static int desktop_link_name( struct object *obj, struct object_name *name, struct object *parent ); +static struct mapping *desktop_get_object_mapping( struct object *obj ); static int desktop_close_handle( struct object *obj, struct process *process, obj_handle_t handle ); static void desktop_destroy( struct object *obj );
@@ -89,6 +90,7 @@ static const struct object_ops winstation_ops = default_unlink_name, /* unlink_name */ no_open_file, /* open_file */ no_kernel_obj_list, /* get_kernel_obj_list */ + no_object_mapping, /* get_object_mapping */ winstation_close_handle, /* close_handle */ winstation_destroy /* destroy */ }; @@ -129,6 +131,7 @@ static const struct object_ops desktop_ops = default_unlink_name, /* unlink_name */ no_open_file, /* open_file */ no_kernel_obj_list, /* get_kernel_obj_list */ + desktop_get_object_mapping, /* get_object_mapping */ desktop_close_handle, /* close_handle */ desktop_destroy /* destroy */ }; @@ -286,6 +289,13 @@ static int desktop_link_name( struct object *obj, struct object_name *name, stru return 1; }
+static struct mapping *desktop_get_object_mapping( struct object *obj ) +{ + struct desktop *desktop = (struct desktop *)obj; + assert( obj->ops == &desktop_ops ); + return (struct mapping *)grab_object( desktop->shared_mapping ); +} + static int desktop_close_handle( struct object *obj, struct process *process, obj_handle_t handle ) { struct thread *thread;
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 | 1 + dlls/win32u/sysparams.c | 1 + dlls/win32u/win32u_private.h | 25 ++++++++++++++++ dlls/win32u/winstation.c | 55 ++++++++++++++++++++++++++++++++++++ 5 files changed, 91 insertions(+), 11 deletions(-)
diff --git a/dlls/win32u/input.c b/dlls/win32u/input.c index ef8d564c264..d793ac103e4 100644 --- a/dlls/win32u/input.c +++ b/dlls/win32u/input.c @@ -749,25 +749,23 @@ BOOL WINAPI NtUserSetCursorPos( INT x, INT y ) */ BOOL get_cursor_pos( POINT *pt ) { - BOOL ret; + const desktop_shm_t *shared; DWORD last_change; + BOOL ret = TRUE; UINT dpi;
- if (!pt) return FALSE; + if (!pt || !(shared = get_desktop_shared_memory())) 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 11bb7f4baf6..a027d99babe 100644 --- a/dlls/win32u/ntuser_private.h +++ b/dlls/win32u/ntuser_private.h @@ -137,6 +137,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) ); diff --git a/dlls/win32u/sysparams.c b/dlls/win32u/sysparams.c index e2c5b10da9e..bdf8ed70262 100644 --- a/dlls/win32u/sysparams.c +++ b/dlls/win32u/sysparams.c @@ -6204,6 +6204,7 @@ static void thread_detach(void) destroy_thread_windows(); cleanup_imm_thread(); NtClose( thread_info->server_queue ); + cleanup_thread_desktop();
exiting_thread_id = 0; } diff --git a/dlls/win32u/win32u_private.h b/dlls/win32u/win32u_private.h index d5f010a8249..edcf45a032e 100644 --- a/dlls/win32u/win32u_private.h +++ b/dlls/win32u/win32u_private.h @@ -194,6 +194,8 @@ extern void user_unlock(void); extern void user_check_not_lock(void);
/* winstation.c */ +extern const desktop_shm_t *get_desktop_shared_memory(void); +extern void cleanup_thread_desktop(void); extern BOOL is_virtual_desktop(void);
/* window.c */ @@ -362,4 +364,27 @@ static inline BOOL intersect_rect( RECT *dst, const RECT *src1, const RECT *src2 return !IsRectEmpty( dst ); }
+#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) YieldProcessor(); \ + __SHARED_READ_FENCE; \ + do + +#define SHARED_READ_END \ + while (0); \ + __SHARED_READ_FENCE; \ + } while (__SHARED_READ_SEQ( __shared->seq ) != __seq); \ + } while(0) + #endif /* __WINE_WIN32U_PRIVATE */ diff --git a/dlls/win32u/winstation.c b/dlls/win32u/winstation.c index b187b246941..9012c377f99 100644 --- a/dlls/win32u/winstation.c +++ b/dlls/win32u/winstation.c @@ -40,6 +40,60 @@ WINE_DECLARE_DEBUG_CHANNEL(win);
#define DESKTOP_ALL_ACCESS 0x01ff
+static volatile void *map_object_shared_memory( HANDLE object, SIZE_T size ) +{ + static const WCHAR object_mappingW[] = + { + '_','_','w','i','n','e','_','m','a','p','p','i','n','g',0 + }; + UNICODE_STRING section_str = RTL_CONSTANT_STRING( object_mappingW ); + OBJECT_ATTRIBUTES attr; + HANDLE handle; + UINT status; + void *ptr; + + InitializeObjectAttributes( &attr, §ion_str, 0, object, NULL ); + if (!(status = NtOpenSection( &handle, SECTION_MAP_READ, &attr ))) + { + ptr = NULL; + status = NtMapViewOfSection( handle, GetCurrentProcess(), &ptr, 0, 0, NULL, + &size, ViewUnmap, 0, PAGE_READONLY ); + NtClose( handle ); + } + + if (status) + { + ERR( "Failed to map object %p mapping, status %#x\n", object, status ); + return NULL; + } + + return ptr; +} + +const desktop_shm_t *get_desktop_shared_memory(void) +{ + struct user_thread_info *thread_info = get_user_thread_info(); + + if (!thread_info->desktop_shm) + { + HANDLE desktop = NtUserGetThreadDesktop( GetCurrentThreadId() ); + thread_info->desktop_shm = map_object_shared_memory( desktop, sizeof(*thread_info->desktop_shm) ); + } + + return thread_info->desktop_shm; +} + +void cleanup_thread_desktop(void) +{ + struct user_thread_info *thread_info = get_user_thread_info(); + + if (thread_info->desktop_shm) + { + NtUnmapViewOfSection( GetCurrentProcess(), (void *)thread_info->desktop_shm ); + thread_info->desktop_shm = NULL; + } +} + BOOL is_virtual_desktop(void) { HANDLE desktop = NtUserGetThreadDesktop( GetCurrentThreadId() ); @@ -265,6 +319,7 @@ 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 ); + cleanup_thread_desktop(); } return ret; }
On Wed Jan 31 16:58:02 2024 +0000, Jinoh Kang wrote:
(super nit)
section_str = RTL_CONSTANT_STRING( mapping_nameW );
Done, I also renamed the constant to match the server side, so grepping finds both.
On Wed Jan 31 16:58:08 2024 +0000, Jinoh Kang wrote:
If the host and guest page sizes don't match, I think we should prefer the original size for mmap(2). Note that we also use original size for munmap(2).
if ((tmp = mmap( NULL, size, PROT_READ | PROT_WRITE, MAP_SHARED, get_unix_fd( mapping->fd ), 0 )) == MAP_FAILED)
Done thanks.
On Wed Jan 31 16:59:45 2024 +0000, Rémi Bernon wrote:
Is this something we should be worried about already? Fwiw this mechanism has been in Proton for a while and I don't think there's been issues because of that. I don't think we can do much about it and if that only means pooling the mappings, I would prefer to only pay the price of the increased complexity if truly necessary.
The shared mapping allocation affects existing code path, so I'm inclined to believe that out-of-memory regression is inevitable, especially for 32bit apps.
Instead, how about calling `wine_server_handle_to_fd()` (include/wine/server.h) on the mapping and passing the returned fd to mmap(2)? No pooling necessary.
On Wed Jan 31 17:32:57 2024 +0000, Jinoh Kang wrote:
The shared mapping allocation affects existing code path, so I'm inclined to believe that out-of-memory regression is inevitable, especially for 32bit apps. Instead, how about calling `wine_server_handle_to_fd()` (include/wine/server.h) on the mapping and passing the returned fd to mmap(2)? No pooling necessary.
(FWIW this is approximately what we're doing for KUSD.)
On Wed Jan 31 17:33:34 2024 +0000, Jinoh Kang wrote:
(FWIW this is approximately what we're doing for KUSD.)
This is is PE code though, mmap() is not possible. KUSD is mmaped on the Unix side. Even on the unix side mixing Nt mappings with native mmap on their fds seems less than ideal, to say the least, in that case it should probably be done without the use of Nt mappings at all, with all the added complexity and Unix side interfacing. IMO if we have to solve this pooling shared mappings is a simpler option.
On Wed Jan 31 17:45:10 2024 +0000, Paul Gofman wrote:
This is is PE code though, mmap() is not possible. KUSD is mmaped on the Unix side. Even on the unix side mixing Nt mappings with native mmap on their fds seems less than ideal, to say the least, in that case it should probably be done without the use of Nt mappings at all, with all the added complexity and Unix side interfacing. IMO if we have to solve this pooling shared mappings is a simpler option.
Eh, that is not PE code of course, but I guess the rest stays valid.
This is is PE code though
winstation.c has `#pragma makedep unix` at the top, unless I'm mistaken. Did I miss some PE code that accesses the mapping directly?
On Wed Jan 31 17:47:34 2024 +0000, Jinoh Kang wrote:
This is is PE code though
winstation.c has `#pragma makedep unix` at the top, unless I'm mistaken. Did I miss some PE code that accesses the mapping directly?
yes, of course. Yet this path requires avoiding the use Nt mapping objects entirely.
Even on the unix side mixing Nt mappings with native mmap on their fds
I think we're doing exactly this with KUSD; see `virtual_map_user_shared_data`.
On Wed Jan 31 17:53:14 2024 +0000, Jinoh Kang wrote:
Even on the unix side mixing Nt mappings with native mmap on their fds
I think we're doing exactly this with KUSD; see `virtual_map_user_shared_data`.
So, that would essentially be something like?
```suggestion:-3+3 if (!(status = NtOpenSection( &handle, SECTION_MAP_READ, &attr ))) { int fd;
if (!(status = wine_server_handle_to_fd( handle, 0, &fd, NULL ))) { if ((ptr = mmap( NULL, size, PROT_READ, MAP_SHARED, fd, 0 )) == MAP_FAILED) status = STATUS_UNSUCCESSFUL; close( fd ); }
NtClose( handle ); } ```
Seems to be simple enough to me.
On Wed Jan 31 17:58:41 2024 +0000, Rémi Bernon wrote:
So, that would essentially be something like?
if (!(status = NtOpenSection( &handle, SECTION_MAP_READ, &attr ))) { int fd; if (!(status = wine_server_handle_to_fd( handle, 0, &fd, NULL ))) { if ((ptr = mmap( NULL, size, PROT_READ, MAP_SHARED, fd, 0 )) == MAP_FAILED) status = STATUS_UNSUCCESSFUL; close( fd ); } NtClose( handle ); }
Seems to be simple enough to me.
Should we then be worried that mmap will go through NT virtual memory management unnoticed?
Should we then be worried that mmap will go through NT virtual memory management unnoticed?
That could be a problem, yes, if PE side accesses the mapping directly. We could avoid this by just shifting everything accessing the mapping to the Unix side. In case PE-side access becomes *ever* necessary/critical for performance, then we can start considering pooling at that point.
On Wed Jan 31 18:01:42 2024 +0000, Jinoh Kang wrote:
Should we then be worried that mmap will go through NT virtual memory
management unnoticed? That could be a problem, yes, if PE side accesses the mapping directly. We could avoid this by just shifting everything accessing the mapping to the Unix side. In case PE-side access becomes *ever* necessary/critical for performance, then we can start considering pooling at that point.
Of course, I guess this exact snippet will break right at `NtClose( handle );`which will destroy the mapping. But it is not the core problem even, that can probably be worked around somehow, just it seems obvious to me that doing lower level management of Nt objects behind the back of their implementation leaves them in a broken state and we'll have to keep that in mind and workaround on various occasions, it just doesn't worth mixing those.
On Wed Jan 31 18:02:03 2024 +0000, Paul Gofman wrote:
Of course, I guess this exact snippet will break right at `NtClose( handle );`which will destroy the mapping. But it is not the core problem even, that can probably be worked around somehow, just it seems obvious to me that doing lower level management of Nt objects behind the back of their implementation leaves them in a broken state and we'll have to keep that in mind and workaround on various occasions, it just doesn't worth mixing those.
That applies the same for KUSD, which I don't think is a section object on Windows. But even then, the object is never intended to be exposed to the user anyway so I'd say we've already lost the moment the existence (and, transitively, its potentially-broken state) of the mapping object becomes publicly accessible to the app.
On Wed Jan 31 18:04:45 2024 +0000, Jinoh Kang wrote:
That applies the same for KUSD, which I don't think is a section object on Windows. But even then, the object is never intended to be exposed to the user anyway so I'd say we've already lost the moment the existence (and, transitively, its potentially-broken state) of the mapping object becomes publicly accessible to the app.
I'm actually thinking of adding some special flag that says "this should never be visible to the application." Sort of like `OBJ_KERNEL_HANDLE` but for objects themselves. This allows us to reuse the existing Ob facility while not risking breaking invariants expected on them. I'm not sure if it's worth introducing *right now*, though.
On Wed Jan 31 18:11:15 2024 +0000, Jinoh Kang wrote:
I'm actually thinking of adding some special flag that says "this object should never be visible to the application." Sort of like `OBJ_KERNEL_HANDLE` but for objects themselves. This allows us to reuse the existing Ob facility while not risking breaking invariants expected on them. I'm not sure if it's worth introducing *right now*, though.
Or rather, are you saying that KUSD's broken state doesn't matter because it's closed before the application starts, but that isn't the case for desktop shared mapping? Like, another thread/proces suspending the desktop-accessing thread at the right moment and extracting the shared mapping handle remotely.
On Wed Jan 31 18:10:46 2024 +0000, Jinoh Kang wrote:
Or rather, are you saying that KUSD's broken state doesn't matter because it's closed before the application starts, but that isn't the case for desktop shared mapping? Like, another thread/proces suspending the desktop-accessing thread at the right moment and extracting the shared mapping handle remotely.
KUSD is handled in ntdll/unix/virtual.c at process initialization, it is a "singleton" object which is created once on the server and never destroyed. So while maybe it is not exactly perfect there as well, doing such hacks in win32u is much worse, it breaks layering with win32u starting making assumptions on Nt kernel object operation and performing memory management directly.
I think if saving space is needed now just avoiding Nt section is more straightforward than building Wine specific infrastructure around those, and some way of pooling of the shared memory is more straightforward than that.
On Wed Jan 31 18:11:53 2024 +0000, Paul Gofman wrote:
KUSD is handled in ntdll/unix/virtual.c at process initialization, it is a "singleton" object which is created once on the server and never destroyed. So while maybe it is not exactly perfect there as well, doing such hacks in win32u is much worse, it breaks layering with win32u starting making assumptions on Nt kernel object operation and performing memory management directly. I think if saving space is needed now just avoiding Nt section is more straightforward than building Wine specific infrastructure around those, and some way of pooling of the shared memory is more straightforward than that.
How about using `NtCreateFile` instead? Mailslot responds to create_file by creating a file object backed by anonymous fd, so we can do something like that w/o abstraction layer violation. That would make `get_object_mapping` and its associated hacks unnecessary; we would just have to implement lookup_name` and perhaps `open_file` (shouldn't be needed if we're using regular/Unix file objects).
On Wed Jan 31 18:21:16 2024 +0000, Jinoh Kang wrote:
How about using `NtCreateFile` instead? Mailslot responds to create_file by creating a file object backed by anonymous fd, so we can do something like that w/o abstraction layer violation. That would make `get_object_mapping` and its associated hacks unnecessary; we would just have to implement lookup_name` and perhaps `open_file` (shouldn't be needed if we're using regular/Unix file objects).
I don't think it's the right thing to do. This is shared memory and all shared memory in Wine is implemented using Nt sections. Using something else is going to be considered inappropriate.
Then I think the mmap may be fine as an optimization, or pooling the mappings if we really have to at some point, but in any case maybe it would be better to leave that for later. And for now, only have the simple solution merged.
Jinoh Kang (@iamahuman) commented about server/mapping.c:
return page_mask + 1;
}
+struct object *create_object_mapping( struct object *object, mem_size_t size, void **ptr )
Shall we accept a security descriptor for API consistency? (Out of scope of this MR, but I would even go far so as to argue that we should only grant `SECTION_MAP_READ` and nothing else in the DACL.)
Jinoh Kang (@iamahuman) commented about server/protocol.def:
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 +{
- 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;
How about merging the declaration?
```suggestion:-5+0 typedef volatile struct desktop_shared_memory { unsigned int seq; /* sequence number - server updating if (seq & 1) != 0 */ struct shared_cursor cursor; /* global cursor information */ } desktop_shm_t; ```
Note that this doesn't make `struct desktop_shared_memory` itself volatile.
Jinoh Kang (@iamahuman) commented about server/device.c:
return NULL;
}
+struct mapping *no_object_mapping( struct object *obj ) +{
- return NULL;
+}
I think this should go into server/object.c instead.
kernel_obj_list is specific to server-ntoskrnl object pairs; object mapping isn't.
Jinoh Kang (@iamahuman) commented about server/mapping.c:
if (root) release_object( root );
}
+static struct mapping *open_object_mapping( user_handle_t handle, struct unicode_str *name )
We have different types[^1] for USER[^u] and KERNEL[^k] handles. Since `get_handle_obj` accepts `obj_handle_t`, I believe this should be changed to:
```suggestion:-0+0 static struct mapping *open_object_mapping( obj_handle_t handle, struct unicode_str *name ) ```
[^1]: Currently the compiler is unable to catch handle type errors, since `obj_handle_t` and `user_handle_t` are both typedef aliases to `unsigned int`. This could use some improvement, though. [^u]: Documented in [User Objects](https://learn.microsoft.com/en-us/windows/win32/sysinfo/user-objects). USER handles are shared by all processes in the same session. Examples: HWND, HMENU, HACCEL, HCURSOR, HICON. [^k]: Documented in [Kernel Objects](https://learn.microsoft.com/en-us/windows/win32/sysinfo/kernel-objects). KERNEL handles are local to the process. Examples: HANDLE (for files, sections, processes, etc.), HDESK, HWINSTA.
Jinoh Kang (@iamahuman) commented about dlls/win32u/winstation.c:
#define DESKTOP_ALL_ACCESS 0x01ff
+static volatile void *map_object_shared_memory( HANDLE object, SIZE_T size )
This volatile seems unnecessary.
```suggestion:-0+0 static void *map_object_shared_memory( HANDLE object, SIZE_T size ) ```
Jinoh Kang (@iamahuman) commented about dlls/win32u/winstation.c:
#define DESKTOP_ALL_ACCESS 0x01ff
+static volatile void *map_object_shared_memory( HANDLE object, SIZE_T size ) +{
- static const WCHAR object_mappingW[] =
- {
'_','_','w','i','n','e','_','m','a','p','p','i','n','g',0
- };
- UNICODE_STRING section_str = RTL_CONSTANT_STRING( object_mappingW );
- OBJECT_ATTRIBUTES attr;
- HANDLE handle;
- UINT status;
```suggestion:-0+0please unsigned int status; // move me up :3 ``` For consistency with virtual_map_user_shared_data et al..
Jinoh Kang (@iamahuman) commented about dlls/win32u/win32u_private.h:
return !IsRectEmpty( dst );
}
+#if defined(__i386__) || defined(__x86_64__) +#define __SHARED_READ_SEQ( x ) (x) +#define __SHARED_READ_FENCE do {} while(0)
For consistency with most other noop macros:
```suggestion:-0+0 #define __SHARED_READ_FENCE ((void)0) ```
This way, `__SHARED_READ_FENCE` is always an expression (of type `void`) instead of a statement.
Jinoh Kang (@iamahuman) commented about dlls/win32u/input.c:
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 );
This is confusing to me, since it looks wrong at the first glance until you look up a bit to see that `ret` is initialized to TRUE. How about leaving this unchanged?
Can we use 64bit integer for counters? It should be as trivial as just changing the type. Note that Wine already assumes 64bit atomic support even for 32bit platforms.
On Fri Feb 9 10:04:31 2024 +0000, Jinoh Kang wrote:
Shall we accept a security descriptor for API consistency? (Out of scope of this MR, but I would even go far so as to argue that we should only grant `SECTION_MAP_READ` and nothing else in the DACL.)
Since this is confusing I'll just mark this one as resolved.
On Sat Feb 10 21:18:59 2024 +0000, Jinoh Kang wrote:
Can we use 64bit integer for counters? It should be as trivial as just changing the type. Note that Wine already assumes 64bit atomic support even for 32bit platforms.
How important is this? This is mildly annoying, as we don't have ReadNoFence64 yet, and as it takes an 8 byte aligned LONG64 pointer, whereas __int64 which is used in protocol.def is 4 byte aligned, which triggers some compiler warning.
I suggest we stick to 32bit, I think this is very very unlikely to be an issue.