From eb2e77fd6f779cda59c1ef82786bbfde9b962676 Mon Sep 17 00:00:00 2001
From: Alexandre Julliard <julliard@winehq.org>
Date: Fri, 4 Jun 1999 19:49:54 +0000
Subject: [PATCH] Made handle table a separate object. Global handle table is
 no longer bound to a process. Removed special handling of the initial
 process.

---
 server/handle.c  | 278 +++++++++++++++++++++++++++++------------------
 server/handle.h  |   5 +-
 server/process.c | 114 ++++++++++---------
 server/process.h |   6 +-
 server/thread.c  |  26 ++---
 5 files changed, 252 insertions(+), 177 deletions(-)

diff --git a/server/handle.c b/server/handle.c
index 996d1d14c2f..bb6b64e10ac 100644
--- a/server/handle.c
+++ b/server/handle.c
@@ -23,7 +23,17 @@ struct handle_entry
     unsigned int   access;
 };
 
-static struct process *initial_process;
+struct handle_table
+{
+    struct object        obj;         /* object header */
+    struct process      *process;     /* process owning this table */
+    int                  count;       /* number of allocated entries */
+    int                  last;        /* last used entry */
+    int                  free;        /* first entry that may be free */
+    struct handle_entry *entries;     /* handle entries */
+};
+
+static struct handle_table *global_table;
 
 /* reserved handle access rights */
 #define RESERVED_SHIFT         25
@@ -39,67 +49,169 @@ static struct process *initial_process;
 
 #define MIN_HANDLE_ENTRIES  32
 
+
+static void handle_table_dump( struct object *obj, int verbose );
+static void handle_table_destroy( struct object *obj );
+
+static const struct object_ops handle_table_ops =
+{
+    handle_table_dump,
+    no_add_queue,
+    NULL,  /* should never get called */
+    NULL,  /* should never get called */
+    NULL,  /* should never get called */
+    no_read_fd,
+    no_write_fd,
+    no_flush,
+    no_get_file_info,
+    handle_table_destroy
+};
+
+/* dump a handle table */
+static void handle_table_dump( struct object *obj, int verbose )
+{
+    int i;
+    struct handle_table *table = (struct handle_table *)obj;
+    struct handle_entry *entry = table->entries;
+
+    assert( obj->ops == &handle_table_ops );
+
+    fprintf( stderr, "Handle table last=%d count=%d process=%p\n",
+             table->last, table->count, table->process );
+    if (!verbose) return;
+    entry = table->entries;
+    for (i = 0; i <= table->last; i++, entry++)
+    {
+        if (!entry->ptr) continue;
+        fprintf( stderr, "%9d: %p %08x ", i + 1, entry->ptr, entry->access );
+        entry->ptr->ops->dump( entry->ptr, 0 );
+    }
+}
+
+/* destroy a handle table */
+static void handle_table_destroy( struct object *obj )
+{
+    int i;
+    struct handle_table *table = (struct handle_table *)obj;
+    struct handle_entry *entry = table->entries;
+
+    assert( obj->ops == &handle_table_ops );
+
+    for (i = 0; i <= table->last; i++, entry++)
+    {
+        struct object *obj = entry->ptr;
+        entry->ptr = NULL;
+        if (obj) release_object( obj );
+    }
+    free( table->entries );
+    free( table );
+}
+
+/* allocate a new handle table */
+struct object *alloc_handle_table( struct process *process, int count )
+{
+    struct handle_table *table;
+
+    if (count < MIN_HANDLE_ENTRIES) count = MIN_HANDLE_ENTRIES;
+    if (!(table = alloc_object( sizeof(*table), &handle_table_ops, NULL )))
+        return NULL;
+    table->process = process;
+    table->count   = count;
+    table->last    = -1;
+    table->free    = 0;
+    if ((table->entries = mem_alloc( count * sizeof(*table->entries) ))) return &table->obj;
+    release_object( table );
+    return NULL;
+}
+
 /* grow a handle table */
-/* return 1 if OK, 0 on error */
-static int grow_handle_table( struct process *process )
+static int grow_handle_table( struct handle_table *table )
 {
     struct handle_entry *new_entries;
-    int count = process->handle_count;
+    int count = table->count;
 
     if (count >= INT_MAX / 2) return 0;
     count *= 2;
-    if (!(new_entries = realloc( process->entries, count * sizeof(struct handle_entry) )))
+    if (!(new_entries = realloc( table->entries, count * sizeof(struct handle_entry) )))
     {
         SET_ERROR( ERROR_OUTOFMEMORY );
         return 0;
     }
-    process->handle_count = count;
-    process->entries      = new_entries;
+    table->entries = new_entries;
+    table->count   = count;
     return 1;
 }
 
