diff --git a/server/event.c b/server/event.c index 020c70ca535..da833d97118 100644 --- a/server/event.c +++ b/server/event.c @@ -65,7 +65,7 @@ struct event *create_event( const WCHAR *name, size_t len, { struct event *event; - if ((event = create_named_object( &event_ops, name, len ))) + if ((event = create_named_object( sync_namespace, &event_ops, name, len ))) { if (get_error() != STATUS_OBJECT_NAME_COLLISION) { @@ -145,7 +145,7 @@ DECL_HANDLER(create_event) /* open a handle to an event */ DECL_HANDLER(open_event) { - reply->handle = open_object( get_req_data(), get_req_data_size(), + reply->handle = open_object( sync_namespace, get_req_data(), get_req_data_size(), &event_ops, req->access, req->inherit ); } diff --git a/server/handle.c b/server/handle.c index 89c92d08dfd..00dbc54f6ce 100644 --- a/server/handle.c +++ b/server/handle.c @@ -154,7 +154,7 @@ static void handle_table_destroy( struct object *obj ) } /* allocate a new handle table */ -struct object *alloc_handle_table( struct process *process, int count ) +struct handle_table *alloc_handle_table( struct process *process, int count ) { struct handle_table *table; @@ -165,7 +165,7 @@ struct object *alloc_handle_table( struct process *process, int count ) table->count = count; table->last = -1; table->free = 0; - if ((table->entries = mem_alloc( count * sizeof(*table->entries) ))) return &table->obj; + if ((table->entries = mem_alloc( count * sizeof(*table->entries) ))) return table; release_object( table ); return NULL; } @@ -213,7 +213,7 @@ static obj_handle_t alloc_entry( struct handle_table *table, void *obj, unsigned /* return the handle, or 0 on error */ obj_handle_t alloc_handle( struct process *process, void *obj, unsigned int access, int inherit ) { - struct handle_table *table = (struct handle_table *)process->handles; + struct handle_table *table = process->handles; assert( table ); assert( !(access & RESERVED_ALL) ); @@ -236,7 +236,7 @@ static obj_handle_t alloc_global_handle( void *obj, unsigned int access ) /* return a handle entry, or NULL if the handle is invalid */ static struct handle_entry *get_handle( struct process *process, obj_handle_t handle ) { - struct handle_table *table = (struct handle_table *)process->handles; + struct handle_table *table = process->handles; struct handle_entry *entry; int index; @@ -281,9 +281,9 @@ static void shrink_handle_table( struct handle_table *table ) /* copy the handle table of the parent process */ /* return 1 if OK, 0 on error */ -struct object *copy_handle_table( struct process *process, struct process *parent ) +struct handle_table *copy_handle_table( struct process *process, struct process *parent ) { - struct handle_table *parent_table = (struct handle_table *)parent->handles; + struct handle_table *parent_table = parent->handles; struct handle_table *table; int i; @@ -307,7 +307,7 @@ struct object *copy_handle_table( struct process *process, struct process *paren } /* attempt to shrink the table */ shrink_handle_table( table ); - return &table->obj; + return table; } /* close a handle and decrement the refcount of the associated object */ @@ -329,7 +329,7 @@ int close_handle( struct process *process, obj_handle_t handle, int *fd ) if (fd) *fd = entry->fd; else if (entry->fd != -1) return 1; /* silently ignore close attempt if we cannot close the fd */ entry->fd = -1; - table = handle_is_global(handle) ? global_table : (struct handle_table *)process->handles; + table = handle_is_global(handle) ? global_table : process->handles; if (entry < table->entries + table->free) table->free = entry - table->entries; if (entry == table->entries + table->last) shrink_handle_table( table ); release_object( obj ); @@ -400,10 +400,28 @@ int get_handle_fd( struct process *process, obj_handle_t handle, unsigned int ac return entry->fd; } +/* find the first inherited handle of the given type */ +/* this is needed for window stations and desktops (don't ask...) */ +obj_handle_t find_inherited_handle( struct process *process, const struct object_ops *ops ) +{ + struct handle_table *table = process->handles; + struct handle_entry *ptr; + int i; + + if (!table) return 0; + + for (i = 0, ptr = table->entries; i <= table->last; i++, ptr++) + { + if (!ptr->ptr) continue; + if (ptr->ptr->ops != ops) continue; + if (ptr->access & RESERVED_INHERIT) return index_to_handle(i); + } + return 0; +} + /* get/set the handle reserved flags */ /* return the old flags (or -1 on error) */ -static int set_handle_info( struct process *process, obj_handle_t handle, - int mask, int flags, int *fd ) +int set_handle_info( struct process *process, obj_handle_t handle, int mask, int flags, int *fd ) { struct handle_entry *entry; unsigned int old_access; @@ -454,11 +472,11 @@ obj_handle_t duplicate_handle( struct process *src, obj_handle_t src_handle, str } /* open a new handle to an existing object */ -obj_handle_t open_object( const WCHAR *name, size_t len, const struct object_ops *ops, - unsigned int access, int inherit ) +obj_handle_t open_object( const struct namespace *namespace, const WCHAR *name, size_t len, + const struct object_ops *ops, unsigned int access, int inherit ) { obj_handle_t handle = 0; - struct object *obj = find_object( name, len ); + struct object *obj = find_object( namespace, name, len ); if (obj) { if (ops && obj->ops != ops) diff --git a/server/handle.h b/server/handle.h index 0dc9fb32b83..994ce48a6c7 100644 --- a/server/handle.h +++ b/server/handle.h @@ -27,6 +27,7 @@ struct process; struct object_ops; +struct namespace; /* handle functions */ @@ -38,12 +39,14 @@ extern int close_handle( struct process *process, obj_handle_t handle, int *fd ) extern struct object *get_handle_obj( struct process *process, obj_handle_t handle, unsigned int access, const struct object_ops *ops ); extern int get_handle_fd( struct process *process, obj_handle_t handle, unsigned int access ); +extern int set_handle_info( struct process *process, obj_handle_t handle, int mask, int flags, int *fd ); extern obj_handle_t duplicate_handle( struct process *src, obj_handle_t src_handle, struct process *dst, unsigned int access, int inherit, int options ); -extern obj_handle_t open_object( const WCHAR *name, size_t len, const struct object_ops *ops, - unsigned int access, int inherit ); -extern struct object *alloc_handle_table( struct process *process, int count ); -extern struct object *copy_handle_table( struct process *process, struct process *parent ); +extern obj_handle_t open_object( const struct namespace *namespace, const WCHAR *name, size_t len, + const struct object_ops *ops, unsigned int access, int inherit ); +extern obj_handle_t find_inherited_handle( struct process *process, const struct object_ops *ops ); +extern struct handle_table *alloc_handle_table( struct process *process, int count ); +extern struct handle_table *copy_handle_table( struct process *process, struct process *parent ); extern void close_global_handles(void); #endif /* __WINE_SERVER_HANDLE_H */ diff --git a/server/list.h b/server/list.h new file mode 100644 index 00000000000..b4a4c1f743f --- /dev/null +++ b/server/list.h @@ -0,0 +1,72 @@ +/* + * Linked lists support + * + * Copyright (C) 2002 Alexandre Julliard + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#ifndef __WINE_SERVER_LIST_H +#define __WINE_SERVER_LIST_H + +struct list +{ + struct list *next; + struct list *prev; +}; + +/* add element at the head of the list */ +inline static void list_add_head( struct list *list, struct list *elem ) +{ + elem->next = list->next; + elem->prev = list; + list->next->prev = elem; + list->next = elem; +} + +/* add element at the tail of the list */ +inline static void list_add_tail( struct list *list, struct list *elem ) +{ + elem->next = list; + elem->prev = list->prev; + list->prev->next = elem; + list->prev = elem; +} + +/* remove an element from its list */ +inline static void list_remove( struct list *elem ) +{ + elem->next->prev = elem->prev; + elem->prev->next = elem->next; +} + +/* initialize a list */ +inline static void list_init( struct list *list ) +{ + list->next = list->prev = list; +} + +/* iterate through the list */ +#define LIST_FOR_EACH(cursor,list) \ + for ((cursor) = (list)->next; (cursor) != (list); (cursor) = (cursor)->next) + +/* macros for statically initialized lists */ +#define LIST_INIT(list) { &(list), &(list) } + +/* get pointer to object containing list element */ +#define LIST_ENTRY(elem, type, field) \ + ((type *)((char *)(elem) - (unsigned int)(&((type *)0)->field))) + +#endif /* __WINE_SERVER_LIST_H */ diff --git a/server/main.c b/server/main.c index e2484f1b27a..032cb65c811 100644 --- a/server/main.c +++ b/server/main.c @@ -36,6 +36,9 @@ int debug_level = 0; int master_socket_timeout = 3; /* master socket timeout in seconds, default is 3 s */ const char *server_argv0; +/* name space for synchronization objects */ +struct namespace *sync_namespace; + /* parse-line args */ /* FIXME: should probably use getopt, and add a (more complete?) help option */ @@ -118,6 +121,7 @@ int main( int argc, char *argv[] ) signal_init(); sock_init(); open_master_socket(); + sync_namespace = create_namespace( 37, TRUE ); setvbuf( stderr, NULL, _IOLBF, 0 ); if (debug_level) fprintf( stderr, "wineserver: starting (pid=%ld)\n", (long) getpid() ); diff --git a/server/mapping.c b/server/mapping.c index d9e79c6156a..190e4aee0be 100644 --- a/server/mapping.c +++ b/server/mapping.c @@ -263,7 +263,7 @@ static struct object *create_mapping( int size_high, int size_low, int protect, if (!page_mask) init_page_size(); - if (!(mapping = create_named_object( &mapping_ops, name, len ))) + if (!(mapping = create_named_object( sync_namespace, &mapping_ops, name, len ))) return NULL; if (get_error() == STATUS_OBJECT_NAME_COLLISION) return &mapping->obj; /* Nothing else to do */ @@ -383,7 +383,7 @@ DECL_HANDLER(create_mapping) /* open a handle to a mapping */ DECL_HANDLER(open_mapping) { - reply->handle = open_object( get_req_data(), get_req_data_size(), + reply->handle = open_object( sync_namespace, get_req_data(), get_req_data_size(), &mapping_ops, req->access, req->inherit ); } diff --git a/server/mutex.c b/server/mutex.c index 28e838b54a9..f38fd8db332 100644 --- a/server/mutex.c +++ b/server/mutex.c @@ -68,7 +68,7 @@ static struct mutex *create_mutex( const WCHAR *name, size_t len, int owned ) { struct mutex *mutex; - if ((mutex = create_named_object( &mutex_ops, name, len ))) + if ((mutex = create_named_object( sync_namespace, &mutex_ops, name, len ))) { if (get_error() != STATUS_OBJECT_NAME_COLLISION) { @@ -169,7 +169,7 @@ DECL_HANDLER(create_mutex) /* open a handle to a mutex */ DECL_HANDLER(open_mutex) { - reply->handle = open_object( get_req_data(), get_req_data_size(), + reply->handle = open_object( sync_namespace, get_req_data(), get_req_data_size(), &mutex_ops, req->access, req->inherit ); } diff --git a/server/named_pipe.c b/server/named_pipe.c index a24465179f1..fab8188d9b1 100644 --- a/server/named_pipe.c +++ b/server/named_pipe.c @@ -222,7 +222,7 @@ static struct named_pipe *create_named_pipe( const WCHAR *name, size_t len ) { struct named_pipe *pipe; - if ((pipe = create_named_object( &named_pipe_ops, name, len ))) + if ((pipe = create_named_object( sync_namespace, &named_pipe_ops, name, len ))) { if (get_error() != STATUS_OBJECT_NAME_COLLISION) { diff --git a/server/object.c b/server/object.c index 2539e216103..600c04039d9 100644 --- a/server/object.c +++ b/server/object.c @@ -30,32 +30,37 @@ #include "thread.h" #include "unicode.h" +#include "list.h" struct object_name { - struct object_name *next; - struct object_name *prev; + struct list entry; /* entry in the hash list */ struct object *obj; size_t len; WCHAR name[1]; }; -#define NAME_HASH_SIZE 37 +struct namespace +{ + unsigned int hash_size; /* size of hash table */ + int case_sensitive; /* are names case sensitive? */ + struct list names[1]; /* array of hash entry lists */ +}; -static struct object_name *names[NAME_HASH_SIZE]; #ifdef DEBUG_OBJECTS -static struct object *first; +static struct list object_list = LIST_INIT(object_list); void dump_objects(void) { - struct object *ptr = first; - while (ptr) + struct list *p; + + LIST_FOR_EACH( p, &object_list ) { + struct object *ptr = LIST_ENTRY( p, struct object, obj_list ); fprintf( stderr, "%p:%d: ", ptr, ptr->refcount ); ptr->ops->dump( ptr, 1 ); - ptr = ptr->next; } } #endif @@ -83,12 +88,13 @@ void *memdup( const void *data, size_t len ) /*****************************************************************/ -static int get_name_hash( const WCHAR *name, size_t len ) +static int get_name_hash( const struct namespace *namespace, const WCHAR *name, size_t len ) { WCHAR hash = 0; len /= sizeof(WCHAR); - while (len--) hash ^= *name++; - return hash % NAME_HASH_SIZE; + if (namespace->case_sensitive) while (len--) hash ^= *name++; + else while (len--) hash ^= tolowerW(*name++); + return hash % namespace->hash_size; } /* allocate a name for an object */ @@ -108,31 +114,18 @@ static struct object_name *alloc_name( const WCHAR *name, size_t len ) static void free_name( struct object *obj ) { struct object_name *ptr = obj->name; - if (ptr->next) ptr->next->prev = ptr->prev; - if (ptr->prev) ptr->prev->next = ptr->next; - else - { - int hash; - for (hash = 0; hash < NAME_HASH_SIZE; hash++) - if (names[hash] == ptr) - { - names[hash] = ptr->next; - break; - } - } + list_remove( &ptr->entry ); free( ptr ); } /* set the name of an existing object */ -static void set_object_name( struct object *obj, struct object_name *ptr ) +static void set_object_name( struct namespace *namespace, + struct object *obj, struct object_name *ptr ) { - int hash = get_name_hash( ptr->name, ptr->len ); + int hash = get_name_hash( namespace, ptr->name, ptr->len ); - if ((ptr->next = names[hash]) != NULL) ptr->next->prev = ptr; + list_add_head( &namespace->names[hash], &ptr->entry ); ptr->obj = obj; - ptr->prev = NULL; - names[hash] = ptr; - assert( !obj->name ); obj->name = ptr; } @@ -157,9 +150,7 @@ void *alloc_object( const struct object_ops *ops, int fd ) return NULL; } #ifdef DEBUG_OBJECTS - obj->prev = NULL; - if ((obj->next = first) != NULL) obj->next->prev = obj; - first = obj; + list_add_head( &object_list, &obj->obj_list ); #endif return obj; } @@ -167,17 +158,16 @@ void *alloc_object( const struct object_ops *ops, int fd ) return NULL; } -void *create_named_object( const struct object_ops *ops, const WCHAR *name, size_t len ) +void *create_named_object( struct namespace *namespace, const struct object_ops *ops, + const WCHAR *name, size_t len ) { struct object *obj; struct object_name *name_ptr; if (!name || !len) return alloc_object( ops, -1 ); - if (!(name_ptr = alloc_name( name, len ))) return NULL; - if ((obj = find_object( name_ptr->name, name_ptr->len ))) + if ((obj = find_object( namespace, name, len ))) { - free( name_ptr ); /* we no longer need it */ if (obj->ops == ops) { set_error( STATUS_OBJECT_NAME_COLLISION ); @@ -186,9 +176,10 @@ void *create_named_object( const struct object_ops *ops, const WCHAR *name, size set_error( STATUS_OBJECT_TYPE_MISMATCH ); return NULL; } + if (!(name_ptr = alloc_name( name, len ))) return NULL; if ((obj = alloc_object( ops, -1 ))) { - set_object_name( obj, name_ptr ); + set_object_name( namespace, obj, name_ptr ); clear_error(); } else free( name_ptr ); @@ -231,9 +222,7 @@ void release_object( void *ptr ) if (obj->select != -1) remove_select_user( obj ); if (obj->fd != -1) close( obj->fd ); #ifdef DEBUG_OBJECTS - if (obj->next) obj->next->prev = obj->prev; - if (obj->prev) obj->prev->next = obj->next; - else first = obj->next; + list_remove( &obj->obj_list ); memset( obj, 0xaa, obj->ops->size ); #endif free( obj ); @@ -241,19 +230,50 @@ void release_object( void *ptr ) } /* find an object by its name; the refcount is incremented */ -struct object *find_object( const WCHAR *name, size_t len ) +struct object *find_object( const struct namespace *namespace, const WCHAR *name, size_t len ) { - struct object_name *ptr; + const struct list *list, *p; if (!name || !len) return NULL; - for (ptr = names[ get_name_hash( name, len ) ]; ptr; ptr = ptr->next) + + list = &namespace->names[ get_name_hash( namespace, name, len ) ]; + if (namespace->case_sensitive) { - if (ptr->len != len) continue; - if (!memcmp( ptr->name, name, len )) return grab_object( ptr->obj ); + LIST_FOR_EACH( p, list ) + { + struct object_name *ptr = LIST_ENTRY( p, struct object_name, entry ); + if (ptr->len != len) continue; + if (!memcmp( ptr->name, name, len )) return grab_object( ptr->obj ); + } + } + else + { + LIST_FOR_EACH( p, list ) + { + struct object_name *ptr = LIST_ENTRY( p, struct object_name, entry ); + if (ptr->len != len) continue; + if (!strncmpiW( ptr->name, name, len/sizeof(WCHAR) )) return grab_object( ptr->obj ); + } } return NULL; } +/* allocate a namespace */ +struct namespace *create_namespace( unsigned int hash_size, int case_sensitive ) +{ + struct namespace *namespace; + unsigned int i; + + namespace = mem_alloc( sizeof(*namespace) + (hash_size - 1) * sizeof(namespace->names[0]) ); + if (namespace) + { + namespace->hash_size = hash_size; + namespace->case_sensitive = case_sensitive; + for (i = 0; i < hash_size; i++) list_init( &namespace->names[i] ); + } + return namespace; +} + /* functions for unimplemented/default object operations */ int no_add_queue( struct object *obj, struct wait_queue_entry *entry ) diff --git a/server/object.h b/server/object.h index b1bd53fd32f..d2f57bc3c09 100644 --- a/server/object.h +++ b/server/object.h @@ -24,11 +24,13 @@ #include #include #include "wine/server_protocol.h" +#include "list.h" #define DEBUG_OBJECTS /* kernel objects */ +struct namespace; struct object; struct object_name; struct thread; @@ -79,8 +81,7 @@ struct object struct wait_queue_entry *tail; struct object_name *name; #ifdef DEBUG_OBJECTS - struct object *prev; - struct object *next; + struct list obj_list; #endif }; @@ -96,12 +97,14 @@ extern void *mem_alloc( size_t size ); /* malloc wrapper */ extern void *memdup( const void *data, size_t len ); extern void *alloc_object( const struct object_ops *ops, int fd ); extern void dump_object_name( struct object *obj ); -extern void *create_named_object( const struct object_ops *ops, const WCHAR *name, size_t len ); +extern void *create_named_object( struct namespace *namespace, const struct object_ops *ops, + const WCHAR *name, size_t len ); +extern struct namespace *create_namespace( unsigned int hash_size, int case_sensitive ); /* grab/release_object can take any pointer, but you better make sure */ /* that the thing pointed to starts with a struct object... */ extern struct object *grab_object( void *obj ); extern void release_object( void *obj ); -extern struct object *find_object( const WCHAR *name, size_t len ); +extern struct object *find_object( const struct namespace *namespace, const WCHAR *name, size_t len ); extern int no_add_queue( struct object *obj, struct wait_queue_entry *entry ); extern int no_satisfied( struct object *obj, struct thread *thread ); extern int no_get_fd( struct object *obj ); @@ -209,4 +212,7 @@ extern const char *server_argv0; /* server start time used for GetTickCount() */ extern unsigned int server_start_ticks; +/* name space for synchronization objects */ +extern struct namespace *sync_namespace; + #endif /* __WINE_SERVER_OBJECT_H */ diff --git a/server/process.h b/server/process.h index 2362b6007b1..e89764e37f0 100644 --- a/server/process.h +++ b/server/process.h @@ -25,6 +25,7 @@ struct msg_queue; struct atom_table; +struct handle_table; struct startup_info; /* process startup state */ @@ -54,7 +55,7 @@ struct process struct process *parent; /* parent process */ struct thread *thread_list; /* head of the thread list */ struct thread *debugger; /* thread debugging this process */ - struct object *handles; /* handle entries */ + struct handle_table *handles; /* handle entries */ int exit_code; /* process exit code */ int running_threads; /* number of threads running in this process */ struct timeval start_time; /* absolute time at process start */ diff --git a/server/semaphore.c b/server/semaphore.c index bd1579ae3c7..4e7e6b6aa0d 100644 --- a/server/semaphore.c +++ b/server/semaphore.c @@ -70,7 +70,7 @@ static struct semaphore *create_semaphore( const WCHAR *name, size_t len, set_error( STATUS_INVALID_PARAMETER ); return NULL; } - if ((sem = create_named_object( &semaphore_ops, name, len ))) + if ((sem = create_named_object( sync_namespace, &semaphore_ops, name, len ))) { if (get_error() != STATUS_OBJECT_NAME_COLLISION) { @@ -153,7 +153,7 @@ DECL_HANDLER(create_semaphore) /* open a handle to a semaphore */ DECL_HANDLER(open_semaphore) { - reply->handle = open_object( get_req_data(), get_req_data_size(), + reply->handle = open_object( sync_namespace, get_req_data(), get_req_data_size(), &semaphore_ops, req->access, req->inherit ); } diff --git a/server/timer.c b/server/timer.c index 523a7974956..8b7eb8fdf02 100644 --- a/server/timer.c +++ b/server/timer.c @@ -72,7 +72,7 @@ static struct timer *create_timer( const WCHAR *name, size_t len, int manual ) { struct timer *timer; - if ((timer = create_named_object( &timer_ops, name, len ))) + if ((timer = create_named_object( sync_namespace, &timer_ops, name, len ))) { if (get_error() != STATUS_OBJECT_NAME_COLLISION) { @@ -211,7 +211,7 @@ DECL_HANDLER(create_timer) /* open a handle to a timer */ DECL_HANDLER(open_timer) { - reply->handle = open_object( get_req_data(), get_req_data_size(), + reply->handle = open_object( sync_namespace, get_req_data(), get_req_data_size(), &timer_ops, req->access, req->inherit ); }