First part of Proton shared memory series. The full branch can be seen at https://gitlab.winehq.org/rbernon/wine/-/commits/mr/shared-memories.
-- v18: user32: Use the desktop shared data for GetCursorPos(). include: Add ReadNoFence64 inline helpers. 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 | 8 ++++++++ server/user.h | 2 ++ server/winstation.c | 12 ++++++++++++ 5 files changed, 40 insertions(+)
diff --git a/server/file.h b/server/file.h index 7f2d1637863..e953120ef80 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 6b0de1b8b94..90b9c3bbe57 100644 --- a/server/mapping.c +++ b/server/mapping.c @@ -1256,6 +1256,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 8b51618ebe0..311a7082ef6 100644 --- a/server/protocol.def +++ b/server/protocol.def @@ -879,6 +879,14 @@ typedef struct lparam_t info; } cursor_pos_t;
+/****************************************************************/ +/* objects shared mapping structures */ + +typedef volatile struct +{ + int placeholder; +} desktop_shm_t; + /****************************************************************/ /* Request declarations */
diff --git a/server/user.h b/server/user.h index 8fa55e09b0f..c002be20fa7 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 (const outside SHARED_WRITE_BEGIN/END) */ };
/* 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 | 91 +++++++++++++++++++++++++++++---------------- server/user.h | 3 -- 3 files changed, 66 insertions(+), 37 deletions(-)
diff --git a/server/protocol.def b/server/protocol.def index 311a7082ef6..84157dc2b05 100644 --- a/server/protocol.def +++ b/server/protocol.def @@ -882,9 +882,16 @@ typedef struct /****************************************************************/ /* objects shared mapping structures */
+struct shared_cursor +{ + int x; /* cursor position */ + int y; + unsigned int last_change; /* time of last position change */ +}; + typedef volatile struct { - int placeholder; + struct shared_cursor cursor; /* global cursor information */ } desktop_shm_t;
/****************************************************************/ diff --git a/server/queue.c b/server/queue.c index 6f38227aa84..7d9d6ac9ee6 100644 --- a/server/queue.c +++ b/server/queue.c @@ -233,6 +233,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 );
@@ -424,8 +434,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 ); } @@ -464,13 +474,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 ); @@ -516,8 +532,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(); }
@@ -541,9 +557,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 ); @@ -1696,8 +1712,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 ))) { @@ -1996,7 +2012,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;
@@ -2017,10 +2033,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) { @@ -2029,23 +2050,27 @@ 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 ))) { + int raw_x, raw_y; + raw_x = x - desktop->shared->cursor.x; + raw_y = y - desktop->shared->cursor.y; + memset( &raw_msg, 0, sizeof(raw_msg) ); raw_msg.foreground = foreground; raw_msg.desktop = desktop; @@ -2053,7 +2078,7 @@ static int queue_mouse_message( struct desktop *desktop, user_handle_t win, cons raw_msg.time = time; raw_msg.message = WM_INPUT; raw_msg.flags = flags; - rawmouse_init( &raw_msg.rawinput, &raw_msg.data.mouse, x - desktop->cursor.x, y - desktop->cursor.y, + rawmouse_init( &raw_msg.rawinput, &raw_msg.data.mouse, raw_x, raw_y, raw_msg.flags, input->mouse.data, input->mouse.info );
enum_processes( queue_rawinput_message, &raw_msg ); @@ -2263,8 +2288,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 ); } @@ -2785,8 +2810,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) { @@ -2804,8 +2829,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 ); }
@@ -3497,8 +3522,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) { @@ -3521,10 +3546,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 c002be20fa7..ccc713a8125 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 | 5 +++++ 2 files changed, 6 insertions(+)
diff --git a/server/protocol.def b/server/protocol.def index 84157dc2b05..5d7b843d592 100644 --- a/server/protocol.def +++ b/server/protocol.def @@ -891,6 +891,7 @@ struct shared_cursor
typedef volatile struct { + LONG64 seq; /* sequence number - server updating if (seq & 1) != 0 */ struct shared_cursor cursor; /* global cursor information */ } desktop_shm_t;
diff --git a/server/queue.c b/server/queue.c index 7d9d6ac9ee6..c19cf5c3806 100644 --- a/server/queue.c +++ b/server/queue.c @@ -237,10 +237,15 @@ static unsigned int cursor_history_latest; do { \ const type *__shared = (object)->shared; \ type *shared = (type *)__shared; \ + LONG64 __seq = shared->seq + 1, __end = __seq + 1; \ + assert( (__seq & 1) != 0 ); \ + __WINE_ATOMIC_STORE_RELEASE( &shared->seq, &__seq ); \ do
#define SHARED_WRITE_END \ while(0); \ + assert( __seq == shared->seq ); \ + __WINE_ATOMIC_STORE_RELEASE( &shared->seq, &__end ); \ } 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 | 4 ++++ 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.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 ++++++++++ 34 files changed, 106 insertions(+)
diff --git a/server/async.c b/server/async.c index 80129ac0ac3..dcc45973c64 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 */ }; @@ -698,6 +699,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 c59a0abea77..7ca3d5722a4 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..bfede2e496b 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 */ }; 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 71cdd2e328c..e66ab994a11 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 90b9c3bbe57..dd2f18c6d65 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 */ }; @@ -1315,10 +1318,35 @@ DECL_HANDLER(create_mapping) if (root) release_object( root ); }
+static struct mapping *open_object_mapping( obj_handle_t handle, const 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.c b/server/object.c index 89e541ffb6b..4f12a9c0980 100644 --- a/server/object.c +++ b/server/object.c @@ -710,6 +710,11 @@ struct object *no_open_file( struct object *obj, unsigned int access, unsigned i return NULL; }
+struct mapping *no_object_mapping( struct object *obj ) +{ + return NULL; +} + int no_close_handle( struct object *obj, struct process *process, obj_handle_t handle ) { return 1; /* ok to close */ diff --git a/server/object.h b/server/object.h index d4d66536b81..d94a1a2d734 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 3651696f505..eceefc2b274 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 c19cf5c3806..fe2e73e7b86 100644 --- a/server/queue.c +++ b/server/queue.c @@ -186,6 +186,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 */ }; @@ -223,6 +224,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 e88bed1e72e..4af5b8563ec 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 3ad1ce39194..614c6871e96 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
--- include/winnt.h | 16 ++++++++++++++++ 1 file changed, 16 insertions(+)
diff --git a/include/winnt.h b/include/winnt.h index 0e0d1cb5170..24df62404c5 100644 --- a/include/winnt.h +++ b/include/winnt.h @@ -6990,11 +6990,14 @@ static FORCEINLINE void MemoryBarrier(void) */ #if _MSC_VER >= 1700 #pragma intrinsic(__iso_volatile_load32) +#pragma intrinsic(__iso_volatile_load64) #pragma intrinsic(__iso_volatile_store32) #define __WINE_LOAD32_NO_FENCE(src) (__iso_volatile_load32(src)) +#define __WINE_LOAD64_NO_FENCE(src) (__iso_volatile_load64(src)) #define __WINE_STORE32_NO_FENCE(dest, value) (__iso_volatile_store32(dest, value)) #else /* _MSC_VER >= 1700 */ #define __WINE_LOAD32_NO_FENCE(src) (*(src)) +#define __WINE_LOAD64_NO_FENCE(src) (*(src)) #define __WINE_STORE32_NO_FENCE(dest, value) ((void)(*(dest) = (value))) #endif /* _MSC_VER >= 1700 */
@@ -7028,6 +7031,12 @@ static FORCEINLINE LONG ReadNoFence( LONG const volatile *src ) return value; }
+static FORCEINLINE LONG64 ReadNoFence64( LONG64 const volatile *src ) +{ + LONG64 value = __WINE_LOAD64_NO_FENCE( (__int64 const volatile *)src ); + return value; +} + static FORCEINLINE void WriteRelease( LONG volatile *dest, LONG value ) { __wine_memory_barrier_acq_rel(); @@ -7214,6 +7223,13 @@ static FORCEINLINE LONG ReadNoFence( LONG const volatile *src ) return value; }
+static FORCEINLINE LONG64 ReadNoFence64( LONG64 const volatile *src ) +{ + LONG64 value; + __WINE_ATOMIC_LOAD_RELAXED( src, &value ); + return value; +} + static FORCEINLINE void WriteRelease( LONG volatile *dest, LONG value ) { __WINE_ATOMIC_STORE_RELEASE( dest, &value );
From: Rémi Bernon rbernon@codeweavers.com
Based on a patch by Huw Davies huw@codeweavers.com. --- dlls/win32u/input.c | 16 +++++------ 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, 90 insertions(+), 8 deletions(-)
diff --git a/dlls/win32u/input.c b/dlls/win32u/input.c index ef8d564c264..58df468f130 100644 --- a/dlls/win32u/input.c +++ b/dlls/win32u/input.c @@ -750,21 +750,21 @@ BOOL WINAPI NtUserSetCursorPos( INT x, INT y ) BOOL get_cursor_pos( POINT *pt ) { BOOL ret; + const desktop_shm_t *shared; DWORD last_change; UINT dpi;
if (!pt) return FALSE;
- SERVER_START_REQ( set_cursor ) + if (!(shared = get_desktop_shared_memory())) ret = FALSE; + else 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; + ret = TRUE; } - 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 ); diff --git a/dlls/win32u/ntuser_private.h b/dlls/win32u/ntuser_private.h index 3b6cab5bdc9..11fc1a19850 100644 --- a/dlls/win32u/ntuser_private.h +++ b/dlls/win32u/ntuser_private.h @@ -127,6 +127,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 673082056b1..03deb0a224d 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..26f50185fdf 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__) +/* this prevents compilers from incorrectly reordering non-volatile reads (e.g., memcpy) from shared memory */ +#define __SHARED_READ_FENCE do { __asm__ __volatile__( "" ::: "memory" ); } while (0) +#else +#define __SHARED_READ_FENCE __atomic_thread_fence( __ATOMIC_ACQUIRE ) +#endif + +#define SHARED_READ_BEGIN( ptr, type ) \ + do { \ + const type *__shared = (ptr); \ + LONG64 __seq; \ + do { \ + while ((__seq = ReadNoFence64( &__shared->seq )) & 1) \ + YieldProcessor(); \ + __SHARED_READ_FENCE; \ + do + +#define SHARED_READ_END \ + while (0); \ + __SHARED_READ_FENCE; \ + } while (ReadNoFence64( &__shared->seq ) != __seq); \ + } while(0) + #endif /* __WINE_WIN32U_PRIVATE */ diff --git a/dlls/win32u/winstation.c b/dlls/win32u/winstation.c index b187b246941..9f736099870 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 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; + unsigned int status; + HANDLE handle; + 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 Mon Feb 12 11:10:29 2024 +0000, Rémi Bernon wrote:
I didn't try to share the desktop mappings, I think it could perhaps be done but I don't like the idea of pooling the mappings together as I feel it's just going to make things more complicated. Instead, we could easily add some kind of thread / process desktop deduplication for the most common case where the thread uses its process default desktop, which could be good enough and could be added later.
I think this needs to be revisited at some point, but this MR as-is seems fine (except perhaps mappings duplicated for each thread). We still have some unresolved questions (e.g., how is information specific to winstation/desktop in the same session placed in the shared memory), though (out of scope of this MR).
Addressed the last round of comments.
This merge request was approved by Jinoh Kang.
Huw Davies (@huw) commented about server/object.h:
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 *);
Adding another `object_ops` member just for this seems like overkill, but I'm going to approve this and let @julliard decide.
This merge request was approved by Huw Davies.
On Tue Feb 13 08:52:09 2024 +0000, Huw Davies wrote:
Adding another `object_ops` member just for this seems like overkill, but I'm going to approve this and let @julliard decide.
It does seem like overkill, and going in the wrong direction. I don't think we want to create a bunch of separate mappings for all kinds of objects. Ideally there would be just one mapping per desktop, with various structures allocated inside it.
On Mon Feb 19 11:09:34 2024 +0000, Alexandre Julliard wrote:
It does seem like overkill, and going in the wrong direction. I don't think we want to create a bunch of separate mappings for all kinds of objects. Ideally there would be just one mapping per desktop, with various structures allocated inside it.
Okay, I thought it could be useful for other objects at some point. At least for the purpose of the later changes, I intended to create mappings for thread inputs and for thread message queues.
I think having separate mappings for these makes the code much simpler as the mapping lifetime simply matches -or slightly exceed, until all references are released- the object lifetime. The clients can keep a reference on the mappings while they are using them and once they get stale -because thread input are detached, or because foreground input changes- call wineserver again to get the updated mapping.
I think managing these within the desktop mappings would simply make things much more complicated as we'd have to make sure they are not incorrectly reused, and synchronize with all clients possibly still reading from them.
Then I don't have any plan outside of these three object types, so we can probably have a more ad-hoc way instead of a new object ops, it was actually done that way initially. Would that be better?
On Mon Feb 19 11:24:12 2024 +0000, Rémi Bernon wrote:
Okay, I thought it could be useful for other objects at some point. At least for the purpose of the later changes, I intended to create mappings for thread inputs and for thread message queues. I think having separate mappings for these makes the code much simpler as the mapping lifetime simply matches -or slightly exceed, until all references are released- the object lifetime. The clients can keep a reference on the mappings while they are using them and once they get stale -because thread input are detached, or because foreground input changes- call wineserver again to get the updated mapping. I think managing these within the desktop mappings would simply make things much more complicated as we'd have to make sure they are not incorrectly reused, and synchronize with all clients possibly still reading from them. Then I don't have any plan outside of these three object types, so we can probably have a more ad-hoc way instead of a new object ops, it was actually done that way initially. Would that be better?
The issue is not so much the object ops, it's the separate mappings. I really don't think we want a mapping for every message queue and every thread input.
On Mon Feb 19 11:36:54 2024 +0000, Alexandre Julliard wrote:
The issue is not so much the object ops, it's the separate mappings. I really don't think we want a mapping for every message queue and every thread input.
Would you mind detailing why?
Using a single mapping for everything we'd simply have to reimplement what is implicit ourselves, handle various struct allocations, refernce counts, and deallocation, mitigate the induced fragmentation somehow, growing the desktop mapping when needed, convert pointers into offsets for the clients, etc... I think it'd be much more effort and complexity, with increased fragility, and I don't understand the point.
On Mon Feb 19 11:53:42 2024 +0000, Rémi Bernon wrote:
Would you mind detailing why? Using a single mapping for everything we'd simply have to reimplement what is implicit ourselves, handle various struct allocations, refernce counts, and deallocation, mitigate the induced fragmentation somehow, growing the desktop mapping when needed, convert pointers into offsets for the clients, etc... I think it'd be much more effort and complexity, with increased fragility, and I don't understand the point.
Mostly it's a waste of resources. Each mapping takes up handles and file descriptors, 64Kb of address space on the client side, and increases the server footprint as well. Mapping/unmapping is also a fairly expensive operation. It doesn't seem to be justified given the small amount of information that each mapping contains.