diff --git a/Makefile.in b/Makefile.in
index bd2af5e527eb4977b260c4fef6d18287db02ad5b..385f8d61582e7f145bb1351a1760b1eb28e7699a 100644
--- a/Makefile.in
+++ b/Makefile.in
@@ -100,7 +100,6 @@ LIBSUBDIRS = \
 	relay32 \
 	resources \
 	scheduler \
-	server \
 	win32 \
 	windows \
 	windows/ttydrv
@@ -112,7 +111,8 @@ X11SUBDIRS = \
 
 EMUSUBDIRS = \
 	debugger \
-	miscemu
+	miscemu \
+	server
 
 PROGSUBDIRS = libtest programs
 
@@ -213,7 +213,6 @@ LIBOBJS = \
 	relay32/relay32.o \
 	resources/resources.o \
 	scheduler/scheduler.o \
-	server/server.o \
 	win32/win32.o \
 	windows/windows.o \
 	windows/ttydrv/ttydrv.o
@@ -231,7 +230,7 @@ LIB_TARGET  = @LIB_TARGET@
 
 ALT_LINK    = @ALT_LINK@
 
-all: Makefile Make.rules $(MAIN_TARGET)
+all: Makefile Make.rules server $(MAIN_TARGET)
 	@echo "Wine build complete."
 
 LIBLINTS = $(LIBOBJS:.o=.ln) 
diff --git a/include/server.h b/include/server.h
index 96685b0cfd412f3e5fdef294f2d1cb96d6a8a3d3..30d4e9748d3daa7b73f321b04f03fb5b2ed39dc4 100644
--- a/include/server.h
+++ b/include/server.h
@@ -121,7 +121,9 @@ struct new_process_request
     IN  int          cmd_show;     /* main window show mode */
     IN  void*        env_ptr;      /* pointer to environment (FIXME: hack) */
     OUT void*        pid;          /* process id */
-    OUT int          handle;       /* process handle (in the current process) */
+    OUT int          phandle;      /* process handle (in the current process) */
+    OUT void*        tid;          /* thread id */
+    OUT int          thandle;      /* thread handle (in the current process) */
     IN  char         cmdline[1];   /* command line */
 };
 
@@ -129,7 +131,6 @@ struct new_process_request
 /* Create a new thread from the context of the parent */
 struct new_thread_request
 {
-    IN  void*        pid;          /* process id for the new thread */
     IN  int          suspend;      /* new thread should be suspended on creation */ 
     IN  int          inherit;      /* inherit flag */
     OUT void*        tid;          /* thread id */
@@ -137,10 +138,10 @@ struct new_thread_request
 };
 
 
-/* Set the server debug level */
-struct set_debug_request
+/* Signal that we are finished booting on the client side */
+struct boot_done_request
 {
-    IN  int          level;        /* New debug level */
+    IN  int          debug_level;  /* new debug level */
 };
 
 
@@ -171,6 +172,7 @@ struct init_thread_request
     IN  void*        teb;          /* TEB of new thread (in thread address space) */
     OUT void*        pid;          /* process id of the new thread's process */
     OUT void*        tid;          /* thread id of the new thread */
+    OUT int          boot;         /* is this the boot thread? */
 };
 
 
@@ -1036,7 +1038,7 @@ enum request
 {
     REQ_NEW_PROCESS,
     REQ_NEW_THREAD,
-    REQ_SET_DEBUG,
+    REQ_BOOT_DONE,
     REQ_INIT_PROCESS,
     REQ_INIT_PROCESS_DONE,
     REQ_INIT_THREAD,
@@ -1189,7 +1191,8 @@ static inline void server_strcpyAtoW( WCHAR *dst, const char *src )
 }
 
 extern int CLIENT_InitServer(void);
-extern int CLIENT_SetDebug( int level );
+extern int CLIENT_BootDone( int debug_level );
+extern int CLIENT_IsBootThread(void);
 extern int CLIENT_DebuggerRequest( int op );
 extern int CLIENT_InitThread(void);
 #endif  /* __WINE_SERVER__ */
diff --git a/include/thread.h b/include/thread.h
index a9255f5e0976a5d9772ba2cf816efdb6d0939426..a08dc18f8c95724a525f3491c2a5efb4d9531969 100644
--- a/include/thread.h
+++ b/include/thread.h
@@ -121,7 +121,7 @@ typedef struct _TEB
 
 /* scheduler/thread.c */
 extern TEB *THREAD_CreateInitialThread( struct _PDB *pdb, int server_fd );
