Added support for multiple object namespaces, and a bunch functions

for managing linked lists.
This commit is contained in:
Alexandre Julliard 2002-10-02 23:49:30 +00:00
parent c401270d60
commit 526a28de51
13 changed files with 202 additions and 78 deletions

View File

@ -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 );
}

View File

@ -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)

View File

@ -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 */

72
server/list.h Normal file
View File

@ -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 */

View File

@ -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() );

View File

@ -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 );
}

View File

@ -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 );
}

View File

@ -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)
{

View File

@ -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 )

View File

@ -24,11 +24,13 @@
#include <sys/poll.h>
#include <sys/time.h>
#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 */

View File

@ -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 */

View File

@ -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 );
}

View File

@ -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 );
}