Made the server listen for new clients on a Unix socket in

$HOME/.wine. Newly started wine processes now attach to an existing
server if one is running.
This commit is contained in:
Alexandre Julliard 2000-01-25 01:40:27 +00:00 committed by Alexandre Julliard
parent 647876e598
commit 2fe57779fb
20 changed files with 690 additions and 250 deletions

View File

@ -100,7 +100,6 @@ LIBSUBDIRS = \
relay32 \ relay32 \
resources \ resources \
scheduler \ scheduler \
server \
win32 \ win32 \
windows \ windows \
windows/ttydrv windows/ttydrv
@ -112,7 +111,8 @@ X11SUBDIRS = \
EMUSUBDIRS = \ EMUSUBDIRS = \
debugger \ debugger \
miscemu miscemu \
server
PROGSUBDIRS = libtest programs PROGSUBDIRS = libtest programs
@ -213,7 +213,6 @@ LIBOBJS = \
relay32/relay32.o \ relay32/relay32.o \
resources/resources.o \ resources/resources.o \
scheduler/scheduler.o \ scheduler/scheduler.o \
server/server.o \
win32/win32.o \ win32/win32.o \
windows/windows.o \ windows/windows.o \
windows/ttydrv/ttydrv.o windows/ttydrv/ttydrv.o
@ -231,7 +230,7 @@ LIB_TARGET = @LIB_TARGET@
ALT_LINK = @ALT_LINK@ ALT_LINK = @ALT_LINK@
all: Makefile Make.rules $(MAIN_TARGET) all: Makefile Make.rules server $(MAIN_TARGET)
@echo "Wine build complete." @echo "Wine build complete."
LIBLINTS = $(LIBOBJS:.o=.ln) LIBLINTS = $(LIBOBJS:.o=.ln)

View File

@ -121,7 +121,9 @@ struct new_process_request
IN int cmd_show; /* main window show mode */ IN int cmd_show; /* main window show mode */
IN void* env_ptr; /* pointer to environment (FIXME: hack) */ IN void* env_ptr; /* pointer to environment (FIXME: hack) */
OUT void* pid; /* process id */ 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 */ IN char cmdline[1]; /* command line */
}; };
@ -129,7 +131,6 @@ struct new_process_request
/* Create a new thread from the context of the parent */ /* Create a new thread from the context of the parent */
struct new_thread_request 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 suspend; /* new thread should be suspended on creation */
IN int inherit; /* inherit flag */ IN int inherit; /* inherit flag */
OUT void* tid; /* thread id */ OUT void* tid; /* thread id */
@ -137,10 +138,10 @@ struct new_thread_request
}; };
/* Set the server debug level */ /* Signal that we are finished booting on the client side */
struct set_debug_request 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) */ IN void* teb; /* TEB of new thread (in thread address space) */
OUT void* pid; /* process id of the new thread's process */ OUT void* pid; /* process id of the new thread's process */
OUT void* tid; /* thread id of the new thread */ 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_PROCESS,
REQ_NEW_THREAD, REQ_NEW_THREAD,
REQ_SET_DEBUG, REQ_BOOT_DONE,
REQ_INIT_PROCESS, REQ_INIT_PROCESS,
REQ_INIT_PROCESS_DONE, REQ_INIT_PROCESS_DONE,
REQ_INIT_THREAD, 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_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_DebuggerRequest( int op );
extern int CLIENT_InitThread(void); extern int CLIENT_InitThread(void);
#endif /* __WINE_SERVER__ */ #endif /* __WINE_SERVER__ */

View File

@ -121,7 +121,7 @@ typedef struct _TEB
/* scheduler/thread.c */ /* scheduler/thread.c */
extern TEB *THREAD_CreateInitialThread( struct _PDB *pdb, int server_fd ); 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, DWORD stack_size, BOOL alloc_stack16,
LPSECURITY_ATTRIBUTES sa, int *server_handle ); LPSECURITY_ATTRIBUTES sa, int *server_handle );
extern BOOL THREAD_IsWin16( TEB *thdb ); extern BOOL THREAD_IsWin16( TEB *thdb );

View File