+/* find the first free entry in the handle table */
+static struct handle_entry *get_free_entry( struct handle_table *table, int *phandle )
+{
+    struct handle_entry *entry = table->entries + table->free;
+    int handle;
+
+    for (handle = table->free; handle <= table->last; handle++, entry++)
+        if (!entry->ptr) goto found;
+    if (handle >= table->count)
+    {
+        if (!grow_handle_table( table )) return NULL;
+        entry = table->entries + handle;  /* the entries may have moved */
+    }
+    table->last = handle;
+ found:
+    table->free = *phandle = handle + 1;  /* avoid handle 0 */
+    return entry;
+}
+
 /* allocate a handle for an object, incrementing its refcount */
 /* return the handle, or -1 on error */
 int alloc_handle( struct process *process, void *obj, unsigned int access, int inherit )
 {
+    struct handle_table *table = (struct handle_table *)process->handles;
     struct handle_entry *entry;
     int handle;
 
+    assert( table );
     assert( !(access & RESERVED_ALL) );
     if (inherit) access |= RESERVED_INHERIT;
 
-    /* find the first free entry */
+    if (!(entry = get_free_entry( table, &handle ))) return -1;
+    entry->ptr    = grab_object( obj );
+    entry->access = access;
+    return handle;
+}
 
-    if (!(entry = process->entries)) return -1;
-    for (handle = 0; handle <= process->handle_last; handle++, entry++)
-        if (!entry->ptr) goto found;
+/* allocate a global handle for an object, incrementing its refcount */
+/* return the handle, or -1 on error */
+static int alloc_global_handle( void *obj, unsigned int access )
+{
+    struct handle_entry *entry;
+    int handle;
 
-    if (handle >= process->handle_count)
+    if (!global_table)
     {
-        if (!grow_handle_table( process )) return -1;
-        entry = process->entries + handle;  /* the table may have moved */
+        if (!(global_table = (struct handle_table *)alloc_handle_table( NULL, 0 ))) return -1;
     }
-    process->handle_last = handle;
-
- found:
+    if (!(entry = get_free_entry( global_table, &handle ))) return -1;
     entry->ptr    = grab_object( obj );
     entry->access = access;
-    return handle + 1;  /* avoid handle 0 */
+    return HANDLE_LOCAL_TO_GLOBAL(handle);
 }
 
 /* return an handle entry, or NULL if the handle is invalid */
 static struct handle_entry *get_handle( struct process *process, int handle )
 {
+    struct handle_table *table = (struct handle_table *)process->handles;
     struct handle_entry *entry;
 
     if (HANDLE_IS_GLOBAL(handle))
     {
         handle = HANDLE_GLOBAL_TO_LOCAL(handle);
-        process = initial_process;
+        table = global_table;
     }
+    if (!table) goto error;
     handle--;  /* handles start at 1 */
-    if ((handle < 0) || (handle > process->handle_last)) goto error;
-    entry = process->entries + handle;
+    if (handle < 0) goto error;
+    if (handle > table->last) goto error;
+    entry = table->entries + handle;
     if (!entry->ptr) goto error;
     return entry;
 
@@ -109,59 +221,45 @@ static struct handle_entry *get_handle( struct process *process, int handle )
 }
 
 /* attempt to shrink a table */
-/* return 1 if OK, 0 on error */
-static int shrink_handle_table( struct process *process )
+static void shrink_handle_table( struct handle_table *table )
 {
+    struct handle_entry *entry = table->entries + table->last;
     struct handle_entry *new_entries;
-    struct handle_entry *entry = process->entries + process->handle_last;
-    int count = process->handle_count;
+    int count = table->count;
 
-    while (process->handle_last >= 0)
+    while (table->last >= 0)
     {
         if (entry->ptr) break;
-        process->handle_last--;
+        table->last--;
         entry--;
     }
-    if (process->handle_last >= count / 4) return 1;  /* no need to shrink */
-    if (count < MIN_HANDLE_ENTRIES * 2) return 1;  /* too small to shrink */
+    if (table->last >= count / 4) return;  /* no need to shrink */
+    if (count < MIN_HANDLE_ENTRIES * 2) return;  /* too small to shrink */
     count /= 2;
-    if (!(new_entries = realloc( process->entries,
-                                 count * sizeof(struct handle_entry) )))
-        return 0;
-    process->handle_count = count;
-    process->entries      = new_entries;
-    return 1;
+    if (!(new_entries = realloc( table->entries, count * sizeof(*new_entries) ))) return;
+    table->count   = count;
+    table->entries = new_entries;
 }
 
 /* copy the handle table of the parent process */
 /* return 1 if OK, 0 on error */
