From: Rémi Bernon <rbernon(a)codeweavers.com>
---
server/file.h | 4 +++
server/mapping.c | 77 +++++++++++++++++++++++++++++++++++++++++++++
server/protocol.def | 7 ++++-
server/user.h | 1 +
server/winstation.c | 8 +++++
5 files changed, 96 insertions(+), 1 deletion(-)
diff --git a/server/file.h b/server/file.h
index a7397ffd093..691487179aa 100644
--- a/server/file.h
+++ b/server/file.h
@@ -192,6 +192,10 @@ extern struct mapping *create_session_mapping( struct object *root,
const struct
unsigned int attr, const struct
security_descriptor *sd );
extern void set_session_mapping( struct mapping *mapping );
+extern unsigned int alloc_shared_object(void);
+extern void free_shared_object( unsigned int index );
+extern const desktop_shm_t *get_shared_desktop( unsigned int index );
+
#define SHARED_WRITE_BEGIN( object_shm, type ) \
do { \
const type *__shared = (object_shm); \
diff --git a/server/mapping.c b/server/mapping.c
index 79072c8b9c8..218c9456d4b 100644
--- a/server/mapping.c
+++ b/server/mapping.c
@@ -229,6 +229,8 @@ struct session
{
const session_object_t *objects;
unsigned int object_capacity;
+ unsigned int last_object_index;
+ object_id_t last_object_id;
};
static struct mapping *session_mapping;
static struct session session;
@@ -1294,11 +1296,86 @@ void set_session_mapping( struct mapping *mapping )
session_mapping = mapping;
session.object_capacity = mapping->size / sizeof(*session.objects);
assert( session.object_capacity != -1 );
+ session.last_object_index = -1;
for (index = 0; index < session.object_capacity; index++)
mark_session_object_free( &session.objects[index] );
}
+static int grow_session_mapping(void)
+{
+ unsigned int index, capacity;
+ mem_size_t size;
+ int unix_fd;
+ void *tmp;
+
+ capacity = session.object_capacity * 3 / 2;
+ size = sizeof(*session.objects) * capacity;
+ size = (size + page_mask) & ~((mem_size_t)page_mask);
+ capacity = size / sizeof(*session.objects);
+ assert( capacity > session.object_capacity );
+
+ unix_fd = get_unix_fd( session_mapping->fd );
+ if (!grow_file( unix_fd, size )) return -1;
+
+ if ((tmp = mmap( NULL, size, PROT_READ | PROT_WRITE, MAP_SHARED, unix_fd, 0 )) ==
MAP_FAILED)
+ {
+ file_set_error();
+ return -1;
+ }
+ munmap( (void *)session.objects, session_mapping->size );
+ session.objects = tmp;
+
+ for (index = session.object_capacity; index < capacity; index++)
+ mark_session_object_free( &session.objects[index] );
+
+ session_mapping->size = size;
+ session.object_capacity = capacity;
+ assert( session.object_capacity != -1 );
+
+ return 0;
+}
+
+unsigned int alloc_shared_object(void)
+{
+ unsigned int index, offset = session.last_object_index + 1, capacity =
session.object_capacity;
+
+ for (index = offset; index != offset + capacity; index++)
+ if (!session.objects[index % capacity].id)
+ break;
+ if (index != offset + capacity) index %= capacity;
+ else
+ {
+ if (grow_session_mapping()) return -1;
+ index = capacity;
+ }
+
+ assert( index < session.object_capacity );
+ session.last_object_index = index;
+
+ SHARED_WRITE_BEGIN( &session.objects[index].shm, object_shm_t )
+ {
+ /* mark the object data as uninitialized */
+ mark_block_uninitialized( (void *)shared, sizeof(*shared) );
+ CONTAINING_RECORD( shared, session_object_t, shm )->id =
++session.last_object_id;
+ }
+ SHARED_WRITE_END;
+
+ return index;
+}
+
+void free_shared_object( unsigned int index )
+{
+ if (index >= session.object_capacity) return;
+ mark_session_object_free( &session.objects[index] );
+}
+
+const desktop_shm_t *get_shared_desktop( unsigned int index )
+{
+ if (index >= session.object_capacity) return NULL;
+ return &session.objects[index].shm.desktop;
+}
+
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 81ac7a65c14..1062e0ca689 100644
--- a/server/protocol.def
+++ b/server/protocol.def
@@ -891,9 +891,14 @@ typedef struct
/****************************************************************/
/* shared session mapping structures */
-typedef volatile union
+typedef volatile struct
{
char placeholder;
+} desktop_shm_t;
+
+typedef volatile union
+{
+ desktop_shm_t desktop;
} object_shm_t;
typedef volatile struct
diff --git a/server/user.h b/server/user.h
index d805a179d16..6079ab92451 100644
--- a/server/user.h
+++ b/server/user.h
@@ -82,6 +82,7 @@ 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 */
+ unsigned int session_index; /* desktop index in session shared memory */
};
/* user handles functions */
diff --git a/server/winstation.c b/server/winstation.c
index 80126ad5d60..167ac8aeb62 100644
--- a/server/winstation.c
+++ b/server/winstation.c
@@ -297,6 +297,13 @@ static struct desktop *create_desktop( const struct unicode_str
*name, unsigned
list_add_tail( &winstation->desktops, &desktop->entry );
list_init( &desktop->hotkeys );
list_init( &desktop->pointers );
+ desktop->session_index = alloc_shared_object();
+
+ if (!get_shared_desktop( desktop->session_index ))
+ {
+ release_object( desktop );
+ return NULL;
+ }
}
else
{
@@ -366,6 +373,7 @@ static void desktop_destroy( struct object *obj )
if (desktop->global_hooks) release_object( desktop->global_hooks );
if (desktop->close_timeout) remove_timeout_user( desktop->close_timeout );
release_object( desktop->winstation );
+ free_shared_object( desktop->session_index );
}
/* retrieve the thread desktop, checking the handle access rights */
--
GitLab
https://gitlab.winehq.org/wine/wine/-/merge_requests/3103