@ -67,24 +67,27 @@ BOOL MAIN_MainInit( int *argc, char *argv[] )
/* Parse command line arguments */ /* Parse command line arguments */
MAIN_WineInit( argc, argv ); MAIN_WineInit( argc, argv );
/* Set server debug level */
CLIENT_SetDebug( TRACE_ON(server) );
/* Load the configuration file */ /* Load the configuration file */
if (!PROFILE_LoadWineIni()) return FALSE; 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 */ /* Initialise DOS drives */
if (!DRIVE_Init()) return FALSE; if (!DRIVE_Init()) return FALSE;
/* Initialise DOS directories */ /* Initialise DOS directories */
if (!DIR_Init()) return FALSE; 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 */ /* Initialize event handling */
if (!EVENT_Init()) return FALSE; if (!EVENT_Init()) return FALSE;
@ -94,9 +97,6 @@ BOOL MAIN_MainInit( int *argc, char *argv[] )
/* Initialize IO-port permissions */ /* Initialize IO-port permissions */
IO_port_init(); IO_port_init();
/* registry initialisation */
SHELL_LoadRegistry();
/* Read DOS config.sys */ /* Read DOS config.sys */
if (!DOSCONF_ReadConfig()) return FALSE; if (!DOSCONF_ReadConfig()) return FALSE;

View File

@ -1486,6 +1486,8 @@ void SHELL_LoadRegistry( void )
TRACE("(void)\n"); TRACE("(void)\n");
if (!CLIENT_IsBootThread()) return; /* already loaded */
REGISTRY_Init(); REGISTRY_Init();
SetLoadLevel(0); SetLoadLevel(0);

View File