-extern TEB *THREAD_Create( struct _PDB *pdb, DWORD flags, 
+extern TEB *THREAD_Create( struct _PDB *pdb, int fd, DWORD flags, 
                            DWORD stack_size, BOOL alloc_stack16,
                            LPSECURITY_ATTRIBUTES sa, int *server_handle );
 extern BOOL THREAD_IsWin16( TEB *thdb );
diff --git a/loader/main.c b/loader/main.c
index 9be7476970b79c90de6e2c8bbcd1edcd625028c9..9d6b9adb32770167643cce53ef1d6912bcf61d23 100644
--- a/loader/main.c
+++ b/loader/main.c
@@ -67,24 +67,27 @@ BOOL MAIN_MainInit( int *argc, char *argv[] )
     /* Parse command line arguments */
     MAIN_WineInit( argc, argv );
 
-    /* Set server debug level */
-    CLIENT_SetDebug( TRACE_ON(server) );
-
     /* Load the configuration file */
     if (!PROFILE_LoadWineIni()) return FALSE;
 
-    /* Initialize module loadorder */
-    if (!MODULE_InitLoadOrder()) return FALSE;
-
-      /* Initialize DOS memory */
-    if (!DOSMEM_Init(0)) return FALSE;
-
     /* Initialise DOS drives */
     if (!DRIVE_Init()) return FALSE;
 
     /* Initialise DOS directories */
     if (!DIR_Init()) return FALSE;
 
+    /* Registry initialisation */
+    SHELL_LoadRegistry();
+    
+    /* Global boot finished, the rest is process-local */
+    CLIENT_BootDone( TRACE_ON(server) );
+
+    /* Initialize module loadorder */
+    if (!MODULE_InitLoadOrder()) return FALSE;
+
+    /* Initialize DOS memory */
+    if (!DOSMEM_Init(0)) return FALSE;
+
     /* Initialize event handling */
     if (!EVENT_Init()) return FALSE;
 
@@ -94,9 +97,6 @@ BOOL MAIN_MainInit( int *argc, char *argv[] )
     /* Initialize IO-port permissions */
     IO_port_init();
 
-    /* registry initialisation */
-    SHELL_LoadRegistry();
-    
     /* Read DOS config.sys */
     if (!DOSCONF_ReadConfig()) return FALSE;
 
diff --git a/misc/registry.c b/misc/registry.c
index e6c9b1765150927a80903e15c4f3b2e8a53391be..fbd806cfdb33dca94c2f81be403c8bd4487961a4 100644
--- a/misc/registry.c
+++ b/misc/registry.c
@@ -1486,6 +1486,8 @@ void SHELL_LoadRegistry( void )
 
   TRACE("(void)\n");
 
+  if (!CLIENT_IsBootThread()) return;  /* already loaded */
+
   REGISTRY_Init();
   SetLoadLevel(0);
 
diff --git a/scheduler/client.c b/scheduler/client.c
index 5ccf04f7a794fab1cce45b428730d027395d6cc3..e8dda1996bb0dd9d306b356d9d61dfbeb523c22f 100644
--- a/scheduler/client.c
+++ b/scheduler/client.c
@@ -7,6 +7,7 @@
 #include "config.h"
 
 #include <assert.h>
+#include <ctype.h>
 #include <errno.h>
 #include <fcntl.h>
 #include <stdio.h>
@@ -15,9 +16,11 @@
 #ifdef HAVE_SYS_SOCKET_H
 # include <sys/socket.h>
 #endif
+#include <sys/un.h>
 #ifdef HAVE_SYS_MMAN_H
 #include <sys/mman.h>
 #endif
+#include <sys/stat.h>
 #include <sys/uio.h>
 #include <unistd.h>
 #include <stdarg.h>
@@ -26,12 +29,17 @@
 #include "thread.h"
 #include "server.h"
 #include "winerror.h"
+#include "options.h"
+#include "xmalloc.h"
 
 /* Some versions of glibc don't define this */
 #ifndef SCM_RIGHTS
 #define SCM_RIGHTS 1
 #endif
 
+#define SERVERDIR  "/wineserver-"  /* server socket directory (hostname appended) */
+#define SOCKETNAME "socket"        /* name of the socket file */
+
 /* data structure used to pass an fd with sendmsg/recvmsg */
 struct cmsg_fd
 {
@@ -41,6 +49,34 @@ struct cmsg_fd
     int fd;    /* fd to pass */
 };
 
+static void *boot_thread_id;
+
+
+/* die on a fatal error; use only during initialization */
+static void fatal_error( const char *err, ... )
+{
+    va_list args;
+
+    va_start( args, err );
+    fprintf( stderr, "wine: " );
+    vfprintf( stderr, err, args );
+    va_end( args );
+    exit(1);
+}
+
+/* die on a fatal error; use only during initialization */
+static void fatal_perror( const char *err, ... )
+{
+    va_list args;
+
+    va_start( args, err );
+    fprintf( stderr, "wine: " );
+    vfprintf( stderr, err, args );
+    perror( " " );
+    va_end( args );
+    exit(1);
+}
+
 /***********************************************************************
  *           CLIENT_Die
  *
@@ -257,6 +293,76 @@ unsigned int server_call_fd( enum request req, int fd_out, int *fd_in )
 }
 
 
+/***********************************************************************
+ *           start_server
+ *
+ * Start a new wine server.
+ */
+static void start_server( const char *oldcwd )
+{
+    static int started;  /* we only try once */
+    if (!started)
+    {
+        int pid = fork();
+        if (pid == -1) fatal_perror( "fork" );
+        if (!pid)
+        {
+            execl( BINDIR "/wineserver", "wineserver", NULL );
+            if (oldcwd) chdir( oldcwd );
+            execlp( "wineserver", "wineserver", NULL );
+            execl( "./server/wineserver", "wineserver", NULL );
+            fatal_error( "could not exec wineserver\n" );
+        }
+        started = 1;
+    }
+}
+
+/***********************************************************************
+ *           server_connect
+ *
+ * Attempt to connect to an existing server socket.
+ * We need to be in the server directory already.
+ */
+static int server_connect( const char *oldcwd, const char *serverdir )
+{
+    struct sockaddr_un addr;
+    struct stat st;
+    int s;
+
+    if (chdir( serverdir ) == -1)
+    {
+        if (errno != ENOENT) fatal_perror( "chdir to %s", serverdir );
+        start_server( NULL );
+        return -1;
+    }
+    if (stat( ".", &st ) == -1) fatal_perror( "stat %s", serverdir );
+    if (st.st_uid != getuid()) fatal_error( "'%s' is not owned by you\n", serverdir );
+    if (st.st_mode & 077) fatal_error( "'%s' must not be accessible by other users\n", serverdir );
+
+    if (lstat( SOCKETNAME, &st ) == -1)
+    {
+        if (errno != ENOENT) fatal_perror( "lstat %s/%s", serverdir, SOCKETNAME );
+        start_server( oldcwd );
+        return -1;
+    }
+    if (!S_ISSOCK(st.st_mode))
+        fatal_error( "'%s/%s' is not a socket\n", serverdir, SOCKETNAME );
+    if (st.st_uid != getuid())
+        fatal_error( "'%s/%s' is not owned by you\n", serverdir, SOCKETNAME );
+
+    if ((s = socket( AF_UNIX, SOCK_STREAM, 0 )) == -1) fatal_perror( "socket" );
+    addr.sun_family = AF_UNIX;
+    strcpy( addr.sun_path, SOCKETNAME );
+    if (connect( s, &addr, sizeof(addr.sun_family) + strlen(addr.sun_path) ) == -1)
+    {
+        close( s );
+        return -2;
+    }
+    fcntl( s, F_SETFD, 1 ); /* set close on exec flag */
+    return s;
+}
+
+
 /***********************************************************************
  *           CLIENT_InitServer
  *
@@ -264,34 +370,62 @@ unsigned int server_call_fd( enum request req, int fd_out, int *fd_in )
  */
 int CLIENT_InitServer(void)
 {
-    int fd[2];
-    char buffer[16];
-    extern void create_initial_thread( int fd );
-
-    if (socketpair( AF_UNIX, SOCK_STREAM, 0, fd ) == -1)
+    int delay, fd, size;
+    const char *env_fd;
+    char hostname[64];
+    char *oldcwd, *serverdir;
+    const char *configdir;
+
+    /* first check if we inherited the socket fd */
+    if ((env_fd = getenv( "__WINE_FD" )) && isdigit(env_fd[0]))
     {
-        perror("socketpair");
-        exit(1);
+        fd = atoi( env_fd );
+        if (fcntl( fd, F_GETFL, 0 ) != -1) return fd;
     }
-    switch(fork())
+
+    /* retrieve the current directory */
+    for (size = 512; ; size *= 2)
     {
-    case -1:  /* error */
-        perror("fork");
-        exit(1);
-    case 0:  /* child */
-        close( fd[1] );
-        fcntl( fd[0], F_SETFD, 1 ); /* set close on exec flag */
+        oldcwd = xmalloc( size );
+        if (getcwd( oldcwd, size )) break;
+        free( oldcwd );
+        if (errno == ERANGE) continue;
+        oldcwd = NULL;
         break;
-    default:  /* parent */
-        close( fd[0] );
-        sprintf( buffer, "%d", fd[1] );
-        execl( BINDIR "/wineserver", "wineserver", buffer, NULL );
-        execlp( "wineserver", "wineserver", buffer, NULL );
-        execl( "./server/wineserver", "wineserver", buffer, NULL );
-        create_initial_thread( fd[1] );
-        exit(0);
     }
-    return fd[0];
+
+    /* get the server directory name */
+    if (gethostname( hostname, sizeof(hostname) ) == -1) fatal_perror( "gethostname" );
+    configdir = PROFILE_GetConfigDir();
+    serverdir = xmalloc( strlen(configdir) + strlen(SERVERDIR) + strlen(hostname) + 1 );
+    strcpy( serverdir, configdir );
+    strcat( serverdir, SERVERDIR );
+    strcat( serverdir, hostname );
+
+    /* try to connect, leaving some time for the server to start up */
+    for (delay = 10000; delay < 500000; delay += delay / 2)
+    {
+        if ((fd = server_connect( oldcwd, serverdir )) >= 0) goto done;
+        usleep( delay );
+    }
+
+    if (fd == -2)
+    {
+        fatal_error( "'%s/%s' exists,\n"
+                     "   but I cannot connect to it; maybe the server has crashed?\n"
+                     "   If this is the case, you should remove the socket file and try again.\n",
+                     serverdir, SOCKETNAME );
+    }
+    fatal_error( "could not start wineserver, giving up\n" );
+
+ done:
+    /* switch back to the starting directory */
+    if (oldcwd)
+    {
+        chdir( oldcwd );
+        free( oldcwd );
+    }
+    return fd;
 }
 
 
@@ -319,20 +453,32 @@ int CLIENT_InitThread(void)
     if (server_call( REQ_INIT_THREAD )) return -1;
     teb->process->server_pid = req->pid;
     teb->tid = req->tid;
+    if (req->boot) boot_thread_id = req->tid;
+    else if (boot_thread_id == req->tid) boot_thread_id = 0;
     return 0;
 }
 