-int copy_handle_table( struct process *process, struct process *parent )
+struct object *copy_handle_table( struct process *process, struct process *parent )
 {
-    struct handle_entry *ptr;
-    int i, count, last;
+    struct handle_table *parent_table = (struct handle_table *)parent->handles;
+    struct handle_table *table;
+    int i;
 
-    if (!parent)  /* first process */
-    {
-        if (!initial_process) initial_process = process;
-        count = MIN_HANDLE_ENTRIES;
-        last  = -1;
-    }
-    else
-    {
-        assert( parent->entries );
-        count = parent->handle_count;
-        last  = parent->handle_last;
-    }
+    assert( parent_table );
+    assert( parent_table->obj.ops == &handle_table_ops );
 
-    if (!(ptr = mem_alloc( count * sizeof(struct handle_entry)))) return 0;
-    process->entries      = ptr;
-    process->handle_count = count;
-    process->handle_last  = last;
+    if (!(table = (struct handle_table *)alloc_handle_table( process, parent_table->count )))
+        return NULL;
 
-    if (last >= 0)
+    if ((table->last = parent_table->last) >= 0)
     {
-        memcpy( ptr, parent->entries, (last + 1) * sizeof(struct handle_entry) );
-        for (i = 0; i <= last; i++, ptr++)
+        struct handle_entry *ptr = table->entries;
+        memcpy( ptr, parent_table->entries, (table->last + 1) * sizeof(struct handle_entry) );
+        for (i = 0; i <= table->last; i++, ptr++)
         {
             if (!ptr->ptr) continue;
             if (ptr->access & RESERVED_INHERIT) grab_object( ptr->ptr );
@@ -169,31 +267,39 @@ int copy_handle_table( struct process *process, struct process *parent )
         }
     }
     /* attempt to shrink the table */
-    shrink_handle_table( process );
-    return 1;
+    shrink_handle_table( table );
+    return &table->obj;
 }
 
 /* close a handle and decrement the refcount of the associated object */
 /* return 1 if OK, 0 on error */
 int close_handle( struct process *process, int handle )
 {
+    struct handle_table *table;
     struct handle_entry *entry;
     struct object *obj;
 
-    if (HANDLE_IS_GLOBAL(handle))
-    {
-        handle = HANDLE_GLOBAL_TO_LOCAL(handle);
-        process = initial_process;
-    }
     if (!(entry = get_handle( process, handle ))) return 0;
     if (entry->access & RESERVED_CLOSE_PROTECT) return 0;  /* FIXME: error code */
     obj = entry->ptr;
     entry->ptr = NULL;
-    if (handle-1 == process->handle_last) shrink_handle_table( process );
+    table = HANDLE_IS_GLOBAL(handle) ? global_table : (struct handle_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 );
     return 1;
 }
 
+/* close all the global handles */
+void close_global_handles(void)
+{
+    if (global_table)
+    {
+        release_object( global_table );
+        global_table = NULL;
+    }
+}
+
 /* retrieve the object corresponding to a handle, incrementing its refcount */
 struct object *get_handle_obj( struct process *process, int handle,
                                unsigned int access, const struct object_ops *ops )
@@ -259,33 +365,15 @@ int duplicate_handle( struct process *src, int src_handle, struct process *dst,
             CLEAR_ERROR();
         }
     }
-    if (options & DUP_HANDLE_MAKE_GLOBAL) dst = initial_process;
     access &= ~RESERVED_ALL;
-    res = alloc_handle( dst, obj, access, inherit );
+    if (options & DUP_HANDLE_MAKE_GLOBAL)
+        res = alloc_global_handle( obj, access );
+    else
+        res = alloc_handle( dst, obj, access, inherit );
     release_object( obj );
-    if ((options & DUP_HANDLE_MAKE_GLOBAL) && (res != -1)) res = HANDLE_LOCAL_TO_GLOBAL(res);
     return res;
 }
 