@ -7,6 +7,7 @@
#include "config.h" #include "config.h"
#include <assert.h> #include <assert.h>
#include <ctype.h>
#include <errno.h> #include <errno.h>
#include <fcntl.h> #include <fcntl.h>
#include <stdio.h> #include <stdio.h>
@ -15,9 +16,11 @@
#ifdef HAVE_SYS_SOCKET_H #ifdef HAVE_SYS_SOCKET_H
# include <sys/socket.h> # include <sys/socket.h>
#endif #endif
#include <sys/un.h>
#ifdef HAVE_SYS_MMAN_H #ifdef HAVE_SYS_MMAN_H
#include <sys/mman.h> #include <sys/mman.h>
#endif #endif
#include <sys/stat.h>
#include <sys/uio.h> #include <sys/uio.h>
#include <unistd.h> #include <unistd.h>
#include <stdarg.h> #include <stdarg.h>
@ -26,12 +29,17 @@
#include "thread.h" #include "thread.h"
#include "server.h" #include "server.h"
#include "winerror.h" #include "winerror.h"
#include "options.h"
#include "xmalloc.h"
/* Some versions of glibc don't define this */ /* Some versions of glibc don't define this */
#ifndef SCM_RIGHTS #ifndef SCM_RIGHTS
#define SCM_RIGHTS 1 #define SCM_RIGHTS 1
#endif #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 */ /* data structure used to pass an fd with sendmsg/recvmsg */
struct cmsg_fd struct cmsg_fd
{ {
@ -41,6 +49,34 @@ struct cmsg_fd
int fd; /* fd to pass */ 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 * 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 * 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 CLIENT_InitServer(void)
{ {
int fd[2]; int delay, fd, size;
char buffer[16]; const char *env_fd;
extern void create_initial_thread( int fd ); char hostname[64];
char *oldcwd, *serverdir;
const char *configdir;
if (socketpair( AF_UNIX, SOCK_STREAM, 0, fd ) == -1) /* first check if we inherited the socket fd */
if ((env_fd = getenv( "__WINE_FD" )) && isdigit(env_fd[0]))
{ {
perror("socketpair"); fd = atoi( env_fd );
exit(1); if (fcntl( fd, F_GETFL, 0 ) != -1) return fd;
} }
switch(fork())
/* retrieve the current directory */
for (size = 512; ; size *= 2)
{ {
case -1: /* error */ oldcwd = xmalloc( size );
perror("fork"); if (getcwd( oldcwd, size )) break;
exit(1); free( oldcwd );
case 0: /* child */ if (errno == ERANGE) continue;
close( fd[1] ); oldcwd = NULL;
fcntl( fd[0], F_SETFD, 1 ); /* set close on exec flag */
break; 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; if (server_call( REQ_INIT_THREAD )) return -1;
teb->process->server_pid = req->pid; teb->process->server_pid = req->pid;
teb->tid = req->tid; 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; 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(); return (GetCurrentThreadId() == (DWORD)boot_thread_id);
req->level = level;
return server_call( REQ_SET_DEBUG );
} }
/*********************************************************************** /***********************************************************************
@ -346,4 +492,3 @@ int CLIENT_DebuggerRequest( int op )
req->op = op; req->op = op;
return server_call( REQ_DEBUGGER ); return server_call( REQ_DEBUGGER );
} }

View File

@ -5,6 +5,7 @@
*/ */
#include <assert.h> #include <assert.h>
#include <fcntl.h>
#include <stdlib.h> #include <stdlib.h>
#include <string.h> #include <string.h>
#include <unistd.h> #include <unistd.h>
@ -241,13 +242,13 @@ static BOOL PROCESS_CreateEnvDB(void)
/* Allocate the env DB */ /* 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; return FALSE;
pdb->env_db = env_db; pdb->env_db = env_db;
InitializeCriticalSection( &env_db->section ); InitializeCriticalSection( &env_db->section );
/* Allocate and fill the startup info */ /* 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; return FALSE;
env_db->startup_info = startup; env_db->startup_info = startup;
@ -263,11 +264,11 @@ static BOOL PROCESS_CreateEnvDB(void)
/* Copy the parent environment */ /* 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 */ /* 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 FALSE;
return TRUE; return TRUE;
@ -286,7 +287,6 @@ void PROCESS_FreePDB( PDB *pdb )
ENV_FreeEnvironment( pdb ); ENV_FreeEnvironment( pdb );
while (*pptr && (*pptr != pdb)) pptr = &(*pptr)->next; while (*pptr && (*pptr != pdb)) pptr = &(*pptr)->next;
if (*pptr) *pptr = pdb->next; if (*pptr) *pptr = pdb->next;
if (pdb->heap && (pdb->heap != pdb->system_heap)) HeapDestroy( pdb->heap );
HeapFree( SystemHeap, 0, pdb ); HeapFree( SystemHeap, 0, pdb );
} }
@ -306,11 +306,9 @@ static PDB *PROCESS_CreatePDB( PDB *parent, BOOL inherit )
pdb->threads = 1; pdb->threads = 1;
pdb->running_threads = 1; pdb->running_threads = 1;
pdb->ring0_threads = 1; pdb->ring0_threads = 1;
pdb->system_heap = SystemHeap;
pdb->parent = parent; pdb->parent = parent;
pdb->group = pdb; pdb->group = pdb;
pdb->priority = 8; /* Normal */ pdb->priority = 8; /* Normal */
pdb->heap = pdb->system_heap; /* will be changed later on */
pdb->next = PROCESS_First; pdb->next = PROCESS_First;
pdb->winver = 0xffff; /* to be determined */ pdb->winver = 0xffff; /* to be determined */
pdb->main_queue = INVALID_HANDLE_VALUE16; pdb->main_queue = INVALID_HANDLE_VALUE16;
@ -350,9 +348,9 @@ BOOL PROCESS_Init(void)
/* Remember TEB selector of initial process for emergency use */ /* Remember TEB selector of initial process for emergency use */
SYSLEVEL_EmergencyTeb = teb->teb_sel; SYSLEVEL_EmergencyTeb = teb->teb_sel;
/* Create the system heap */ /* Create the system and process heaps */
if (!(SystemHeap = HeapCreate( HEAP_GROWABLE, 0x10000, 0 ))) return FALSE; if (!HEAP_CreateSystemHeap()) return FALSE;
initial_pdb.system_heap = initial_pdb.heap = SystemHeap; initial_pdb.heap = HeapCreate( HEAP_GROWABLE, 0, 0 );
/* Create the idle event for the initial process /* Create the idle event for the initial process
FIXME 1: Shouldn't we call UserSignalProc for the initial process too? FIXME 1: Shouldn't we call UserSignalProc for the initial process too?
@ -406,11 +404,13 @@ void PROCESS_Start(void)
InitializeCriticalSection( &pdb->crit_section ); InitializeCriticalSection( &pdb->crit_section );
/* Create the heap */ /* Create the heap */
if (!(pdb->heap = HeapCreate( HEAP_GROWABLE, if (!(pdb->heap = GetProcessHeap()))
header? header->SizeOfHeapReserve : 0x10000, {
header? header->SizeOfHeapCommit : 0 ))) if (!(pdb->heap = HeapCreate( HEAP_GROWABLE,
goto error; header? header->SizeOfHeapReserve : 0x10000,
pdb->heap_list = pdb->heap; header? header->SizeOfHeapCommit : 0 )))
goto error;
}
/* Create the environment db */ /* Create the environment db */
if (!PROCESS_CreateEnvDB()) goto error; if (!PROCESS_CreateEnvDB()) goto error;
@ -492,7 +492,8 @@ void PROCESS_Start(void)
} }
/* If requested, add entry point breakpoint */ /* If requested, add entry point breakpoint */
if ( Options.debug && TASK_AddTaskEntryBreakpoint ) if ( (Options.debug && TASK_AddTaskEntryBreakpoint) ||
(pdb->flags & PDB32_DEBUGGED))
TASK_AddTaskEntryBreakpoint( pdb->task ); TASK_AddTaskEntryBreakpoint( pdb->task );
/* Call UserSignalProc ( USIG_PROCESS_RUNNING ... ) only for non-GUI win32 apps */ /* Call UserSignalProc ( USIG_PROCESS_RUNNING ... ) only for non-GUI win32 apps */
@ -515,6 +516,7 @@ void PROCESS_Start(void)
case PROC_WIN32: case PROC_WIN32:
TRACE_(relay)( "Starting Win32 process (entryproc=%p)\n", entry ); TRACE_(relay)( "Starting Win32 process (entryproc=%p)\n", entry );
if (pdb->flags & PDB32_DEBUGGED) DebugBreak();
ExitProcess( entry(NULL) ); 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; HANDLE handles[2], load_done_evt = 0;
DWORD exitcode, size; DWORD exitcode, size;
BOOL alloc_stack16; BOOL alloc_stack16;
int server_thandle; int server_thandle, fd = -1;
struct new_process_request *req = get_req_buffer(); struct new_process_request *req = get_req_buffer();
TEB *teb = NULL; TEB *teb = NULL;
PDB *parent = PROCESS_Current(); 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->cmd_show = startup->wShowWindow;
req->env_ptr = (void*)env; /* FIXME: hack */ req->env_ptr = (void*)env; /* FIXME: hack */
lstrcpynA( req->cmdline, cmd_line, server_remaining(req->cmdline) ); 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; pdb->server_pid = req->pid;
info->hProcess = req->handle; info->hProcess = req->phandle;
info->dwProcessId = (DWORD)pdb->server_pid; 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))) ((parent->flags & PDB32_DEBUGGED) && !(flags & DEBUG_ONLY_THIS_PROCESS)))
pdb->flags |= PDB32_DEBUGGED; pdb->flags |= PDB32_DEBUGGED;
@ -600,11 +605,11 @@ PDB *PROCESS_Create( NE_MODULE *pModule, LPCSTR cmd_line, LPCSTR env,
/* Create the main thread */ /* 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; alloc_stack16, tsa, &server_thandle ))) goto error;
info->hThread = server_thandle; teb->tid = (void *)info->dwThreadId;
info->dwThreadId = (DWORD)teb->tid;
teb->startup = PROCESS_Start; teb->startup = PROCESS_Start;
fd = -1; /* don't close it */
/* Pass module to new process (FIXME: hack) */ /* Pass module to new process (FIXME: hack) */
pdb->module = pModule->self; pdb->module = pModule->self;
@ -650,6 +655,7 @@ error:
if (info->hThread != INVALID_HANDLE_VALUE) CloseHandle( info->hThread ); if (info->hThread != INVALID_HANDLE_VALUE) CloseHandle( info->hThread );
if (info->hProcess != INVALID_HANDLE_VALUE) CloseHandle( info->hProcess ); if (info->hProcess != INVALID_HANDLE_VALUE) CloseHandle( info->hProcess );
PROCESS_FreePDB( pdb ); PROCESS_FreePDB( pdb );
if (fd != -1) close( fd );
return NULL; 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) * 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) * SetErrorMode (KERNEL32.486)
*/ */

