From: Rémi Bernon rbernon@codeweavers.com
--- server/file.h | 4 +++ server/mapping.c | 74 +++++++++++++++++++++++++++++++++++++++++++++ server/protocol.def | 8 +++++ server/user.h | 1 + server/winstation.c | 19 ++++++++++++ 5 files changed, 106 insertions(+)
diff --git a/server/file.h b/server/file.h index ab6e475539b..efacf240cb2 100644 --- a/server/file.h +++ b/server/file.h @@ -193,6 +193,10 @@ extern struct mapping *create_session_mapping( struct object *root, const struct extern void set_session_mapping( struct mapping *mapping );
+extern int alloc_shared_object(void); +extern void free_shared_object( int index ); +extern const desktop_shm_t *get_shared_desktop( int index ); + #define SHARED_WRITE_BEGIN( object, type ) \ do { \ const type *__shared = (object); \ diff --git a/server/mapping.c b/server/mapping.c index c540cd5bad9..8987fb0dd8e 100644 --- a/server/mapping.c +++ b/server/mapping.c @@ -229,6 +229,7 @@ struct session { const session_shm_t *shared; unsigned int object_count; + object_id_t last_object_id; }; static struct mapping *session_mapping; static struct session session; @@ -1285,6 +1286,79 @@ void set_session_mapping( struct mapping *mapping ) SHARED_WRITE_END; }
+static int grow_session_mapping(void) +{ + unsigned int capacity; + mem_size_t size; + int unix_fd; + void *tmp; + + capacity = session.shared->object_capacity * 3 / 2; + size = offsetof(session_shm_t, objects[capacity]); + size = (size + page_mask) & ~((mem_size_t)page_mask); + + 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) return -1; + munmap( (void *)session.shared, session_mapping->size ); + session.shared = tmp; + session_mapping->size = size; + + SHARED_WRITE_BEGIN( session.shared, session_shm_t ) + { + shared->obj.id++; + shared->object_capacity = (size - offsetof(session_shm_t, objects[0])) / sizeof(session_obj_t); + } + SHARED_WRITE_END; + + return 0; +} + +int alloc_shared_object(void) +{ + int index; + + if (session.object_count < session.shared->object_capacity) + index = session.object_count++; + else + { + for (index = 0; index < session.object_count; index++) + if (!session.shared->objects[index].obj.id) + break; + if (index == session.object_count) + { + if (grow_session_mapping()) return -1; + index = session.object_count++; + } + } + + SHARED_WRITE_BEGIN( &session.shared->objects[index], session_obj_t ) + { + shared->obj.id = ++session.last_object_id; + } + SHARED_WRITE_END; + + return index; +} + +void free_shared_object( int index ) +{ + if (index < 0) return; + + SHARED_WRITE_BEGIN( &session.shared->objects[index], session_obj_t ) + { + shared->obj.id = 0; + } + SHARED_WRITE_END; +} + +const desktop_shm_t *get_shared_desktop( int index ) +{ + if (index < 0) return NULL; + return &session.shared->objects[index].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 2a3c25b7892..dcbdf23bb3f 100644 --- a/server/protocol.def +++ b/server/protocol.def @@ -889,9 +889,15 @@ typedef volatile struct object_id_t id; /* object unique id, object data is valid if != 0 */ } object_shm_t;
+typedef volatile struct +{ + object_shm_t obj; +} desktop_shm_t; + typedef volatile union { object_shm_t obj; + desktop_shm_t desktop; } session_obj_t;
typedef volatile struct @@ -2810,6 +2816,8 @@ enum coords_relative thread_id_t tid; /* thread id */ @REPLY obj_handle_t handle; /* handle to the desktop */ + int index; /* index of desktop object in session shared memory */ + object_id_t object_id; /* id of the session object */ @END
diff --git a/server/user.h b/server/user.h index b4cf618f87e..599ffd68c19 100644 --- a/server/user.h +++ b/server/user.h @@ -80,6 +80,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 */ + int session_index; /* desktop index in session shared memory */ };
/* user handles functions */ diff --git a/server/winstation.c b/server/winstation.c index 373a1f7ba92..4de5dd69039 100644 --- a/server/winstation.c +++ b/server/winstation.c @@ -296,6 +296,13 @@ 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->session_index = -1; + + if ((desktop->session_index = alloc_shared_object()) == -1) + { + release_object( desktop ); + return NULL; + } } else { @@ -363,6 +370,7 @@ 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 ); + free_shared_object( desktop->session_index ); }
/* retrieve the thread desktop, checking the handle access rights */ @@ -726,10 +734,21 @@ DECL_HANDLER(close_desktop) /* get the thread current desktop */ DECL_HANDLER(get_thread_desktop) { + struct desktop *desktop; struct thread *thread;
if (!(thread = get_thread_from_id( req->tid ))) return; reply->handle = thread->desktop; + reply->index = -1; + + if ((desktop = get_thread_desktop( thread, 0 ))) + { + const desktop_shm_t *desktop_shm = get_shared_desktop( desktop->session_index ); + reply->index = desktop->session_index; + reply->object_id = desktop_shm->obj.id; + release_object( desktop ); + } + release_object( thread ); }