-/* free the process handle entries */
-void free_handles( struct process *process )
-{
-    struct handle_entry *entry;
-    int handle;
-
-    if (!(entry = process->entries)) return;
-    for (handle = 0; handle <= process->handle_last; handle++, entry++)
-    {
-        struct object *obj = entry->ptr;
-        entry->ptr = NULL;
-        if (obj) release_object( obj );
-    }
-    free( process->entries );
-    process->handle_count = 0;
-    process->handle_last  = -1;
-    process->entries      = NULL;
-}
-
 /* open a new handle to an existing object */
 int open_object( const char *name, const struct object_ops *ops,
                  unsigned int access, int inherit )
@@ -305,22 +393,6 @@ int open_object( const char *name, const struct object_ops *ops,
     return alloc_handle( current->process, obj, access, inherit );
 }
 
-/* dump a handle table on stdout */
-void dump_handles( struct process *process )
-{
-    struct handle_entry *entry;
-    int i;
-
-    if (!process->entries) return;
-    entry = process->entries;
-    for (i = 0; i <= process->handle_last; i++, entry++)
-    {
-        if (!entry->ptr) continue;
-        printf( "%5d: %p %08x ", i + 1, entry->ptr, entry->access );
-        entry->ptr->ops->dump( entry->ptr, 0 );
-    }
-}
-
 /* close a handle */
 DECL_HANDLER(close_handle)
 {
diff --git a/server/handle.h b/server/handle.h
index 827dbc67d28..cd42e874230 100644
--- a/server/handle.h
+++ b/server/handle.h
@@ -27,7 +27,8 @@ extern int duplicate_handle( struct process *src, int src_handle, struct process
                              unsigned int access, int inherit, int options );
 extern int open_object( const char *name, const struct object_ops *ops,
                         unsigned int access, int inherit );
-extern int copy_handle_table( struct process *process, struct process *parent );
-extern void free_handles( struct process *process );
+extern struct object *alloc_handle_table( struct process *process, int count );
+extern struct object *copy_handle_table( struct process *process, struct process *parent );
+extern void close_global_handles(void);
 
 #endif  /* __WINE_SERVER_HANDLE_H */
diff --git a/server/process.c b/server/process.c
index f7617f0734e..125b0897764 100644
--- a/server/process.c
+++ b/server/process.c
@@ -24,8 +24,7 @@
 
 /* process structure */
 
-static struct process initial_process;
-static struct process *first_process = &initial_process;
+static struct process *first_process;
 static int running_processes;
 
 /* process operations */
@@ -49,16 +48,20 @@ static const struct object_ops process_ops =
 };
 
 
-/* initialization of a process structure */
-static void init_process( struct process *process )
+/* create a new process */
+static struct process *create_process( struct process *parent,
+                                       struct new_process_request *req, const char *cmd_line )
 {
-    init_object( &process->obj, &process_ops, NULL );
+    struct process *process;
+
+    if (!(process = alloc_object( sizeof(*process), &process_ops, NULL ))) return NULL;
     process->next            = NULL;
     process->prev            = NULL;
     process->thread_list     = NULL;
     process->debug_next      = NULL;
     process->debug_prev      = NULL;
     process->debugger        = NULL;
+    process->handles         = NULL;
     process->exit_code       = 0x103;  /* STILL_ACTIVE */
     process->running_threads = 0;
     process->priority        = NORMAL_PRIORITY_CLASS;
@@ -68,47 +71,15 @@ static void init_process( struct process *process )
     process->console_out     = NULL;
     process->info            = NULL;
     gettimeofday( &process->start_time, NULL );
-    /* alloc a handle for the process itself */
-    alloc_handle( process, process, PROCESS_ALL_ACCESS, 0 );
-}
 