View File

@ -212,8 +212,8 @@ TEB *THREAD_CreateInitialThread( PDB *pdb, int server_fd )
* allocate in this area and don't support a granularity of 4kb * allocate in this area and don't support a granularity of 4kb
* yet we leave it to VirtualAlloc to choose an address. * yet we leave it to VirtualAlloc to choose an address.
*/ */
TEB *THREAD_Create( PDB *pdb, DWORD flags, DWORD stack_size, BOOL alloc_stack16, TEB *THREAD_Create( PDB *pdb, int fd, DWORD flags, DWORD stack_size, BOOL alloc_stack16,
LPSECURITY_ATTRIBUTES sa, int *server_handle ) LPSECURITY_ATTRIBUTES sa, int *server_handle )
{ {
struct new_thread_request *req = get_req_buffer(); struct new_thread_request *req = get_req_buffer();
HANDLE cleanup_object; 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->tls_ptr = teb->tls_array;
teb->process = pdb; teb->process = pdb;
teb->exit_code = 0x103; /* STILL_ACTIVE */ teb->exit_code = 0x103; /* STILL_ACTIVE */
teb->socket = -1; teb->socket = fd;
/* Allocate the TEB selector (%fs register) */ /* 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 */ /* Create the thread on the server side */
req->pid = teb->process->server_pid; if (teb->socket == -1)
req->suspend = ((flags & CREATE_SUSPENDED) != 0); {
req->inherit = (sa && (sa->nLength>=sizeof(*sa)) && sa->bInheritHandle); req->suspend = ((flags & CREATE_SUSPENDED) != 0);
if (server_call_fd( REQ_NEW_THREAD, -1, &teb->socket )) goto error; req->inherit = (sa && (sa->nLength>=sizeof(*sa)) && sa->bInheritHandle);
teb->tid = req->tid; if (server_call_fd( REQ_NEW_THREAD, -1, &teb->socket )) goto error;
*server_handle = req->handle; teb->tid = req->tid;
fcntl( teb->socket, F_SETFD, 1 ); /* set close on exec flag */ *server_handle = req->handle;
fcntl( teb->socket, F_SETFD, 1 ); /* set close on exec flag */
}
/* Do the rest of the initialization */ /* Do the rest of the initialization */
@ -295,7 +297,7 @@ HANDLE WINAPI CreateThread( SECURITY_ATTRIBUTES *sa, DWORD stack,
DWORD flags, LPDWORD id ) DWORD flags, LPDWORD id )
{ {
int handle = -1; 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; if (!teb) return 0;
teb->flags |= TEBF_WIN32; teb->flags |= TEBF_WIN32;
teb->entry_point = start; teb->entry_point = start;

View File

@ -1,9 +1,9 @@
DEFS = @DLLFLAGS@ -D__WINE__ -D__WINE_SERVER__ DEFS = -D__WINE__ -D__WINE_SERVER__
TOPSRCDIR = @top_srcdir@ TOPSRCDIR = @top_srcdir@
TOPOBJDIR = .. TOPOBJDIR = ..
SRCDIR = @srcdir@ SRCDIR = @srcdir@
VPATH = @srcdir@ VPATH = @srcdir@
MODULE = server MODULE = none
C_SRCS = \ C_SRCS = \
change.c \ change.c \
@ -14,6 +14,7 @@ C_SRCS = \
event.c \ event.c \
file.c \ file.c \
handle.c \ handle.c \
main.c \
mapping.c \ mapping.c \
mutex.c \ mutex.c \
object.c \ object.c \
@ -31,16 +32,13 @@ C_SRCS = \
trace.c \ trace.c \
unicode.c unicode.c
EXTRA_SRCS = main.c
MAIN_OBJS = main.o
PROGRAMS = wineserver PROGRAMS = wineserver
all: $(MODULE).o $(PROGRAMS) all: $(PROGRAMS)
@MAKE_RULES@ @MAKE_RULES@
wineserver: $(OBJS) $(MAIN_OBJS) wineserver: $(OBJS)
$(CC) -o $(PROGRAMS) $(OBJS) $(MAIN_OBJS) $(LIBS) $(CC) -o $(PROGRAMS) $(OBJS) $(LIBS)
### Dependencies: ### Dependencies:

View File

@ -4,39 +4,98 @@
* Copyright (C) 1998 Alexandre Julliard * Copyright (C) 1998 Alexandre Julliard
*/ */
#include <assert.h>
#include <ctype.h> #include <ctype.h>
#include <fcntl.h> #include <fcntl.h>
#include <signal.h>
#include <stdio.h> #include <stdio.h>
#include <stdlib.h> #include <stdlib.h>
#include <sys/time.h>
#include <unistd.h> #include <unistd.h>
#include "object.h" #include "object.h"
#include "thread.h" #include "thread.h"
#include "request.h"
/* 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 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);
}
}
}
static void sigterm_handler()
{
exit(1); /* make sure atexit functions get called */
}
/* 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[] ) int main( int argc, char *argv[] )
{ {
int fd; parse_args( argc, argv );
signal_init();
if (argc != 2) goto error; open_master_socket();
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;
/* debug_level = 1; */
if (debug_level) fprintf( stderr, "Server: starting (pid=%ld)\n", (long) getpid() ); 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() ); if (debug_level) fprintf( stderr, "Server: exiting (pid=%ld)\n", (long) getpid() );
close_registry();
#ifdef DEBUG_OBJECTS #ifdef DEBUG_OBJECTS
close_registry();
dump_objects(); /* dump any remaining objects */ dump_objects(); /* dump any remaining objects */
#endif #endif
exit(0); exit(0);
error:
fprintf( stderr, "%s: must be run from Wine.\n", argv[0] );
exit(1);
} }

