From: Rémi Bernon rbernon@codeweavers.com
--- server/file.h | 19 ++++++++ server/mapping.c | 109 ++++++++++++++++++++++++++++++++++++++++++++ server/protocol.def | 11 ++++- server/user.h | 1 + server/winstation.c | 18 ++++++++ 5 files changed, 157 insertions(+), 1 deletion(-)
diff --git a/server/file.h b/server/file.h index 079f065b263..51fc6eb1858 100644 --- a/server/file.h +++ b/server/file.h @@ -191,6 +191,25 @@ extern struct object *create_user_data_mapping( struct object *root, const struc extern struct object *create_session_mapping( struct object *root, const struct unicode_str *name, unsigned int attr, const struct security_descriptor *sd );
+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); \ + type *shared = (type *)__shared; \ + LONG64 __seq = shared->obj.seq + 1, __end = __seq + 1; \ + assert( (__seq & 1) != 0 ); \ + __WINE_ATOMIC_STORE_RELEASE( &shared->obj.seq, &__seq ); \ + do + +#define SHARED_WRITE_END \ + while(0); \ + assert( __seq == shared->obj.seq ); \ + __WINE_ATOMIC_STORE_RELEASE( &shared->obj.seq, &__end ); \ + } while(0) + /* device functions */
extern struct object *create_named_pipe_device( struct object *root, const struct unicode_str *name, diff --git a/server/mapping.c b/server/mapping.c index 3a0c578ea4f..4a1d5a0c46e 100644 --- a/server/mapping.c +++ b/server/mapping.c @@ -1286,6 +1286,115 @@ struct object *create_session_mapping( struct object *root, const struct unicode return &mapping->obj; }
+static int grow_session_mapping(void) +{ + struct session new_session; + unsigned int capacity; + mem_size_t size; + int unix_fd, i; + struct fd *fd; + + capacity = session.object_capacity * 3 / 2; + size = offsetof(session_shm_t, objects[capacity]); + size = (size + page_mask) & ~((mem_size_t)page_mask); + + if ((unix_fd = create_temp_file( size )) == -1) return -1; + if (!(fd = create_anonymous_fd( &mapping_fd_ops, unix_fd, &session_mapping->obj, FILE_SYNCHRONOUS_IO_NONALERT ))) + { + close( unix_fd ); + return -1; + } + if ((new_session.shared = mmap( NULL, size, PROT_READ | PROT_WRITE, MAP_SHARED, unix_fd, 0 )) == MAP_FAILED) + { + release_object( fd ); + return -1; + } + allow_fd_caching( fd ); + + SHARED_WRITE_BEGIN( new_session.shared, session_shm_t ) + { + const session_shm_t *old_shared = session.shared; + + /* copy the valid objects, mark the invalid ones as fully destroyed. No need + * to write-lock the objects as nothing can be using the new session yet. */ + for (i = 0; i < session.object_count; i++) + { + const object_shm_t *old_object = &old_shared->objects[i].obj; + object_shm_t *object = &shared->objects[i].obj; + + if (!old_object->invalid) *object = *old_object; + else object->destroyed = 1; + } + + new_session.object_count = session.object_count; + } + SHARED_WRITE_END; + + SHARED_WRITE_BEGIN( session.shared, session_shm_t ) + { + shared->obj.invalid = 1; + } + SHARED_WRITE_END; + + for (i = 0; i < session.object_count; i++) + { + const session_obj_t *object = &session.shared->objects[i]; + SHARED_WRITE_BEGIN( object, session_obj_t ) + { + shared->obj.invalid = 1; + } + SHARED_WRITE_END; + } + + munmap( (void *)session.shared, session_mapping->size ); + release_object( session_mapping->fd ); + session_mapping->size = size; + session_mapping->fd = fd; + session = new_session; + + return 0; +} + +int alloc_shared_object(void) +{ + int i; + + for (i = 0; i < session.object_count; i++) + { + const session_obj_t *object = &session.shared->objects[i]; + if (object->obj.destroyed) + { + SHARED_WRITE_BEGIN( object, session_obj_t ) + { + shared->obj.destroyed = 0; + } + SHARED_WRITE_END; + return i; + } + } + + if (session.object_count == session.object_capacity && grow_session_mapping()) return -1; + return session.object_count++; +} + +void free_shared_object( int index ) +{ + const session_obj_t *object = &session.shared->objects[index]; + + if (index < 0) return; + SHARED_WRITE_BEGIN( object, session_obj_t ) + { + shared->obj.invalid = 1; + } + 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 0f8fdea441e..00daa50f894 100644 --- a/server/protocol.def +++ b/server/protocol.def @@ -884,12 +884,20 @@ typedef struct
typedef volatile struct { - int placeholder; + LONG64 seq; /* sequence number - server updating if (seq & 1) != 0 */ + unsigned int invalid; /* object has been invalidated, call wineserver */ + unsigned int destroyed; /* object has been destroyed, can be reused */ } 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 @@ -2801,6 +2809,7 @@ enum coords_relative thread_id_t tid; /* thread id */ @REPLY obj_handle_t handle; /* handle to the desktop */ + int session_index; /* index of desktop object in session shared memory */ @END
diff --git a/server/user.h b/server/user.h index 8fa55e09b0f..32f648b4dc2 100644 --- a/server/user.h +++ b/server/user.h @@ -76,6 +76,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 5903497d61e..0b6a118ef25 100644 --- a/server/winstation.c +++ b/server/winstation.c @@ -240,6 +240,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 { @@ -298,6 +305,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 */ @@ -601,10 +609,20 @@ 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; + + if (!(desktop = get_thread_desktop( thread, 0 ))) + reply->session_index = -1; + else + { + reply->session_index = desktop->session_index; + release_object( desktop ); + } + release_object( thread ); }