-/* create the initial process */
-struct process *create_initial_process(void)
-{
-    struct new_process_request *info;
-
-    copy_handle_table( &initial_process, NULL );
-    init_process( &initial_process );
-
-    if (!alloc_console( &initial_process )) return NULL;
-    if (!(info = mem_alloc( sizeof(*info) ))) return NULL;
-    info->start_flags = STARTF_USESTDHANDLES;
-    info->hstdin  = alloc_handle( &initial_process, initial_process.console_in,
-                                  GENERIC_READ | GENERIC_WRITE | SYNCHRONIZE, 1 );
-    info->hstdout = alloc_handle( &initial_process, initial_process.console_out,
-                                  GENERIC_READ | GENERIC_WRITE | SYNCHRONIZE, 1 );
-    info->hstderr = alloc_handle( &initial_process, initial_process.console_out,
-                                  GENERIC_READ | GENERIC_WRITE | SYNCHRONIZE, 1 );
-    info->env_ptr = NULL;
-    initial_process.info = info;
-    grab_object( &initial_process ); /* so that we never free it */
-    return &initial_process;
-
-}
-
-/* create a new process */
-static struct process *create_process( struct new_process_request *req, const char *cmd_line )
-{
-    struct process *process = NULL;
-    struct process *parent = current->process;
+    if (req->inherit_all)
+        process->handles = copy_handle_table( process, parent );
+    else
+        process->handles = alloc_handle_table( process, 0 );
+    if (!process->handles) goto error;
 
-    if (!(process = mem_alloc( sizeof(*process) ))) return NULL;
-    if (!copy_handle_table( process, req->inherit_all ? parent : NULL ))
-    {
-        free( process );
-        return NULL;
-    }
-    init_process( process );
+    /* alloc a handle for the process itself */
+    alloc_handle( process, process, PROCESS_ALL_ACCESS, 0 );
 
     if (!(process->info = mem_alloc( sizeof(*process->info) + strlen(cmd_line) + 1 ))) goto error;
     memcpy( process->info, req, sizeof(*req) );
@@ -138,33 +109,60 @@ static struct process *create_process( struct new_process_request *req, const ch
     /* attach to the debugger if requested */
     if (req->create_flags & DEBUG_PROCESS)
         debugger_attach( process, current );
-    else if (parent->debugger && !(req->create_flags & DEBUG_ONLY_THIS_PROCESS))
+    else if (parent && parent->debugger && !(req->create_flags & DEBUG_ONLY_THIS_PROCESS))
         debugger_attach( process, parent->debugger );
 
-    process->next = first_process;
-    first_process->prev = process;
+    if ((process->next = first_process) != NULL) process->next->prev = process;
     first_process = process;
     return process;
 
  error:
+    free_console( process );
+    if (process->info) free( process->info );
+    if (process->handles) release_object( process->handles );
     release_object( process );
     return NULL;
 }
 
+/* create the initial process */
+struct process *create_initial_process(void)
+{
+    struct process *process;
+    struct new_process_request req;
+
+    req.inherit      = 0;
+    req.inherit_all  = 0;
+    req.create_flags = CREATE_NEW_CONSOLE;
+    req.start_flags  = STARTF_USESTDHANDLES;
+    req.hstdin       = -1;
+    req.hstdout      = -1;
+    req.hstderr      = -1;
+    req.cmd_show     = 0;
+    req.env_ptr      = NULL;
+    if ((process = create_process( NULL, &req, "" )))
+    {
+        process->info->hstdin  = alloc_handle( process, process->console_in,
+                                               GENERIC_READ | GENERIC_WRITE | SYNCHRONIZE, 1 );
+        process->info->hstdout = alloc_handle( process, process->console_out,
+                                               GENERIC_READ | GENERIC_WRITE | SYNCHRONIZE, 1 );
+        process->info->hstderr = alloc_handle( process, process->console_out,
+                                               GENERIC_READ | GENERIC_WRITE | SYNCHRONIZE, 1 );
+        release_object( process );
+    }
+    return process;
+}
+
 /* destroy a process when its refcount is 0 */
 static void process_destroy( struct object *obj )
 {
     struct process *process = (struct process *)obj;
     assert( obj->ops == &process_ops );
-    assert( process != &initial_process );
 
     /* we can't have a thread remaining */
     assert( !process->thread_list );
     if (process->next) process->next->prev = process->prev;
     if (process->prev) process->prev->next = process->next;
     else first_process = process->next;
-    free_console( process );
-    free_handles( process );
     if (process->info) free( process->info );
     if (debug_level) memset( process, 0xbb, sizeof(process) );  /* catch errors */
     free( process );
@@ -176,7 +174,9 @@ static void process_dump( struct object *obj, int verbose )
     struct process *process = (struct process *)obj;
     assert( obj->ops == &process_ops );
 
-    printf( "Process next=%p prev=%p\n", process->next, process->prev );
+    fprintf( stderr, "Process next=%p prev=%p console=%p/%p handles=%p\n",
+             process->next, process->prev, process->console_in, process->console_out,
+             process->handles );
 }
 
 static int process_signaled( struct object *obj, struct thread *thread )
@@ -209,8 +209,15 @@ static void process_killed( struct process *process, int exit_code )
     assert( !process->thread_list );
     process->exit_code = exit_code;
     gettimeofday( &process->end_time, NULL );
+    release_object( process->handles );
+    process->handles = NULL;
+    free_console( process );
     wake_up( &process->obj, 0 );
-    free_handles( process );
+    if (!--running_processes)
+    {
+        /* last process died, close global handles */
+        close_global_handles();
+    }
 }
 
 /* add a thread to a process running threads list */