View File

@ -15,7 +15,6 @@
#include "thread.h" #include "thread.h"
#include "unicode.h" #include "unicode.h"
int debug_level = 0;
struct object_name struct object_name
{ {

View File

@ -165,6 +165,9 @@ extern int get_page_size(void);
extern void close_registry(void); extern void close_registry(void);
/* global variables (command-line options) */
extern int debug_level; extern int debug_level;
extern int persistent_server;
#endif /* __WINE_SERVER_OBJECT_H */ #endif /* __WINE_SERVER_OBJECT_H */

View File

@ -12,6 +12,7 @@
#include <stdio.h> #include <stdio.h>
#include <stdlib.h> #include <stdlib.h>
#include <sys/time.h> #include <sys/time.h>
#include <sys/socket.h>
#include <unistd.h> #include <unistd.h>
#include "winbase.h" #include "winbase.h"
@ -50,14 +51,89 @@ static const struct object_ops process_ops =
process_destroy /* destroy */ 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 */ /* set the console and stdio handles for a newly created process */
static struct process *create_process( struct process *parent, struct new_process_request *req, static int set_process_console( struct process *process, struct process *parent )
const char *cmd_line, size_t len ) {
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 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->next = NULL;
process->prev = NULL; process->prev = NULL;
process->thread_list = 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->init_event = NULL;
process->info = NULL; process->info = NULL;
gettimeofday( &process->start_time, NULL ); gettimeofday( &process->start_time, NULL );
if ((process->next = first_process) != NULL) process->next->prev = process;
first_process = process;
/* copy the request structure */ /* copy the request structure */
if (!(process->info = mem_alloc( sizeof(*process->info) + len ))) goto error; if (!set_creation_info( process, req, cmd_line, 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 (req->inherit_all) if (process->info->inherit_all)
process->handles = copy_handle_table( process, parent ); process->handles = copy_handle_table( process, parent );
else else
process->handles = alloc_handle_table( process, 0 ); 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 ); alloc_handle( process, process, PROCESS_ALL_ACCESS, 0 );
/* get the init done event */ /* 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 ))) if (!(process->init_event = get_event_obj( parent, process->info->event,
goto error; EVENT_MODIFY_STATE ))) goto error;
} }
/* set the process console */ /* set the process console */
if (process->create_flags & CREATE_NEW_CONSOLE) if (!set_process_console( process, parent )) goto error;
{
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 (!req->inherit_all && !(req->start_flags & STARTF_USESTDHANDLES)) /* create the main thread */
{ if (!(thread = create_thread( fd, process, (process->create_flags & CREATE_SUSPENDED) != 0)))
process->info->hstdin = duplicate_handle( parent, req->hstdin, process, goto error;
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 );
}
/* attach to the debugger if requested */ /* attach to the debugger if requested */
if (process->create_flags & (DEBUG_PROCESS | DEBUG_ONLY_THIS_PROCESS)) 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)) else if (parent && parent->debugger && !(parent->create_flags & DEBUG_ONLY_THIS_PROCESS))
debugger_attach( process, parent->debugger ); debugger_attach( process, parent->debugger );
if ((process->next = first_process) != NULL) process->next->prev = process; release_object( process );
first_process = process; return thread;
return process;
error: error:
close( fd );
free_console( process ); free_console( process );
if (process->handles) release_object( process->handles ); if (process->handles) release_object( process->handles );
release_object( process ); release_object( process );
return NULL; 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 */ /* destroy a process when its refcount is 0 */
static void process_destroy( struct object *obj ) 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 */ /* last process died, close global handles */
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) DECL_HANDLER(new_process)
{ {
size_t len = get_req_strlen( req->cmdline ); size_t len = get_req_strlen( req->cmdline );
struct process *process; struct thread *thread;
int sock[2];
req->handle = -1; req->phandle = -1;
req->pid = NULL; req->thandle = -1;
if ((process = create_process( current->process, req, req->cmdline, len ))) 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 ); file_set_error();
req->pid = process; return;
release_object( process );
} }
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 */ /* initialize a new process */

View File

@ -47,7 +47,9 @@ struct process_snapshot
/* process functions */ /* 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_id( void *id );
extern struct process *get_process_from_handle( int handle, unsigned int access ); extern struct process *get_process_from_handle( int handle, unsigned int access );
extern int process_set_debugger( struct process *process, struct thread *thread ); extern int process_set_debugger( struct process *process, struct thread *thread );

View File

@ -9,22 +9,27 @@
#include <assert.h> #include <assert.h>
#include <errno.h> #include <errno.h>
#include <fcntl.h> #include <fcntl.h>
#include <pwd.h>
#include <signal.h>
#include <stdio.h> #include <stdio.h>
#include <stdlib.h> #include <stdlib.h>
#include <stdarg.h> #include <stdarg.h>
#include <string.h> #include <string.h>
#include <sys/stat.h>
#include <sys/time.h> #include <sys/time.h>
#include <sys/types.h> #include <sys/types.h>
#ifdef HAVE_SYS_SOCKET_H #ifdef HAVE_SYS_SOCKET_H
# include <sys/socket.h> # include <sys/socket.h>
#endif #endif
#include <sys/uio.h> #include <sys/uio.h>
#include <sys/un.h>
#include <unistd.h> #include <unistd.h>
#include "winnt.h" #include "winnt.h"
#include "winbase.h" #include "winbase.h"
#include "wincon.h" #include "wincon.h"
#include "thread.h" #include "thread.h"
#include "process.h"
#include "server.h" #include "server.h"
#define WANT_REQUEST_HANDLERS #define WANT_REQUEST_HANDLERS
#include "request.h" #include "request.h"
@ -34,9 +39,41 @@
#define SCM_RIGHTS 1 #define SCM_RIGHTS 1
#endif #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 */ struct thread *current = NULL; /* thread handling the current request */
static struct master_socket *master_socket; /* the master socket object */
/* socket communication static structures */ /* socket communication static structures */
static struct iovec myiovec; static struct iovec myiovec;
@ -64,6 +101,31 @@ void fatal_protocol_error( struct thread *thread, const char *err, ... )
kill_thread( thread, PROTOCOL_ERROR ); 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 */ /* call a request handler */
static void call_req_handler( struct thread *thread, enum request req, int fd ) 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; return 1;
} }
/* set the debug level */ static void master_socket_dump( struct object *obj, int verbose )
DECL_HANDLER(set_debug)
{ {
debug_level = req->level; struct master_socket *sock = (struct master_socket *)obj;
/* Make sure last_req is initialized */ assert( obj->ops == &master_socket_ops );
current->last_req = REQ_SET_DEBUG; 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 )
{
set_select_events( &master_socket->obj, locked ? 0 : POLLIN );
} }
/* debugger support operations */ /* debugger support operations */