+/***********************************************************************
+ *           CLIENT_BootDone
+ *
+ * Signal that we have finished booting, and set debug level.
+ */
+int CLIENT_BootDone( int debug_level )
+{
+    struct boot_done_request *req = get_req_buffer();
+    req->debug_level = debug_level;
+    return server_call( REQ_BOOT_DONE );
+}
+
 
 /***********************************************************************
- *           CLIENT_SetDebug
+ *           CLIENT_IsBootThread
  *
- * Send a set debug level request. Return 0 if OK.
+ * Return TRUE if current thread is the boot thread.
  */
-int CLIENT_SetDebug( int level )
+int CLIENT_IsBootThread(void)
 {
-    struct set_debug_request *req = get_req_buffer();
-    req->level = level;
-    return server_call( REQ_SET_DEBUG );
+    return (GetCurrentThreadId() == (DWORD)boot_thread_id);
 }
 
 /***********************************************************************
@@ -346,4 +492,3 @@ int CLIENT_DebuggerRequest( int op )
     req->op = op;
     return server_call( REQ_DEBUGGER );
 }
-
diff --git a/scheduler/process.c b/scheduler/process.c
index d9ff8fd1291ea01ea9def97f863265f55829a0f7..89671aa1fd3ef708a8dc96a4344ab9a7108723d5 100644
--- a/scheduler/process.c
+++ b/scheduler/process.c
@@ -5,6 +5,7 @@
  */
 
 #include <assert.h>
+#include <fcntl.h>
 #include <stdlib.h>
 #include <string.h>
 #include <unistd.h>
@@ -241,13 +242,13 @@ static BOOL PROCESS_CreateEnvDB(void)
 
     /* Allocate the env DB */
 
-    if (!(env_db = HeapAlloc( pdb->heap, HEAP_ZERO_MEMORY, sizeof(ENVDB) )))
+    if (!(env_db = HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(ENVDB) )))
         return FALSE;
     pdb->env_db = env_db;
     InitializeCriticalSection( &env_db->section );
 
     /* Allocate and fill the startup info */
-    if (!(startup = HeapAlloc( pdb->heap, HEAP_ZERO_MEMORY, sizeof(STARTUPINFOA) )))
+    if (!(startup = HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(STARTUPINFOA) )))
         return FALSE;
     env_db->startup_info = startup;
 
@@ -263,11 +264,11 @@ static BOOL PROCESS_CreateEnvDB(void)
 
     /* Copy the parent environment */
 
-    if (!ENV_InheritEnvironment( pdb, req->env_ptr )) return FALSE;
+    if (!ENV_InheritEnvironment( req->env_ptr )) return FALSE;
 
     /* Copy the command line */
 
-    if (!(pdb->env_db->cmd_line = HEAP_strdupA( pdb->heap, 0, cmd_line )))
+    if (!(pdb->env_db->cmd_line = HEAP_strdupA( GetProcessHeap(), 0, cmd_line )))
         return FALSE;
 
     return TRUE;
@@ -286,7 +287,6 @@ void PROCESS_FreePDB( PDB *pdb )
     ENV_FreeEnvironment( pdb );
     while (*pptr && (*pptr != pdb)) pptr = &(*pptr)->next;
     if (*pptr) *pptr = pdb->next;
-    if (pdb->heap && (pdb->heap != pdb->system_heap)) HeapDestroy( pdb->heap );
     HeapFree( SystemHeap, 0, pdb );
 }
 
@@ -306,11 +306,9 @@ static PDB *PROCESS_CreatePDB( PDB *parent, BOOL inherit )
     pdb->threads         = 1;
     pdb->running_threads = 1;
     pdb->ring0_threads   = 1;
-    pdb->system_heap     = SystemHeap;
     pdb->parent          = parent;
     pdb->group           = pdb;
     pdb->priority        = 8;  /* Normal */
-    pdb->heap            = pdb->system_heap;  /* will be changed later on */
     pdb->next            = PROCESS_First;
     pdb->winver          = 0xffff; /* to be determined */
     pdb->main_queue      = INVALID_HANDLE_VALUE16;
@@ -350,9 +348,9 @@ BOOL PROCESS_Init(void)
     /* Remember TEB selector of initial process for emergency use */
     SYSLEVEL_EmergencyTeb = teb->teb_sel;
 
-    /* Create the system heap */
-    if (!(SystemHeap = HeapCreate( HEAP_GROWABLE, 0x10000, 0 ))) return FALSE;
-    initial_pdb.system_heap = initial_pdb.heap = SystemHeap;
+    /* Create the system and process heaps */
+    if (!HEAP_CreateSystemHeap()) return FALSE;
+    initial_pdb.heap = HeapCreate( HEAP_GROWABLE, 0, 0 );
 
     /* Create the idle event for the initial process
        FIXME 1: Shouldn't we call UserSignalProc for the initial process too?
@@ -406,11 +404,13 @@ void PROCESS_Start(void)
     InitializeCriticalSection( &pdb->crit_section );
 
     /* Create the heap */
-    if (!(pdb->heap = HeapCreate( HEAP_GROWABLE, 
-                                  header? header->SizeOfHeapReserve : 0x10000,
-                                  header? header->SizeOfHeapCommit  : 0 ))) 
-        goto error;
-    pdb->heap_list = pdb->heap;
+    if (!(pdb->heap = GetProcessHeap()))
+    {
+        if (!(pdb->heap = HeapCreate( HEAP_GROWABLE, 
+                                      header? header->SizeOfHeapReserve : 0x10000,
+                                      header? header->SizeOfHeapCommit  : 0 ))) 
+            goto error;
+    }
 
     /* Create the environment db */
     if (!PROCESS_CreateEnvDB()) goto error;
@@ -492,7 +492,8 @@ void PROCESS_Start(void)
     }
 
     /* If requested, add entry point breakpoint */
-    if ( Options.debug && TASK_AddTaskEntryBreakpoint )
+    if ( (Options.debug && TASK_AddTaskEntryBreakpoint) ||
+         (pdb->flags & PDB32_DEBUGGED))
         TASK_AddTaskEntryBreakpoint( pdb->task );
 
     /* Call UserSignalProc ( USIG_PROCESS_RUNNING ... ) only for non-GUI win32 apps */
@@ -515,6 +516,7 @@ void PROCESS_Start(void)
 
     case PROC_WIN32:
         TRACE_(relay)( "Starting Win32 process (entryproc=%p)\n", entry );
+        if (pdb->flags & PDB32_DEBUGGED) DebugBreak();
         ExitProcess( entry(NULL) );
     }
 
