From: Rémi Bernon rbernon@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 32642b10c09..b2ebf3c2b3a 100644 --- a/server/protocol.def +++ b/server/protocol.def @@ -878,9 +878,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 */