View File

@ -31,6 +31,9 @@ extern int write_request( struct thread *thread );
extern void fatal_protocol_error( struct thread *thread, const char *err, ... ); extern void fatal_protocol_error( struct thread *thread, const char *err, ... );
extern void set_reply_fd( struct thread *thread, int pass_fd ); extern void set_reply_fd( struct thread *thread, int pass_fd );
extern void send_reply( struct thread *thread ); 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_request( enum request req, int fd );
extern void trace_kill( struct thread *thread ); 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_process);
DECL_HANDLER(new_thread); DECL_HANDLER(new_thread);
DECL_HANDLER(set_debug); DECL_HANDLER(boot_done);
DECL_HANDLER(init_process); DECL_HANDLER(init_process);
DECL_HANDLER(init_process_done); DECL_HANDLER(init_process_done);
DECL_HANDLER(init_thread); DECL_HANDLER(init_thread);
@ -168,7 +171,7 @@ static const struct handler {
} req_handlers[REQ_NB_REQUESTS] = { } req_handlers[REQ_NB_REQUESTS] = {
{ (void(*)())req_new_process, sizeof(struct new_process_request) }, { (void(*)())req_new_process, sizeof(struct new_process_request) },
{ (void(*)())req_new_thread, sizeof(struct new_thread_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, sizeof(struct init_process_request) },
{ (void(*)())req_init_process_done, sizeof(struct init_process_done_request) }, { (void(*)())req_init_process_done, sizeof(struct init_process_done_request) },
{ (void(*)())req_init_thread, sizeof(struct init_thread_request) }, { (void(*)())req_init_thread, sizeof(struct init_thread_request) },

View File

@ -210,9 +210,6 @@ void select_loop(void)
sigset_t sigset; sigset_t sigset;
struct sigaction action; struct sigaction action;
setsid();
signal( SIGPIPE, SIG_IGN );
/* block the signals we use */ /* block the signals we use */
sigemptyset( &sigset ); sigemptyset( &sigset );
sigaddset( &sigset, SIGCHLD ); sigaddset( &sigset, SIGCHLD );

View File

@ -87,6 +87,7 @@ static const struct object_ops thread_ops =
}; };
static struct thread *first_thread; static struct thread *first_thread;
static struct thread *booting_thread;
/* allocate the buffer for the communication with the client */ /* allocate the buffer for the communication with the client */
static int alloc_client_buffer( struct thread *thread ) static int alloc_client_buffer( struct thread *thread )
@ -106,7 +107,7 @@ static int alloc_client_buffer( struct thread *thread )
} }
/* create a new 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; struct thread *thread;
int buf_fd; int buf_fd;
@ -135,14 +136,15 @@ static struct thread *create_thread( int fd, struct process *process, int suspen
thread->suspend = (suspend != 0); thread->suspend = (suspend != 0);
thread->buffer = (void *)-1; thread->buffer = (void *)-1;
thread->last_req = REQ_GET_THREAD_BUFFER; 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; booting_thread = thread;
thread->process = process = create_initial_process(); lock_master_socket(1);
assert( process );
} }
else thread->process = (struct process *)grab_object( process );
if ((thread->next = first_thread) != NULL) thread->next->prev = thread; if ((thread->next = first_thread) != NULL) thread->next->prev = thread;
first_thread = thread; first_thread = thread;
@ -161,13 +163,6 @@ static struct thread *create_thread( int fd, struct process *process, int suspen
return NULL; 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 */ /* handle a client event */
void thread_poll_event( struct object *obj, int 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 ); 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 */ /* create a new thread */
DECL_HANDLER(new_thread) DECL_HANDLER(new_thread)
{ {
struct thread *thread; struct thread *thread;
struct process *process;
int sock[2]; int sock[2];
if (!(process = get_process_from_id( req->pid ))) return;
if (socketpair( AF_UNIX, SOCK_STREAM, 0, sock ) != -1) 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; req->tid = thread;
if ((req->handle = alloc_handle( current->process, thread, if ((req->handle = alloc_handle( current->process, thread,
THREAD_ALL_ACCESS, req->inherit )) != -1) THREAD_ALL_ACCESS, req->inherit )) != -1)
{ {
set_reply_fd( current, sock[1] ); set_reply_fd( current, sock[1] );
release_object( process );
/* thread object will be released when the thread gets killed */ /* thread object will be released when the thread gets killed */
return; return;
} }
@ -570,7 +574,6 @@ DECL_HANDLER(new_thread)
close( sock[1] ); close( sock[1] );
} }
else file_set_error(); else file_set_error();
release_object( process );
} }
/* retrieve the thread buffer file descriptor */ /* retrieve the thread buffer file descriptor */
@ -590,8 +593,9 @@ DECL_HANDLER(init_thread)
current->unix_pid = req->unix_pid; current->unix_pid = req->unix_pid;
current->teb = req->teb; current->teb = req->teb;
if (current->suspend + current->process->suspend > 0) stop_thread( current ); if (current->suspend + current->process->suspend > 0) stop_thread( current );
req->pid = current->process; req->pid = current->process;
req->tid = current; req->tid = current;
req->boot = (current == booting_thread);
} }
/* terminate a thread */ /* terminate a thread */