@@ -536,7 +538,7 @@ PDB *PROCESS_Create( NE_MODULE *pModule, LPCSTR cmd_line, LPCSTR env,
     HANDLE handles[2], load_done_evt = 0;
     DWORD exitcode, size;
     BOOL alloc_stack16;
-    int server_thandle;
+    int server_thandle, fd = -1;
     struct new_process_request *req = get_req_buffer();
     TEB *teb = NULL;
     PDB *parent = PROCESS_Current();
@@ -568,12 +570,15 @@ PDB *PROCESS_Create( NE_MODULE *pModule, LPCSTR cmd_line, LPCSTR env,
     req->cmd_show = startup->wShowWindow;
     req->env_ptr = (void*)env;  /* FIXME: hack */
     lstrcpynA( req->cmdline, cmd_line, server_remaining(req->cmdline) );
-    if (server_call( REQ_NEW_PROCESS )) goto error;
+    if (server_call_fd( REQ_NEW_PROCESS, -1, &fd )) goto error;
+    fcntl( fd, F_SETFD, 1 ); /* set close on exec flag */
     pdb->server_pid   = req->pid;
-    info->hProcess    = req->handle;
-    info->dwProcessId = (DWORD)pdb->server_pid;
+    info->hProcess    = req->phandle;
+    info->dwProcessId = (DWORD)req->pid;
+    info->hThread     = req->thandle;
+    info->dwThreadId  = (DWORD)req->tid;
 
-    if ((flags & DEBUG_PROCESS) ||
+    if ((flags & (DEBUG_PROCESS|DEBUG_ONLY_THIS_PROCESS)) ||
         ((parent->flags & PDB32_DEBUGGED) && !(flags & DEBUG_ONLY_THIS_PROCESS)))
         pdb->flags |= PDB32_DEBUGGED;
 
@@ -600,11 +605,11 @@ PDB *PROCESS_Create( NE_MODULE *pModule, LPCSTR cmd_line, LPCSTR env,
 
     /* Create the main thread */
 
-    if (!(teb = THREAD_Create( pdb, flags & CREATE_SUSPENDED, size,
+    if (!(teb = THREAD_Create( pdb, fd, flags & CREATE_SUSPENDED, size,
                                alloc_stack16, tsa, &server_thandle ))) goto error;
-    info->hThread     = server_thandle;
-    info->dwThreadId  = (DWORD)teb->tid;
+    teb->tid = (void *)info->dwThreadId;
     teb->startup = PROCESS_Start;
+    fd = -1;  /* don't close it */
 
     /* Pass module to new process (FIXME: hack) */
     pdb->module = pModule->self;
@@ -650,6 +655,7 @@ error:
     if (info->hThread != INVALID_HANDLE_VALUE) CloseHandle( info->hThread );
     if (info->hProcess != INVALID_HANDLE_VALUE) CloseHandle( info->hProcess );
     PROCESS_FreePDB( pdb );
+    if (fd != -1) close( fd );
     return NULL;
 }
 
@@ -852,16 +858,6 @@ DWORD WINAPI GetCurrentProcessId(void)
 }
 
 
-/***********************************************************************
- *           GetProcessHeap    (KERNEL32.259)
- */
-HANDLE WINAPI GetProcessHeap(void)
-{
-    PDB *pdb = PROCESS_Current();
-    return pdb->heap ? pdb->heap : SystemHeap;
-}
-
-
 /***********************************************************************
  *           GetThreadLocale    (KERNEL32.295)
  */
@@ -1236,22 +1232,6 @@ BOOL WINAPI GetExitCodeProcess(
 }
 
 
-/***********************************************************************
- * GetProcessHeaps [KERNEL32.376]
- */
-DWORD WINAPI GetProcessHeaps(DWORD nrofheaps,HANDLE *heaps) {
-	FIXME_(win32)("(%ld,%p), incomplete implementation.\n",nrofheaps,heaps);
-
-	if (nrofheaps) {
-		heaps[0] = GetProcessHeap();
-		/* ... probably SystemHeap too ? */
-		return 1;
-	}
-	/* number of available heaps */
-	return 1;
-}
-
-
 /***********************************************************************
  *           SetErrorMode   (KERNEL32.486)
  */
diff --git a/scheduler/thread.c b/scheduler/thread.c
index 4038a8a92aa2af10654280d4602c7a898497e506..247d4b580e873110278907643450e4b43526c4bf 100644
--- a/scheduler/thread.c
+++ b/scheduler/thread.c
@@ -212,8 +212,8 @@ TEB *THREAD_CreateInitialThread( PDB *pdb, int server_fd )
  *	allocate in this area and don't support a granularity of 4kb
  *	yet we leave it to VirtualAlloc to choose an address.
  */
-TEB *THREAD_Create( PDB *pdb, DWORD flags, DWORD stack_size, BOOL alloc_stack16,
-                     LPSECURITY_ATTRIBUTES sa, int *server_handle )
+TEB *THREAD_Create( PDB *pdb, int fd, DWORD flags, DWORD stack_size, BOOL alloc_stack16,
+                    LPSECURITY_ATTRIBUTES sa, int *server_handle )
 {
     struct new_thread_request *req = get_req_buffer();
     HANDLE cleanup_object;
@@ -227,7 +227,7 @@ TEB *THREAD_Create( PDB *pdb, DWORD flags, DWORD stack_size, BOOL alloc_stack16,
     teb->tls_ptr     = teb->tls_array;
     teb->process     = pdb;
     teb->exit_code   = 0x103; /* STILL_ACTIVE */
-    teb->socket      = -1;
+    teb->socket      = fd;
 
     /* Allocate the TEB selector (%fs register) */
 
@@ -237,13 +237,15 @@ TEB *THREAD_Create( PDB *pdb, DWORD flags, DWORD stack_size, BOOL alloc_stack16,
 
     /* Create the thread on the server side */
 
-    req->pid     = teb->process->server_pid;
-    req->suspend = ((flags & CREATE_SUSPENDED) != 0);
-    req->inherit = (sa && (sa->nLength>=sizeof(*sa)) && sa->bInheritHandle);
-    if (server_call_fd( REQ_NEW_THREAD, -1, &teb->socket )) goto error;
-    teb->tid = req->tid;
-    *server_handle = req->handle;
-    fcntl( teb->socket, F_SETFD, 1 ); /* set close on exec flag */
+    if (teb->socket == -1)
+    {
+        req->suspend = ((flags & CREATE_SUSPENDED) != 0);
+        req->inherit = (sa && (sa->nLength>=sizeof(*sa)) && sa->bInheritHandle);
+        if (server_call_fd( REQ_NEW_THREAD, -1, &teb->socket )) goto error;
+        teb->tid = req->tid;
+        *server_handle = req->handle;
+        fcntl( teb->socket, F_SETFD, 1 ); /* set close on exec flag */
+    }
 
     /* Do the rest of the initialization */
 
@@ -295,7 +297,7 @@ HANDLE WINAPI CreateThread( SECURITY_ATTRIBUTES *sa, DWORD stack,
                             DWORD flags, LPDWORD id )
 {
     int handle = -1;
-    TEB *teb = THREAD_Create( PROCESS_Current(), flags, stack, TRUE, sa, &handle );
+    TEB *teb = THREAD_Create( PROCESS_Current(), -1, flags, stack, TRUE, sa, &handle );
     if (!teb) return 0;
     teb->flags      |= TEBF_WIN32;
     teb->entry_point = start;
diff --git a/server/Makefile.in b/server/Makefile.in
index e2bad9f3a6235c696085d4658397a71830a79e13..e849135d37397b3a299933952059c734ab7f43c8 100644
--- a/server/Makefile.in
+++ b/server/Makefile.in
@@ -1,9 +1,9 @@
-DEFS      = @DLLFLAGS@ -D__WINE__ -D__WINE_SERVER__
+DEFS      = -D__WINE__ -D__WINE_SERVER__
 TOPSRCDIR = @top_srcdir@
 TOPOBJDIR = ..
 SRCDIR    = @srcdir@
 VPATH     = @srcdir@
-MODULE    = server
+MODULE    = none
 
 C_SRCS = \
 	change.c \
@@ -14,6 +14,7 @@ C_SRCS = \
 	event.c \
 	file.c \
 	handle.c \
+	main.c \
 	mapping.c \
 	mutex.c \
 	object.c \
@@ -31,16 +32,13 @@ C_SRCS = \
 	trace.c \
 	unicode.c
 
-EXTRA_SRCS = main.c
-MAIN_OBJS = main.o
-
 PROGRAMS = wineserver
 
-all: $(MODULE).o $(PROGRAMS)
+all: $(PROGRAMS)
 
 @MAKE_RULES@
 
-wineserver: $(OBJS) $(MAIN_OBJS)
-	$(CC) -o $(PROGRAMS) $(OBJS) $(MAIN_OBJS) $(LIBS)
+wineserver: $(OBJS)
+	$(CC) -o $(PROGRAMS) $(OBJS) $(LIBS)
 
 ### Dependencies:
diff --git a/server/main.c b/server/main.c
index 51490ce63e7e38392a0d097c3427adbbfe857b2b..7ec67d712d434e08f007ef2255d34d2174d6e08d 100644
--- a/server/main.c
+++ b/server/main.c
@@ -4,39 +4,98 @@
  * Copyright (C) 1998 Alexandre Julliard
  */
 
+#include <assert.h>
 #include <ctype.h>
 #include <fcntl.h>
+#include <signal.h>
 #include <stdio.h>
 #include <stdlib.h>
+#include <sys/time.h>
 #include <unistd.h>
 
 #include "object.h"
 #include "thread.h"
+#include "request.h"
 
-int main( int argc, char *argv[] )
+/* command-line options */
+int debug_level = 0;
+int persistent_server = 0;
+
+/* parse-line args */
+/* FIXME: should probably use getopt, and add a help option */
+static void parse_args( int argc, char *argv[] )
 {
-    int fd;
+    int i;
+    for (i = 1; i < argc; i++)
+    {
+        if (argv[i][0] == '-')
+        {
+            switch(argv[i][1])
+            {
+            case 'd':
+                if (isdigit(argv[i][2])) debug_level = atoi( argv[i] + 2 );
+                else debug_level++;
+                break;
+            case 'p':
+                persistent_server = 1;
+                break;
+            default:
+                fprintf( stderr, "Unknown option '%s'\n", argv[i] );
+                exit(1);
+            }
+        }
+        else
+        {
+            fprintf( stderr, "Unknown argument '%s'\n", argv[i] );
+            exit(1);
+        }
+    }
+}
 
-    if (argc != 2) goto error;
-    if (!isdigit( *argv[1] )) goto error;
-    fd = atoi( argv[1] );
-    /* make sure the fd is valid */
-    if (fcntl( fd, F_GETFL, 0 ) == -1) goto error;
+static void sigterm_handler()
+{
+    exit(1);  /* make sure atexit functions get called */
+}
 
-/*    debug_level = 1; */
+/* initialize signal handling */
+static void signal_init(void)
+{
+#if 0
+    if (!debug_level)
+    {
+        switch(fork())
+        {
+        case -1:
+            break;
+        case 0:
+            setsid();
+            break;
+        default:
+            exit(0);
+        }
+    }
+#endif
+    signal( SIGPIPE, SIG_IGN );
+    signal( SIGHUP, sigterm_handler );
+    signal( SIGINT, sigterm_handler );
+    signal( SIGQUIT, sigterm_handler );
+    signal( SIGTERM, sigterm_handler );
+    signal( SIGABRT, sigterm_handler );
+}
+
+int main( int argc, char *argv[] )
+{
+    parse_args( argc, argv );
+    signal_init();
+    open_master_socket();
 
     if (debug_level) fprintf( stderr, "Server: starting (pid=%ld)\n", (long) getpid() );
-    create_initial_thread( fd );
+    select_loop();
     if (debug_level) fprintf( stderr, "Server: exiting (pid=%ld)\n", (long) getpid() );
 
-    close_registry();
 #ifdef DEBUG_OBJECTS
+    close_registry();
     dump_objects();  /* dump any remaining objects */
 #endif
-
     exit(0);
-
- error:    
-    fprintf( stderr, "%s: must be run from Wine.\n", argv[0] );
-    exit(1);
 }
diff --git a/server/object.c b/server/object.c
index 71e9451f51d77fb576c6b1cd90db87c7d97296b3..4ade00630237b9aa50377ea870523c22d043facc 100644
--- a/server/object.c
+++ b/server/object.c
@@ -15,7 +15,6 @@
 #include "thread.h"
 #include "unicode.h"
 
-int debug_level = 0;
 
 struct object_name
 {
diff --git a/server/object.h b/server/object.h
index fb874f7db42d0f9246e67535a75e75e0951ada0a..5ab85a1d3e0eae726c0dec6d1ddaa8cc385663f0 100644
--- a/server/object.h
+++ b/server/object.h
@@ -165,6 +165,9 @@ extern int get_page_size(void);
 
 extern void close_registry(void);
 
+/* global variables (command-line options) */
+
 extern int debug_level;
+extern int persistent_server;
 
 #endif  /* __WINE_SERVER_OBJECT_H */
diff --git a/server/process.c b/server/process.c
index b2a53e451621920e57bbc3bcc5cf2dc7e0c794fb..b2743e12033cf05d398d503ceb53aab167baeb36 100644
--- a/server/process.c
+++ b/server/process.c
@@ -12,6 +12,7 @@
 #include <stdio.h>
 #include <stdlib.h>
 #include <sys/time.h>
+#include <sys/socket.h>
 #include <unistd.h>
 
 #include "winbase.h"
@@ -50,14 +51,89 @@ static const struct object_ops process_ops =
     process_destroy              /* destroy */
 };
 
+/* set the process creation info */
+static int set_creation_info( struct process *process, struct new_process_request *req,
+                              const char *cmd_line, size_t len )
+{
+    if (!(process->info = mem_alloc( sizeof(*process->info) + len ))) return 0;
+    if (req)
+    {
+        /* copy the request structure */
+        memcpy( process->info, req, sizeof(*req) );
+    }
+    else  /* no request, use defaults */
+    {
+        req = process->info;
+        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->event        = -1;
+        req->cmd_show     = 0;
+        req->env_ptr      = NULL;
+    }
+    memcpy( process->info->cmdline, cmd_line, len );
+    process->info->cmdline[len] = 0;
+    process->create_flags = process->info->create_flags;
+    return 1;
+}
 
-/* create a new process */
-static struct process *create_process( struct process *parent, struct new_process_request *req,
-                                       const char *cmd_line, size_t len )
+/* set the console and stdio handles for a newly created process */
+static int set_process_console( struct process *process, struct process *parent )
+{
+    struct new_process_request *info = process->info;
+
+    if (process->create_flags & CREATE_NEW_CONSOLE)
+    {
+        if (!alloc_console( process )) return 0;
+    }
+    else if (!(process->create_flags & DETACHED_PROCESS))
+    {
+        if (parent->console_in) process->console_in = grab_object( parent->console_in );
+        if (parent->console_out) process->console_out = grab_object( parent->console_out );
+    }
+    if (parent)
+    {
+        if (!info->inherit_all && !(info->start_flags & STARTF_USESTDHANDLES))
+        {
+            /* duplicate the handle from the parent into this process */
+            info->hstdin  = duplicate_handle( parent, info->hstdin, process,
+                                              0, TRUE, DUPLICATE_SAME_ACCESS );
+            info->hstdout = duplicate_handle( parent, info->hstdout, process,
+                                              0, TRUE, DUPLICATE_SAME_ACCESS );
+            info->hstderr = duplicate_handle( parent, info->hstderr, process,
+                                              0, TRUE, DUPLICATE_SAME_ACCESS );
+        }
+    }
+    else
+    {
+        /* no parent, use handles to the console for stdio */
+        info->hstdin  = alloc_handle( process, process->console_in,
+                                      GENERIC_READ | GENERIC_WRITE | SYNCHRONIZE, 1 );
+        info->hstdout = alloc_handle( process, process->console_out,
+                                      GENERIC_READ | GENERIC_WRITE | SYNCHRONIZE, 1 );
+        info->hstderr = alloc_handle( process, process->console_out,
+                                      GENERIC_READ | GENERIC_WRITE | SYNCHRONIZE, 1 );
+    }
+    return 1;
+}
+
+/* create a new process and its main thread */
+struct thread *create_process( int fd, struct process *parent,
+                               struct new_process_request *req,
+                               const char *cmd_line, size_t len )
 {
     struct process *process;
+    struct thread *thread = NULL;
 
-    if (!(process = alloc_object( &process_ops, -1 ))) return NULL;
+    if (!(process = alloc_object( &process_ops, -1 )))
+    {
+        close( fd );
+        return NULL;
+    }
     process->next            = NULL;
     process->prev            = NULL;
     process->thread_list     = NULL;
@@ -74,16 +150,13 @@ static struct process *create_process( struct process *parent, struct new_proces
     process->init_event      = NULL;
     process->info            = NULL;
     gettimeofday( &process->start_time, NULL );
+    if ((process->next = first_process) != NULL) process->next->prev = process;
+    first_process = process;
 
     /* copy the request structure */
-    if (!(process->info = mem_alloc( sizeof(*process->info) + len ))) goto error;
-    memcpy( process->info, req, sizeof(*req) );
-    memcpy( process->info->cmdline, cmd_line, len );
-    process->info->cmdline[len] = 0;
-    req = process->info;  /* use the copy now */
-    process->create_flags = req->create_flags;
+    if (!set_creation_info( process, req, cmd_line, len )) goto error;
 
-    if (req->inherit_all)
+    if (process->info->inherit_all)
         process->handles = copy_handle_table( process, parent );
     else
         process->handles = alloc_handle_table( process, 0 );
@@ -93,32 +166,18 @@ static struct process *create_process( struct process *parent, struct new_proces
     alloc_handle( process, process, PROCESS_ALL_ACCESS, 0 );
 
     /* get the init done event */
-    if (req->event != -1)
+    if (process->info->event != -1)
     {
-        if (!(process->init_event = get_event_obj( parent, req->event, EVENT_MODIFY_STATE )))
-            goto error;
+        if (!(process->init_event = get_event_obj( parent, process->info->event,
+                                                   EVENT_MODIFY_STATE ))) goto error;
     }
 
     /* set the process console */
-    if (process->create_flags & CREATE_NEW_CONSOLE)
-    {
-        if (!alloc_console( process )) goto error;
-    }
-    else if (!(process->create_flags & DETACHED_PROCESS))
-    {
-        if (parent->console_in) process->console_in = grab_object( parent->console_in );
-        if (parent->console_out) process->console_out = grab_object( parent->console_out );
-    }
+    if (!set_process_console( process, parent )) goto error;
 
-    if (!req->inherit_all && !(req->start_flags & STARTF_USESTDHANDLES))
-    {
-        process->info->hstdin  = duplicate_handle( parent, req->hstdin, process,
-                                                   0, TRUE, DUPLICATE_SAME_ACCESS );
-        process->info->hstdout = duplicate_handle( parent, req->hstdout, process,
-                                                   0, TRUE, DUPLICATE_SAME_ACCESS );
-        process->info->hstderr = duplicate_handle( parent, req->hstderr, process,
-                                                   0, TRUE, DUPLICATE_SAME_ACCESS );
-    }
+    /* create the main thread */
+    if (!(thread = create_thread( fd, process, (process->create_flags & CREATE_SUSPENDED) != 0)))
+        goto error;
 
     /* attach to the debugger if requested */
     if (process->create_flags & (DEBUG_PROCESS | DEBUG_ONLY_THIS_PROCESS))
@@ -126,45 +185,17 @@ static struct process *create_process( struct process *parent, struct new_proces
     else if (parent && parent->debugger && !(parent->create_flags & DEBUG_ONLY_THIS_PROCESS))
         debugger_attach( process, parent->debugger );
 
-    if ((process->next = first_process) != NULL) process->next->prev = process;
-    first_process = process;
-    return process;
+    release_object( process );
+    return thread;
 
  error:
+    close( fd );
     free_console( process );
     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.event        = -1;
-    req.cmd_show     = 0;
-    req.env_ptr      = NULL;
-    if ((process = create_process( NULL, &req, "", 1 )))
-    {
-        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 );
-    }
-    return process;
-}
-
 /* destroy a process when its refcount is 0 */
 static void process_destroy( struct object *obj )
 {
@@ -229,6 +260,8 @@ static void process_killed( struct process *process, int exit_code )
     {
         /* last process died, close global handles */
         close_global_handles();
+        /* this will cause the select loop to terminate */
+        if (!persistent_server) close_master_socket();
     }
 }
 
@@ -455,16 +488,40 @@ struct process_snapshot *process_snap( int *count )
 DECL_HANDLER(new_process)
 {
     size_t len = get_req_strlen( req->cmdline );
-    struct process *process;
+    struct thread *thread;
+    int sock[2];
 
-    req->handle = -1;
-    req->pid    = NULL;
-    if ((process = create_process( current->process, req, req->cmdline, len )))
+    req->phandle = -1;
+    req->thandle = -1;
+    req->pid     = NULL;
+    req->tid     = NULL;
+
+    if (socketpair( AF_UNIX, SOCK_STREAM, 0, sock ) == -1)
     {
-        req->handle = alloc_handle( current->process, process, PROCESS_ALL_ACCESS, req->inherit );
-        req->pid    = process;
-        release_object( process );
+        file_set_error();
+        return;
+    }
+
+    if ((thread = create_process( sock[0], current->process, req, req->cmdline, len )))
+    {
+        int phandle = alloc_handle( current->process, thread->process,
+                                    PROCESS_ALL_ACCESS, req->inherit );
+        if ((req->phandle = phandle) != -1)
+        {
+            if ((req->thandle = alloc_handle( current->process, thread,
+                                              THREAD_ALL_ACCESS, req->inherit )) != -1)
+            {
+                /* thread object will be released when the thread gets killed */
+                set_reply_fd( current, sock[1] );
+                req->pid = thread->process;
+                req->tid = thread;
+                return;
+            }
+            close_handle( current->process, phandle );
+        }
+        release_object( thread );
     }
+    close( sock[1] );
 }
 
 /* initialize a new process */
diff --git a/server/process.h b/server/process.h
index 305d1c5afe351f9fe631b07f3cf051c8ce0f6947..737de561bc75decf7414096d201f0bdc0e221dad 100644
--- a/server/process.h
+++ b/server/process.h
@@ -47,7 +47,9 @@ struct process_snapshot
 
 /* process functions */
 
-extern struct process *create_initial_process(void);
+extern struct thread *create_process( int fd, struct process *parent,
+                                      struct new_process_request *req,
+                                      const char *cmd_line, size_t len );
 extern struct process *get_process_from_id( void *id );
 extern struct process *get_process_from_handle( int handle, unsigned int access );
 extern int process_set_debugger( struct process *process, struct thread *thread );
diff --git a/server/request.c b/server/request.c
index 945126b17f2d1d28f468951ce1ea82c232f484aa..b7a5161d44ab45ff66521302a807f06f82ab0306 100644
--- a/server/request.c
+++ b/server/request.c
@@ -9,22 +9,27 @@
 #include <assert.h>
 #include <errno.h>
 #include <fcntl.h>
+#include <pwd.h>
+#include <signal.h>
 #include <stdio.h>
 #include <stdlib.h>
 #include <stdarg.h>
 #include <string.h>
+#include <sys/stat.h>
 #include <sys/time.h>
 #include <sys/types.h>
 #ifdef HAVE_SYS_SOCKET_H
 # include <sys/socket.h>
 #endif
 #include <sys/uio.h>
+#include <sys/un.h>
 #include <unistd.h>
 
 #include "winnt.h"
 #include "winbase.h"
 #include "wincon.h"
 #include "thread.h"
+#include "process.h"
 #include "server.h"
 #define WANT_REQUEST_HANDLERS
 #include "request.h"
@@ -34,9 +39,41 @@
 #define SCM_RIGHTS 1
 #endif
 
- 
+ /* path names for server master Unix socket */
+#define CONFDIR    "/.wine"        /* directory for Wine config relative to $HOME */
+#define SERVERDIR  "/wineserver-"  /* server socket directory (hostname appended) */
+#define SOCKETNAME "socket"        /* name of the socket file */
+
+struct master_socket
+{
+    struct object       obj;         /* object header */
+};
+
+static void master_socket_dump( struct object *obj, int verbose );
+static void master_socket_poll_event( struct object *obj, int event );
+static void master_socket_destroy( struct object *obj );
+
+static const struct object_ops master_socket_ops =
+{
+    sizeof(struct master_socket),  /* size */
+    master_socket_dump,            /* dump */
+    no_add_queue,                  /* add_queue */
+    NULL,                          /* remove_queue */
+    NULL,                          /* signaled */
+    NULL,                          /* satisfied */
+    NULL,                          /* get_poll_events */
+    master_socket_poll_event,      /* poll_event */
+    no_read_fd,                    /* get_read_fd */
+    no_write_fd,                   /* get_write_fd */
+    no_flush,                      /* flush */
+    no_get_file_info,              /* get_file_info */
+    master_socket_destroy          /* destroy */
+};
+
+
 struct thread *current = NULL;  /* thread handling the current request */
 
+static struct master_socket *master_socket;  /* the master socket object */
 
 /* socket communication static structures */
 static struct iovec myiovec;
@@ -64,6 +101,31 @@ void fatal_protocol_error( struct thread *thread, const char *err, ... )
     kill_thread( thread, PROTOCOL_ERROR );
 }
 
+/* die on a fatal error */
+static void fatal_error( const char *err, ... )
+{
+    va_list args;
+
+    va_start( args, err );
+    fprintf( stderr, "wineserver: " );
+    vfprintf( stderr, err, args );
+    va_end( args );
+    exit(1);
+}
+
+/* die on a fatal error */
+static void fatal_perror( const char *err, ... )
+{
+    va_list args;
+
+    va_start( args, err );
+    fprintf( stderr, "wineserver: " );
+    vfprintf( stderr, err, args );
+    perror( " " );
+    va_end( args );
+    exit(1);
+}
+
 /* call a request handler */
 static void call_req_handler( struct thread *thread, enum request req, int fd )
 {
@@ -187,12 +249,135 @@ int write_request( struct thread *thread )
     return 1;
 }
 
-/* set the debug level */
-DECL_HANDLER(set_debug)
+static void master_socket_dump( struct object *obj, int verbose )
+{
+    struct master_socket *sock = (struct master_socket *)obj;
+    assert( obj->ops == &master_socket_ops );
+    fprintf( stderr, "Master socket fd=%d\n", sock->obj.fd );
+}
+
+/* handle a socket event */
+static void master_socket_poll_event( struct object *obj, int event )
+{
+    struct master_socket *sock = (struct master_socket *)obj;
+    assert( obj->ops == &master_socket_ops );
+
+    assert( sock == master_socket );  /* there is only one master socket */
+
+    if (event & (POLLERR | POLLHUP))
+    {
+        /* this is not supposed to happen */
+        fprintf( stderr, "wineserver: Error on master socket\n" );
+        release_object( obj );
+    }
+    else if (event & POLLIN)
+    {
+        struct sockaddr_un dummy;
+        int len = sizeof(dummy);
+        int client = accept( master_socket->obj.fd, &dummy, &len );
+        if (client != -1) create_process( client, NULL, NULL, "", 1 );
+    }
+}
+
+/* remove the socket upon exit */
+static void socket_cleanup(void)
+{
+    unlink( SOCKETNAME );
+}
+
+static void master_socket_destroy( struct object *obj )
+{
+    socket_cleanup();
+}
+
+/* return the configuration directory ($HOME/.wine) */
+static const char *get_config_dir(void)
+{
+    static char *confdir;
+    if (!confdir)
+    {
+        const char *home = getenv( "HOME" );
+        if (!home)
+        {
+            struct passwd *pwd = getpwuid( getuid() );
+            if (!pwd) fatal_error( "could not find your home directory\n" );
+            home = pwd->pw_dir;
+        }
+        if (!(confdir = malloc( strlen(home) + strlen(CONFDIR) + 1 )))
+            fatal_error( "out of memory\n" );
+        strcpy( confdir, home );
+        strcat( confdir, CONFDIR );
+        mkdir( confdir, 0755 );  /* just in case */
+    }
+    return confdir;
+}
+
+/* create the server directory and chdir to it */
+static void create_server_dir(void)
+{
+    char hostname[64];
+    char *serverdir;
+    const char *confdir = get_config_dir();
+    struct stat st;
+
+    if (gethostname( hostname, sizeof(hostname) ) == -1) fatal_perror( "gethostname" );
+
+    if (!(serverdir = malloc( strlen(confdir) + strlen(SERVERDIR) + strlen(hostname) + 1 )))
+        fatal_error( "out of memory\n" );
+
+    strcpy( serverdir, confdir );
+    strcat( serverdir, SERVERDIR );
+    strcat( serverdir, hostname );
+
+    if (chdir( serverdir ) == -1)
+    {
+        if (errno != ENOENT) fatal_perror( "chdir %s", serverdir );
+        if (mkdir( serverdir, 0700 ) == -1) fatal_perror( "mkdir %s", serverdir );
+        if (chdir( serverdir ) == -1) fatal_perror( "chdir %s", serverdir );
+    }
+    if (stat( ".", &st ) == -1) fatal_perror( "stat %s", serverdir );
+    if (!S_ISDIR(st.st_mode)) fatal_error( "%s is not a directory\n", serverdir );
+    if (st.st_uid != getuid()) fatal_error( "%s is not owned by you\n", serverdir );
+    if (st.st_mode & 077) fatal_error( "%s must not be accessible by other users\n", serverdir );
+}
+
+/* open the master server socket and start waiting for new clients */
+void open_master_socket(void)
+{
+    struct sockaddr_un addr;
+    int fd;
+
+    create_server_dir();
+    if ((fd = socket( AF_UNIX, SOCK_STREAM, 0 )) == -1) fatal_perror( "socket" );
+    addr.sun_family = AF_UNIX;
+    strcpy( addr.sun_path, "socket" );
+    if (bind( fd, &addr, sizeof(addr.sun_family) + strlen(addr.sun_path) ) == -1)
+    {
+        if ((errno == EEXIST) || (errno == EADDRINUSE))
+            fatal_error( "another server is already running\n" );
+        else
+            fatal_perror( "bind" );
+    }
+    atexit( socket_cleanup );
+
+    chmod( "socket", 0600 );  /* make sure no other user can connect */
+    if (listen( fd, 5 ) == -1) fatal_perror( "listen" );
+
+    if (!(master_socket = alloc_object( &master_socket_ops, fd )))
+        fatal_error( "out of memory\n" );
+    set_select_events( &master_socket->obj, POLLIN );
+}
+
+/* close the master socket and stop waiting for new clients */
+void close_master_socket(void)
+{
+    release_object( master_socket );
+}
+
+/* lock/unlock the master socket to stop accepting new clients */
+void lock_master_socket( int locked )
 {
-    debug_level = req->level;
-    /* Make sure last_req is initialized */
-    current->last_req = REQ_SET_DEBUG;
+    set_select_events( &master_socket->obj, locked ? 0 : POLLIN );
 }
 
 /* debugger support operations */
diff --git a/server/request.h b/server/request.h
index 80ad9aa4fa913e67f118105779bb864e23b8b1ae..c9fcd10ccfb94ad8f7eee6bf1094cde8462c520e 100644
--- a/server/request.h
+++ b/server/request.h
@@ -31,6 +31,9 @@ extern int write_request( struct thread *thread );
 extern void fatal_protocol_error( struct thread *thread, const char *err, ... );
 extern void set_reply_fd( struct thread *thread, int pass_fd );
 extern void send_reply( struct thread *thread );
+extern void open_master_socket(void);
+extern void close_master_socket(void);
+extern void lock_master_socket( int locked );
 
 extern void trace_request( enum request req, int fd );
 extern void trace_kill( struct thread *thread );
@@ -69,7 +72,7 @@ static inline size_t get_req_strlenW( const WCHAR *str )
 
 DECL_HANDLER(new_process);
 DECL_HANDLER(new_thread);
-DECL_HANDLER(set_debug);
+DECL_HANDLER(boot_done);
 DECL_HANDLER(init_process);
 DECL_HANDLER(init_process_done);
 DECL_HANDLER(init_thread);
@@ -168,7 +171,7 @@ static const struct handler {
 } req_handlers[REQ_NB_REQUESTS] = {
     { (void(*)())req_new_process, sizeof(struct new_process_request) },
     { (void(*)())req_new_thread, sizeof(struct new_thread_request) },
-    { (void(*)())req_set_debug, sizeof(struct set_debug_request) },
+    { (void(*)())req_boot_done, sizeof(struct boot_done_request) },
     { (void(*)())req_init_process, sizeof(struct init_process_request) },
     { (void(*)())req_init_process_done, sizeof(struct init_process_done_request) },
     { (void(*)())req_init_thread, sizeof(struct init_thread_request) },
diff --git a/server/select.c b/server/select.c
index 98b4817e982037eff1eb2a69bf48cce76712044e..c46ccd629fc5b26c2b6a501e0b17c2870992cdf9 100644
--- a/server/select.c
+++ b/server/select.c
@@ -210,9 +210,6 @@ void select_loop(void)
     sigset_t sigset;
     struct sigaction action;
 
-    setsid();
-    signal( SIGPIPE, SIG_IGN );
-
     /* block the signals we use */
     sigemptyset( &sigset );
     sigaddset( &sigset, SIGCHLD );
diff --git a/server/thread.c b/server/thread.c
index f1629189c96b6811b04bd0c1af6f1d32269eadf3..d2c5a56e5a3adde90cab6a05056fe71a923f02cc 100644
--- a/server/thread.c
+++ b/server/thread.c
@@ -87,6 +87,7 @@ static const struct object_ops thread_ops =
 };
 
 static struct thread *first_thread;
+static struct thread *booting_thread;
 
 /* allocate the buffer for the communication with the client */
 static int alloc_client_buffer( struct thread *thread )
@@ -106,7 +107,7 @@ static int alloc_client_buffer( struct thread *thread )
 }
 
 /* create a new thread */
-static struct thread *create_thread( int fd, struct process *process, int suspend )
+struct thread *create_thread( int fd, struct process *process, int suspend )
 {
     struct thread *thread;
     int buf_fd;
@@ -135,14 +136,15 @@ static struct thread *create_thread( int fd, struct process *process, int suspen
     thread->suspend     = (suspend != 0);
     thread->buffer      = (void *)-1;
     thread->last_req    = REQ_GET_THREAD_BUFFER;
+    thread->process     = (struct process *)grab_object( process );
 
-    if (!first_thread)  /* creating the first thread */
+    if (!current) current = thread;
+
+    if (!booting_thread)  /* first thread ever */
     {
-        current = thread;
-        thread->process = process = create_initial_process(); 
-        assert( process );
+        booting_thread = thread;
+        lock_master_socket(1);
     }
-    else thread->process = (struct process *)grab_object( process );
 
     if ((thread->next = first_thread) != NULL) thread->next->prev = thread;
     first_thread = thread;
@@ -161,13 +163,6 @@ static struct thread *create_thread( int fd, struct process *process, int suspen
     return NULL;
 }
 
-/* create the initial thread and start the main server loop */
-void create_initial_thread( int fd )
-{
-    create_thread( fd, NULL, 0 );
-    select_loop();
-}
-
 /* handle a client event */
 void thread_poll_event( struct object *obj, int event )
 {
@@ -543,25 +538,34 @@ void kill_thread( struct thread *thread, int exit_code )
     release_object( thread );
 }
 
+/* signal that we are finished booting on the client side */
+DECL_HANDLER(boot_done)
+{
+    debug_level = req->debug_level;
+    /* Make sure last_req is initialized */
+    current->last_req = REQ_BOOT_DONE;
+    if (current == booting_thread)
+    {
+        booting_thread = (struct thread *)~0UL;  /* make sure it doesn't match other threads */
+        lock_master_socket(0);  /* allow other clients now */
+    }
+}
+
 /* create a new thread */
 DECL_HANDLER(new_thread)
 {
     struct thread *thread;
-    struct process *process;
     int sock[2];
 
-    if (!(process = get_process_from_id( req->pid ))) return;
-
     if (socketpair( AF_UNIX, SOCK_STREAM, 0, sock ) != -1)
     {
-        if ((thread = create_thread( sock[0], process, req->suspend )))
+        if ((thread = create_thread( sock[0], current->process, req->suspend )))
         {
             req->tid = thread;
             if ((req->handle = alloc_handle( current->process, thread,
                                              THREAD_ALL_ACCESS, req->inherit )) != -1)
             {
                 set_reply_fd( current, sock[1] );
-                release_object( process );
                 /* thread object will be released when the thread gets killed */
                 return;
             }
@@ -570,7 +574,6 @@ DECL_HANDLER(new_thread)
         close( sock[1] );
     }
     else file_set_error();
-    release_object( process );
 }
 
 /* retrieve the thread buffer file descriptor */
@@ -590,8 +593,9 @@ DECL_HANDLER(init_thread)
     current->unix_pid = req->unix_pid;
     current->teb      = req->teb;
     if (current->suspend + current->process->suspend > 0) stop_thread( current );
-    req->pid = current->process;
-    req->tid = current;
+    req->pid  = current->process;
+    req->tid  = current;
+    req->boot = (current == booting_thread);
 }
 
 /* terminate a thread */
diff --git a/server/thread.h b/server/thread.h
index c19b9d40ff0a59b84ab24a455c9611f63afbd73e..5e464938615c3a6c5b0524cde0817451a6bd554d 100644
--- a/server/thread.h
+++ b/server/thread.h
@@ -62,7 +62,7 @@ extern struct thread *current;
 
 /* thread functions */
 
-extern void create_initial_thread( int fd );
+extern struct thread *create_thread( int fd, struct process *process, int suspend );
 extern struct thread *get_thread_from_id( void *id );
 extern struct thread *get_thread_from_handle( int handle, unsigned int access );
 extern struct thread *get_thread_from_pid( int pid );
diff --git a/server/trace.c b/server/trace.c
index f140afb7ad40060d1a0a75b22d8867fafc584503..89547b50f67e513839cdc7bc038f9b13b46e4f28 100644
--- a/server/trace.c
+++ b/server/trace.c
@@ -215,12 +215,13 @@ static void dump_new_process_request( const struct new_process_request *req )
 static void dump_new_process_reply( const struct new_process_request *req )
 {
     fprintf( stderr, " pid=%p,", req->pid );
-    fprintf( stderr, " handle=%d", req->handle );
+    fprintf( stderr, " phandle=%d,", req->phandle );
+    fprintf( stderr, " tid=%p,", req->tid );
+    fprintf( stderr, " thandle=%d", req->thandle );
 }
 
 static void dump_new_thread_request( const struct new_thread_request *req )
 {
-    fprintf( stderr, " pid=%p,", req->pid );
     fprintf( stderr, " suspend=%d,", req->suspend );
     fprintf( stderr, " inherit=%d", req->inherit );
 }
@@ -231,9 +232,9 @@ static void dump_new_thread_reply( const struct new_thread_request *req )
     fprintf( stderr, " handle=%d", req->handle );
 }
 
-static void dump_set_debug_request( const struct set_debug_request *req )
+static void dump_boot_done_request( const struct boot_done_request *req )
 {
-    fprintf( stderr, " level=%d", req->level );
+    fprintf( stderr, " debug_level=%d", req->debug_level );
 }
 
 static void dump_init_process_request( const struct init_process_request *req )
@@ -265,7 +266,8 @@ static void dump_init_thread_request( const struct init_thread_request *req )
 static void dump_init_thread_reply( const struct init_thread_request *req )
 {
     fprintf( stderr, " pid=%p,", req->pid );
-    fprintf( stderr, " tid=%p", req->tid );
+    fprintf( stderr, " tid=%p,", req->tid );
+    fprintf( stderr, " boot=%d", req->boot );
 }
 
 static void dump_get_thread_buffer_request( const struct get_thread_buffer_request *req )
@@ -1168,7 +1170,7 @@ static void dump_set_thread_context_request( const struct set_thread_context_req
 static const dump_func req_dumpers[REQ_NB_REQUESTS] = {
     (dump_func)dump_new_process_request,
     (dump_func)dump_new_thread_request,
-    (dump_func)dump_set_debug_request,
+    (dump_func)dump_boot_done_request,
     (dump_func)dump_init_process_request,
     (dump_func)dump_init_process_done_request,
     (dump_func)dump_init_thread_request,
@@ -1358,7 +1360,7 @@ static const dump_func reply_dumpers[REQ_NB_REQUESTS] = {
 static const char * const req_names[REQ_NB_REQUESTS] = {
     "new_process",
     "new_thread",
-    "set_debug",
+    "boot_done",
     "init_process",
     "init_process_done",
     "init_thread",