@@ -237,7 +244,6 @@ void remove_process_thread( struct process *process, struct thread *thread )
     if (!--process->running_threads)
     {
         /* we have removed the last running thread, exit the process */
-        running_processes--;
         process_killed( process, thread->exit_code );
     }
     release_object( thread );
@@ -366,7 +372,7 @@ DECL_HANDLER(new_process)
     char *cmd_line = (char *)data;
 
     CHECK_STRING( "new_process", cmd_line, len );
-    if ((process = create_process( req, cmd_line )))
+    if ((process = create_process( current->process, req, cmd_line )))
     {
         reply.pid    = process;
         reply.handle = alloc_handle( current->process, process,
diff --git a/server/process.h b/server/process.h
index b9b44fc1b13..5dbc1ee5bfe 100644
--- a/server/process.h
+++ b/server/process.h
@@ -15,8 +15,6 @@
 
 /* process structures */
 
-struct handle_entry;
-
 struct process
 {
     struct object        obj;             /* object header */
@@ -26,9 +24,7 @@ struct process
     struct process      *debug_next;      /* per-debugger process list */
     struct process      *debug_prev;
     struct thread       *debugger;        /* thread debugging this process */
-    struct handle_entry *entries;         /* handle entries */
-    int                  handle_last;     /* last valid handle */
-    int                  handle_count;    /* allocated table entries */
+    struct object       *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/thread.c b/server/thread.c
index 28cdefb346a..2e4f9e5af25 100644
--- a/server/thread.c
+++ b/server/thread.c
@@ -74,8 +74,7 @@ static const struct object_ops thread_ops =
     destroy_thread
 };
 
-static struct thread initial_thread;
-static struct thread *first_thread = &initial_thread;
+static struct thread *first_thread;
 
 /* initialization of a thread structure */
 static void init_thread( struct thread *thread, int fd )
@@ -104,12 +103,14 @@ static void init_thread( struct thread *thread, int fd )
 /* create the initial thread and start the main server loop */
 void create_initial_thread( int fd )
 {
-    current = &initial_thread;
-    init_thread( &initial_thread, fd );
-    initial_thread.process = create_initial_process(); 
-    add_process_thread( initial_thread.process, &initial_thread );
-    initial_thread.client = add_client( fd, &initial_thread );
-    grab_object( &initial_thread ); /* so that we never free it */
+    first_thread = mem_alloc( sizeof(*first_thread) );
+    assert( first_thread );
+
+    current = first_thread;
+    init_thread( first_thread, fd );
+    first_thread->process = create_initial_process(); 
+    add_process_thread( first_thread->process, first_thread );
+    first_thread->client = add_client( fd, first_thread );
     select_loop();
 }
 
@@ -131,8 +132,7 @@ static struct thread *create_thread( int fd, void *pid, int suspend, int inherit
 
     if (suspend) thread->suspend++;
 
-    thread->next = first_thread;
-    first_thread->prev = thread;
+    if ((thread->next = first_thread) != NULL) thread->next->prev = thread;
     first_thread = thread;
     add_process_thread( process, thread );
 
@@ -146,7 +146,7 @@ static struct thread *create_thread( int fd, void *pid, int suspend, int inherit
     return thread;
 
  error:
-    if (current) close_handle( current->process, *handle );
+    close_handle( current->process, *handle );
     remove_process_thread( process, thread );
     release_object( thread );
     return NULL;
@@ -174,8 +174,8 @@ static void dump_thread( struct object *obj, int verbose )
     struct thread *thread = (struct thread *)obj;
     assert( obj->ops == &thread_ops );
 
-    fprintf( stderr, "Thread pid=%d teb=%p client=%p\n",
-             thread->unix_pid, thread->teb, thread->client );
+    fprintf( stderr, "Thread pid=%d teb=%p state=%d\n",
+             thread->unix_pid, thread->teb, thread->state );
 }
 
 static int thread_signaled( struct object *obj, struct thread *thread )
-- 
GitLab