View File

@ -62,7 +62,7 @@ extern struct thread *current;
/* thread functions */ /* 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_id( void *id );
extern struct thread *get_thread_from_handle( int handle, unsigned int access ); extern struct thread *get_thread_from_handle( int handle, unsigned int access );
extern struct thread *get_thread_from_pid( int pid ); extern struct thread *get_thread_from_pid( int pid );

View File

@ -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 ) static void dump_new_process_reply( const struct new_process_request *req )
{ {
fprintf( stderr, " pid=%p,", req->pid ); 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 ) 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, " suspend=%d,", req->suspend );
fprintf( stderr, " inherit=%d", req->inherit ); 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 ); 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 ) 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 ) static void dump_init_thread_reply( const struct init_thread_request *req )
{ {
fprintf( stderr, " pid=%p,", req->pid ); 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 ) 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] = { static const dump_func req_dumpers[REQ_NB_REQUESTS] = {
(dump_func)dump_new_process_request, (dump_func)dump_new_process_request,
(dump_func)dump_new_thread_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_request,
(dump_func)dump_init_process_done_request, (dump_func)dump_init_process_done_request,
(dump_func)dump_init_thread_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] = { static const char * const req_names[REQ_NB_REQUESTS] = {
"new_process", "new_process",
"new_thread", "new_thread",
"set_debug", "boot_done",
"init_process", "init_process",
"init_process_done", "init_process_done",
"init_thread", "init_thread",