From: Rémi Bernon rbernon@codeweavers.com
--- server/protocol.def | 17 ++++- server/user.c | 181 ++++++++++++++++++++++++++------------------ server/user.h | 2 - 3 files changed, 123 insertions(+), 77 deletions(-)
diff --git a/server/protocol.def b/server/protocol.def index 1abe0fb0861..c3304d8b82b 100644 --- a/server/protocol.def +++ b/server/protocol.def @@ -976,9 +976,24 @@ struct shared_cursor struct rectangle clip; /* cursor clip rectangle */ };
+struct user_entry +{ + mem_size_t offset; /* shared user object offset */ + thread_id_t tid; /* owner thread id */ + process_id_t pid; /* owner process id */ + unsigned short type; /* object type (0 if free) */ + unsigned short generation; /* generation counter */ + unsigned int __pad; +}; +typedef volatile struct user_entry user_entry_t; + +#define MAX_USER_HANDLES ((LAST_USER_HANDLE - FIRST_USER_HANDLE + 1) >> 1) + typedef volatile struct { - int placeholder; + struct user_entry user_entries[MAX_USER_HANDLES]; + unsigned int user_entry_count; + unsigned int user_entry_next; } session_shm_t;
typedef volatile struct diff --git a/server/user.c b/server/user.c index 0f72b851770..43f314cb6aa 100644 --- a/server/user.c +++ b/server/user.c @@ -26,20 +26,10 @@ #include "thread.h" #include "file.h" #include "user.h" +#include "file.h" +#include "process.h" #include "request.h"
-struct user_handle -{ - void *ptr; /* pointer to object */ - unsigned short type; /* object type (0 if free) */ - unsigned short generation; /* generation counter */ -}; - -static struct user_handle *handles; -static struct user_handle *freelist; -static int nb_handles; -static int allocated_handles; - const session_shm_t *get_session_shm(void) { static const session_shm_t *session; @@ -49,7 +39,8 @@ const session_shm_t *get_session_shm(void) { SHARED_WRITE_BEGIN( session, session_shm_t ) { - shared->placeholder = 0; + shared->user_entry_count = 0; + shared->user_entry_next = -1; } SHARED_WRITE_END; } @@ -57,85 +48,120 @@ const session_shm_t *get_session_shm(void) return session; }
-static struct user_handle *handle_to_entry( user_handle_t handle ) +static void *server_objects[MAX_USER_HANDLES]; + +static void *get_server_object( const user_entry_t *entry ) { + const session_shm_t *session = get_session_shm(); + return server_objects[entry - session->user_entries]; +} + +static void *set_server_object( const user_entry_t *entry, void *ptr ) +{ + const session_shm_t *session = get_session_shm(); + void *prev = server_objects[entry - session->user_entries]; + server_objects[entry - session->user_entries] = ptr; + return prev; +} + +static const user_entry_t *handle_to_entry( user_handle_t handle ) +{ + const session_shm_t *session = get_session_shm(); + const user_entry_t *entry; unsigned short generation; - int index = ((handle & 0xffff) - FIRST_USER_HANDLE) >> 1; - if (index < 0 || index >= nb_handles) return NULL; - if (!handles[index].type) return NULL; + int index; + + index = ((handle & 0xffff) - FIRST_USER_HANDLE) >> 1; + if (index < 0 || index >= session->user_entry_count) return NULL; + + entry = session->user_entries + index; + if (!entry->type) return NULL; + generation = handle >> 16; - if (generation == handles[index].generation || !generation || generation == 0xffff) - return &handles[index]; + if (generation == entry->generation || !generation || generation == 0xffff) return entry; return NULL; }
-static inline user_handle_t entry_to_handle( struct user_handle *ptr ) +static user_handle_t entry_to_handle( const user_entry_t *entry ) { - unsigned int index = ptr - handles; - return (index << 1) + FIRST_USER_HANDLE + (ptr->generation << 16); + const session_shm_t *session = get_session_shm(); + unsigned int index = entry - session->user_entries; + return (index << 1) + FIRST_USER_HANDLE + (entry->generation << 16); }
-static inline struct user_handle *alloc_user_entry(void) +static const user_entry_t *alloc_user_entry( unsigned short type ) { - struct user_handle *handle; + const session_shm_t *session = get_session_shm(); + const user_entry_t *ret;
- if (freelist) - { - handle = freelist; - freelist = handle->ptr; - return handle; - } - if (nb_handles >= allocated_handles) /* need to grow the array */ + SHARED_WRITE_BEGIN( session, session_shm_t ) { - struct user_handle *new_handles; - /* grow array by 50% (but at minimum 32 entries) */ - int growth = max( 32, allocated_handles / 2 ); - int new_size = min( allocated_handles + growth, MAX_USER_HANDLES ); - if (new_size <= allocated_handles) return NULL; - if (!(new_handles = realloc( handles, new_size * sizeof(*handles) ))) - return NULL; - handles = new_handles; - allocated_handles = new_size; + user_entry_t *entry; + + if (shared->user_entry_next != -1) + { + entry = shared->user_entries + shared->user_entry_next; + shared->user_entry_next = entry->offset; + if (++entry->generation >= 0xffff) entry->generation = 1; + } + else + { + entry = shared->user_entries + shared->user_entry_count; + shared->user_entry_count++; + entry->generation = 1; + } + + entry->offset = -1; + entry->tid = get_thread_id( current ); + entry->pid = get_process_id( current->process ); + entry->type = type; + + ret = entry; } - handle = &handles[nb_handles++]; - handle->generation = 0; - return handle; + SHARED_WRITE_END; + + return ret; }
-static inline void *free_user_entry( struct user_handle *ptr ) +static void free_user_entry( const user_entry_t *entry ) { - void *ret; - ret = ptr->ptr; - ptr->ptr = freelist; - ptr->type = 0; - freelist = ptr; - return ret; + const session_shm_t *session = get_session_shm(); + size_t index = entry - session->user_entries; + + SHARED_WRITE_BEGIN( session, session_shm_t ) + { + shared->user_entries[index].offset = shared->user_entry_next; + shared->user_entries[index].pid = 0; + shared->user_entries[index].tid = 0; + shared->user_entries[index].type = 0; + shared->user_entry_next = index; + } + SHARED_WRITE_END; }
/* allocate a user handle for a given object */ user_handle_t alloc_user_handle( void *ptr, unsigned short type ) { - struct user_handle *entry = alloc_user_entry(); - if (!entry) return 0; - entry->ptr = ptr; - entry->type = type; - if (++entry->generation >= 0xffff) entry->generation = 1; + const user_entry_t *entry; + + if (!(entry = alloc_user_entry( type ))) return 0; + set_server_object( entry, ptr ); return entry_to_handle( entry ); }
/* return a pointer to a user object from its handle */ void *get_user_object( user_handle_t handle, unsigned short type ) { - struct user_handle *entry; + const user_entry_t *entry;
if (!(entry = handle_to_entry( handle )) || entry->type != type) return NULL; - return entry->ptr; + return get_server_object( entry ); }
/* get the full handle for a possibly truncated handle */ user_handle_t get_user_full_handle( user_handle_t handle ) { - struct user_handle *entry; + const user_entry_t *entry;
if (handle >> 16) return handle; if (!(entry = handle_to_entry( handle ))) return handle; @@ -145,44 +171,49 @@ user_handle_t get_user_full_handle( user_handle_t handle ) /* same as get_user_object plus set the handle to the full 32-bit value */ void *get_user_object_handle( user_handle_t *handle, unsigned short type ) { - struct user_handle *entry; + const user_entry_t *entry;
if (!(entry = handle_to_entry( *handle )) || entry->type != type) return NULL; *handle = entry_to_handle( entry ); - return entry->ptr; + return get_server_object( entry ); }
/* free a user handle and return a pointer to the object */ void *free_user_handle( user_handle_t handle ) { - struct user_handle *entry; + const user_entry_t *entry; + void *ret;
if (!(entry = handle_to_entry( handle ))) { set_error( STATUS_INVALID_HANDLE ); return NULL; } - return free_user_entry( entry ); + + ret = set_server_object( entry, NULL ); + free_user_entry( entry ); + return ret; }
/* return the next user handle after 'handle' that is of a given type */ void *next_user_handle( user_handle_t *handle, unsigned short type ) { - struct user_handle *entry; + const session_shm_t *session = get_session_shm(); + const user_entry_t *entry;
- if (!*handle) entry = handles; + if (!*handle) entry = session->user_entries; else { int index = ((*handle & 0xffff) - FIRST_USER_HANDLE) >> 1; - if (index < 0 || index >= nb_handles) return NULL; - entry = handles + index + 1; /* start from the next one */ + if (index < 0 || index >= session->user_entry_count) return NULL; + entry = session->user_entries + index + 1; /* start from the next one */ } - while (entry < handles + nb_handles) + while (entry < session->user_entries + session->user_entry_count) { if (!type || entry->type == type) { *handle = entry_to_handle( entry ); - return entry->ptr; + return get_server_object( entry ); } entry++; } @@ -192,16 +223,18 @@ void *next_user_handle( user_handle_t *handle, unsigned short type ) /* free client-side user handles managed by the process */ void free_process_user_handles( struct process *process ) { - unsigned int i; + const session_shm_t *session = get_session_shm(); + unsigned int i, pid = get_process_id( process );
- for (i = 0; i < nb_handles; i++) + for (i = 0; i < session->user_entry_count; i++) { - switch (handles[i].type) + const user_entry_t *entry = session->user_entries + i; + switch (entry->type) { case NTUSER_OBJ_HOOK: continue; case NTUSER_OBJ_WINDOW: continue; default: - if (handles[i].ptr == process) free_user_entry( &handles[i] ); + if (entry->pid == pid) free_user_entry( entry ); break; } } @@ -210,14 +243,14 @@ void free_process_user_handles( struct process *process ) /* allocate an arbitrary user handle */ DECL_HANDLER(alloc_user_handle) { - reply->handle = alloc_user_handle( current->process, req->type ); + reply->handle = alloc_user_handle( NULL, req->type ); }
/* free an arbitrary user handle */ DECL_HANDLER(free_user_handle) { - struct user_handle *entry; + const user_entry_t *entry;
if ((entry = handle_to_entry( req->handle )) && entry->type == req->type) free_user_entry( entry ); diff --git a/server/user.h b/server/user.h index 473ff0ce820..06541ff8ec3 100644 --- a/server/user.h +++ b/server/user.h @@ -36,8 +36,6 @@ struct clipboard;
#define DESKTOP_ATOM ((atom_t)32769)
-#define MAX_USER_HANDLES ((LAST_USER_HANDLE - FIRST_USER_HANDLE + 1) >> 1) - struct winstation { struct object obj; /* object header */