Rewrote Unix process launching to allow passing startup information to

Winelib apps. Improved handling of execve() failures.
This commit is contained in:
Alexandre Julliard 2000-05-01 16:24:22 +00:00
parent 045d81f16c
commit 5b4f3e8d6d
17 changed files with 662 additions and 364 deletions

View File

@ -148,8 +148,9 @@ extern DWORD WINAPI GetProcessDword( DWORD dwProcessID, INT offset );
void WINAPI SetProcessDword( DWORD dwProcessID, INT offset, DWORD value ); void WINAPI SetProcessDword( DWORD dwProcessID, INT offset, DWORD value );
extern DWORD WINAPI MapProcessHandle( HANDLE handle ); extern DWORD WINAPI MapProcessHandle( HANDLE handle );
/* scheduler/environ.c */ /* memory/environ.c */
extern BOOL ENV_InheritEnvironment( LPCSTR env ); extern BOOL ENV_BuildEnvironment(void);
extern BOOL ENV_InheritEnvironment( PDB *pdb, LPCSTR env );
extern void ENV_FreeEnvironment( PDB *pdb ); extern void ENV_FreeEnvironment( PDB *pdb );
/* scheduler/process.c */ /* scheduler/process.c */
@ -161,6 +162,10 @@ extern PDB *PROCESS_Create( struct _NE_MODULE *pModule, HFILE hFile,
LPSECURITY_ATTRIBUTES psa, LPSECURITY_ATTRIBUTES tsa, LPSECURITY_ATTRIBUTES psa, LPSECURITY_ATTRIBUTES tsa,
BOOL inherit, DWORD flags, BOOL inherit, DWORD flags,
STARTUPINFOA *startup, PROCESS_INFORMATION *info ); STARTUPINFOA *startup, PROCESS_INFORMATION *info );
extern BOOL PROCESS_CreateUnixProcess( LPCSTR filename, LPCSTR cmd_line, LPCSTR env,
LPSECURITY_ATTRIBUTES psa, LPSECURITY_ATTRIBUTES tsa,
BOOL inherit, DWORD flags, LPSTARTUPINFOA startup,
LPPROCESS_INFORMATION info );
extern void PROCESS_FreePDB( PDB *pdb ); extern void PROCESS_FreePDB( PDB *pdb );
extern void PROCESS_WalkProcess( void ); extern void PROCESS_WalkProcess( void );

View File

@ -104,8 +104,6 @@ typedef struct
/* Create a new process from the context of the parent */ /* Create a new process from the context of the parent */
struct new_process_request struct new_process_request
{ {
IN int pinherit; /* process handle inherit flag */
IN int tinherit; /* thread handle inherit flag */
IN int inherit_all; /* inherit all handles from parent */ IN int inherit_all; /* inherit all handles from parent */
IN int create_flags; /* creation flags */ IN int create_flags; /* creation flags */
IN int start_flags; /* flags from startup info */ IN int start_flags; /* flags from startup info */
@ -114,13 +112,22 @@ struct new_process_request
IN int hstdout; /* handle for stdout */ IN int hstdout; /* handle for stdout */
IN int hstderr; /* handle for stderr */ IN int hstderr; /* handle for stderr */
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 int alloc_fd; /* create the fd pair right now? */
};
/* Wait for the new process to start */
struct wait_process_request
{
IN int pinherit; /* process handle inherit flag */
IN int tinherit; /* thread handle inherit flag */
IN int timeout; /* wait timeout */
IN int cancel; /* cancel the process creation? */
OUT void* pid; /* process id */ OUT void* pid; /* process id */
OUT int phandle; /* process handle (in the current process) */ OUT int phandle; /* process handle (in the current process) */
OUT void* tid; /* thread id */ OUT void* tid; /* thread id */
OUT int thandle; /* thread handle (in the current process) */ OUT int thandle; /* thread handle (in the current process) */
OUT int event; /* event handle to signal startup */ OUT int event; /* event handle to signal startup */
IN char cmdline[1]; /* command line */
}; };
@ -146,14 +153,13 @@ struct init_process_request
{ {
IN void* ldt_copy; /* addr of LDT copy */ IN void* ldt_copy; /* addr of LDT copy */
IN void* ldt_flags; /* addr of LDT flags */ IN void* ldt_flags; /* addr of LDT flags */
IN int ppid; /* parent Unix pid */
OUT int start_flags; /* flags from startup info */ OUT int start_flags; /* flags from startup info */
OUT int exe_file; /* file handle for main exe */ OUT int exe_file; /* file handle for main exe */
OUT int hstdin; /* handle for stdin */ OUT int hstdin; /* handle for stdin */
OUT int hstdout; /* handle for stdout */ OUT int hstdout; /* handle for stdout */
OUT int hstderr; /* handle for stderr */ OUT int hstderr; /* handle for stderr */
OUT int cmd_show; /* main window show mode */ OUT int cmd_show; /* main window show mode */
OUT void* env_ptr; /* pointer to environment (FIXME: hack) */
OUT char cmdline[1]; /* command line */
}; };
@ -1142,6 +1148,7 @@ struct get_atom_name_request
enum request enum request
{ {
REQ_NEW_PROCESS, REQ_NEW_PROCESS,
REQ_WAIT_PROCESS,
REQ_NEW_THREAD, REQ_NEW_THREAD,
REQ_BOOT_DONE, REQ_BOOT_DONE,
REQ_INIT_PROCESS, REQ_INIT_PROCESS,
@ -1246,7 +1253,7 @@ enum request
REQ_NB_REQUESTS REQ_NB_REQUESTS
}; };
#define SERVER_PROTOCOL_VERSION 9 #define SERVER_PROTOCOL_VERSION 10
/* ### make_requests end ### */ /* ### make_requests end ### */
/* Everything above this line is generated automatically by tools/make_requests */ /* Everything above this line is generated automatically by tools/make_requests */

View File

@ -119,9 +119,8 @@ typedef struct _TEB
/* scheduler/thread.c */ /* scheduler/thread.c */
extern TEB *THREAD_CreateInitialThread( struct _PDB *pdb, int server_fd ); extern TEB *THREAD_Init( struct _PDB *pdb );
extern TEB *THREAD_Create( struct _PDB *pdb, void *pid, void *tid, int fd, extern TEB *THREAD_Create( struct _PDB *pdb, int fd, DWORD stack_size, BOOL alloc_stack16 );
DWORD stack_size, BOOL alloc_stack16 );
extern TEB *THREAD_InitStack( TEB *teb, struct _PDB *pdb, DWORD stack_size, BOOL alloc_stack16 ); extern TEB *THREAD_InitStack( TEB *teb, struct _PDB *pdb, DWORD stack_size, BOOL alloc_stack16 );
extern BOOL THREAD_IsWin16( TEB *thdb ); extern BOOL THREAD_IsWin16( TEB *thdb );
extern TEB *THREAD_IdToTEB( DWORD id ); extern TEB *THREAD_IdToTEB( DWORD id );

View File

@ -62,8 +62,6 @@ DEFAULT_DEBUG_CHANNEL(server);
*/ */
BOOL MAIN_MainInit( int argc, char *argv[], BOOL win32 ) BOOL MAIN_MainInit( int argc, char *argv[], BOOL win32 )
{ {
char szGraphicsDriver[MAX_PATH];
/* store the program name */ /* store the program name */
argv0 = argv[0]; argv0 = argv[0];
@ -94,15 +92,6 @@ BOOL MAIN_MainInit( int argc, char *argv[], BOOL win32 )
/* Initialize module loadorder */ /* Initialize module loadorder */
if (!MODULE_InitLoadOrder()) return FALSE; if (!MODULE_InitLoadOrder()) return FALSE;
/* Initialize KERNEL */
if (!LoadLibraryA( "KERNEL32" )) return FALSE;
if (PROFILE_GetWineIniString( "Wine", "GraphicsDriver",
"x11drv", szGraphicsDriver, sizeof(szGraphicsDriver)))
{
if (!LoadLibraryA( szGraphicsDriver )) return FALSE;
}
return TRUE; return TRUE;
} }

View File

@ -684,60 +684,6 @@ BOOL WINAPI GetBinaryTypeW( LPCWSTR lpApplicationName, LPDWORD lpBinaryType )
return ret; return ret;
} }
/**********************************************************************
* MODULE_CreateUnixProcess
*/
static BOOL MODULE_CreateUnixProcess( LPCSTR filename, LPCSTR lpCmdLine,
LPSTARTUPINFOA lpStartupInfo,
LPPROCESS_INFORMATION lpProcessInfo )
{
const char *argv[256], **argptr;
char *cmdline = NULL;
char *p;
const char *unixfilename = filename;
DOS_FULL_NAME full_name;
/* Build argument list */
argptr = argv;
p = cmdline = strdup(lpCmdLine);
if (strchr(filename, '/') || strchr(filename, ':') || strchr(filename, '\\'))
{
if ( DOSFS_GetFullName( filename, TRUE, &full_name ) )
unixfilename = full_name.long_name;
}
while (1)
{
while (*p && (*p == ' ' || *p == '\t')) *p++ = '\0';
if (!*p) break;
*argptr++ = p;
while (*p && *p != ' ' && *p != '\t') p++;
}
*argptr++ = 0;
/* overwrite program name gotten from tidy_cmd */
argv[0] = unixfilename;
/* Fork and execute */
if ( !fork() )
{
/* Note: don't use Wine routines here, as this process
has not been correctly initialized! */
execvp( argv[0], (char**)argv );
exit( 1 );
}
/* Fake success return value */
memset( lpProcessInfo, '\0', sizeof( *lpProcessInfo ) );
lpProcessInfo->hProcess = INVALID_HANDLE_VALUE;
lpProcessInfo->hThread = INVALID_HANDLE_VALUE;
if (cmdline) free(cmdline);
SetLastError( ERROR_SUCCESS );
return TRUE;
}
/*********************************************************************** /***********************************************************************
* WinExec16 (KERNEL.166) * WinExec16 (KERNEL.166)
@ -1027,7 +973,10 @@ BOOL WINAPI CreateProcessA( LPCSTR lpApplicationName, LPSTR lpCommandLine,
{ {
CloseHandle( hFile ); CloseHandle( hFile );
/* FIXME: Try Unix executable only when appropriate! */ /* FIXME: Try Unix executable only when appropriate! */
retv = MODULE_CreateUnixProcess( name, tidy_cmdline, lpStartupInfo, lpProcessInfo ); retv = PROCESS_CreateUnixProcess( name, tidy_cmdline, lpEnvironment,
lpProcessAttributes, lpThreadAttributes,
bInheritHandles, dwCreationFlags,
lpStartupInfo, lpProcessInfo );
goto done; goto done;
} }

View File

@ -67,7 +67,7 @@ static LPCSTR ENV_FindVariable( LPCSTR env, LPCSTR name, INT len )
* *
* Build the environment for the initial process * Build the environment for the initial process
*/ */
static BOOL ENV_BuildEnvironment( PDB *pdb ) BOOL ENV_BuildEnvironment(void)
{ {
extern char **environ; extern char **environ;
LPSTR p, *e; LPSTR p, *e;
@ -81,7 +81,7 @@ static BOOL ENV_BuildEnvironment( PDB *pdb )
/* Now allocate the environment */ /* Now allocate the environment */
if (!(p = HeapAlloc( GetProcessHeap(), 0, size ))) return FALSE; if (!(p = HeapAlloc( GetProcessHeap(), 0, size ))) return FALSE;
pdb->env_db->environ = p; PROCESS_Current()->env_db->environ = p;
/* And fill it with the Unix environment */ /* And fill it with the Unix environment */
@ -104,20 +104,11 @@ static BOOL ENV_BuildEnvironment( PDB *pdb )
* Make a process inherit the environment from its parent or from an * Make a process inherit the environment from its parent or from an
* explicit environment. * explicit environment.
*/ */
BOOL ENV_InheritEnvironment( LPCSTR env ) BOOL ENV_InheritEnvironment( PDB *pdb, LPCSTR env )
{ {
DWORD size; DWORD size;
LPCSTR src; LPCSTR src;
LPSTR dst; LPSTR dst;
PDB *pdb = PROCESS_Current();
/* FIXME: should lock the parent environment */
if (!env)
{
if (!pdb->parent) /* initial process */
return ENV_BuildEnvironment( pdb );
env = pdb->parent->env_db->environ;
}
/* Compute the environment size */ /* Compute the environment size */

View File

@ -42,6 +42,13 @@ void MAIN_EmulatorRun( void )
char startProg[256], defProg[256]; char startProg[256], defProg[256];
int i, tasks = 0; int i, tasks = 0;
MSG msg; MSG msg;
char szGraphicsDriver[MAX_PATH];
if (PROFILE_GetWineIniString( "Wine", "GraphicsDriver",
"x11drv", szGraphicsDriver, sizeof(szGraphicsDriver)))
{
if (!LoadLibraryA( szGraphicsDriver )) return FALSE;
}
/* Load system DLLs into the initial process (and initialize them) */ /* Load system DLLs into the initial process (and initialize them) */
if ( !LoadLibrary16("GDI.EXE" ) || !LoadLibraryA("GDI32.DLL" ) if ( !LoadLibrary16("GDI.EXE" ) || !LoadLibraryA("GDI32.DLL" )
@ -102,6 +109,12 @@ int main( int argc, char *argv[] )
/* Initialize everything */ /* Initialize everything */
if (!MAIN_MainInit( argc, argv, FALSE )) return 1; if (!MAIN_MainInit( argc, argv, FALSE )) return 1;
if (!THREAD_InitStack( NtCurrentTeb(), PROCESS_Current(), 0, TRUE )) return 1;
SIGNAL_Init(); /* reinitialize signal stack */
/* Initialize KERNEL */
if (!LoadLibraryA( "KERNEL32" )) return FALSE;
/* Create initial task */ /* Create initial task */
if ( !(pModule = NE_GetPtr( GetModuleHandle16( "KERNEL" ) )) ) return 1; if ( !(pModule = NE_GetPtr( GetModuleHandle16( "KERNEL" ) )) ) return 1;
if ( !TASK_Create( pModule, FALSE ) ) return 1; if ( !TASK_Create( pModule, FALSE ) ) return 1;

View File

@ -5,6 +5,8 @@
*/ */
#include <assert.h> #include <assert.h>
#include <ctype.h>
#include <errno.h>
#include <fcntl.h> #include <fcntl.h>
#include <stdlib.h> #include <stdlib.h>
#include <stdio.h> #include <stdio.h>
@ -43,31 +45,6 @@ static STARTUPINFOA initial_startup;
static PDB *PROCESS_First = &initial_pdb; static PDB *PROCESS_First = &initial_pdb;
/***********************************************************************
* PROCESS_WalkProcess
*/
void PROCESS_WalkProcess(void)
{
PDB *pdb;
char *name;
pdb = PROCESS_First;
MESSAGE( " pid PDB #th modref module \n" );
while(pdb)
{
if (pdb == &initial_pdb)
name = "initial PDB";
else
name = (pdb->exe_modref) ? pdb->exe_modref->filename : "";
MESSAGE( " %8p %8p %5d %8p %s\n", pdb->server_pid, pdb,
pdb->threads, pdb->exe_modref, name);
pdb = pdb->next;
}
return;
}
/*********************************************************************** /***********************************************************************
* PROCESS_IdToPDB * PROCESS_IdToPDB
* *
@ -210,27 +187,15 @@ void PROCESS_CallUserSignalProc( UINT uCode, HMODULE hModule )
static BOOL PROCESS_CreateEnvDB(void) static BOOL PROCESS_CreateEnvDB(void)
{ {
struct init_process_request *req = get_req_buffer(); struct init_process_request *req = get_req_buffer();
STARTUPINFOA *startup;
ENVDB *env_db;
char cmd_line[4096];
PDB *pdb = PROCESS_Current(); PDB *pdb = PROCESS_Current();
ENVDB *env_db = pdb->env_db;
/* Allocate the env DB */ STARTUPINFOA *startup = env_db->startup_info;
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( GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(STARTUPINFOA) )))
return FALSE;
env_db->startup_info = startup;
/* Retrieve startup info from the server */ /* Retrieve startup info from the server */
req->ldt_copy = ldt_copy; req->ldt_copy = ldt_copy;
req->ldt_flags = ldt_flags_copy; req->ldt_flags = ldt_flags_copy;
req->ppid = getppid();
if (server_call( REQ_INIT_PROCESS )) return FALSE; if (server_call( REQ_INIT_PROCESS )) return FALSE;
pdb->exe_file = req->exe_file; pdb->exe_file = req->exe_file;
startup->dwFlags = req->start_flags; startup->dwFlags = req->start_flags;
@ -238,16 +203,6 @@ static BOOL PROCESS_CreateEnvDB(void)
env_db->hStdin = startup->hStdInput = req->hstdin; env_db->hStdin = startup->hStdInput = req->hstdin;
env_db->hStdout = startup->hStdOutput = req->hstdout; env_db->hStdout = startup->hStdOutput = req->hstdout;
env_db->hStderr = startup->hStdError = req->hstderr; env_db->hStderr = startup->hStdError = req->hstderr;
lstrcpynA( cmd_line, req->cmdline, sizeof(cmd_line) );
/* Copy the parent environment */
if (!ENV_InheritEnvironment( req->env_ptr )) return FALSE;
/* Copy the command line */
if (!(pdb->env_db->cmd_line = HEAP_strdupA( GetProcessHeap(), 0, cmd_line )))
return FALSE;
return TRUE; return TRUE;
} }
@ -277,7 +232,8 @@ void PROCESS_FreePDB( PDB *pdb )
*/ */
static PDB *PROCESS_CreatePDB( PDB *parent, BOOL inherit ) static PDB *PROCESS_CreatePDB( PDB *parent, BOOL inherit )
{ {
PDB *pdb = HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(PDB) ); PDB *pdb = HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY,
sizeof(PDB) + sizeof(ENVDB) + sizeof(STARTUPINFOA) );
if (!pdb) return NULL; if (!pdb) return NULL;
pdb->exit_code = STILL_ACTIVE; pdb->exit_code = STILL_ACTIVE;
@ -291,6 +247,11 @@ static PDB *PROCESS_CreatePDB( PDB *parent, BOOL inherit )
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;
pdb->env_db = (ENVDB *)(pdb + 1);
pdb->env_db->startup_info = (STARTUPINFOA *)(pdb->env_db + 1);
InitializeCriticalSection( &pdb->env_db->section );
PROCESS_First = pdb; PROCESS_First = pdb;
return pdb; return pdb;
} }
@ -303,10 +264,6 @@ BOOL PROCESS_Init( BOOL win32 )
{ {
struct init_process_request *req; struct init_process_request *req;
TEB *teb; TEB *teb;
int server_fd;
/* Start the server */
server_fd = CLIENT_InitServer();
/* Fill the initial process structure */ /* Fill the initial process structure */
initial_pdb.exit_code = STILL_ACTIVE; initial_pdb.exit_code = STILL_ACTIVE;
@ -320,12 +277,31 @@ BOOL PROCESS_Init( BOOL win32 )
initial_pdb.winver = 0xffff; /* to be determined */ initial_pdb.winver = 0xffff; /* to be determined */
initial_pdb.main_queue = INVALID_HANDLE_VALUE16; initial_pdb.main_queue = INVALID_HANDLE_VALUE16;
initial_envdb.startup_info = &initial_startup; initial_envdb.startup_info = &initial_startup;
teb = THREAD_Init( &initial_pdb );
/* Setup the server connection */
teb->socket = CLIENT_InitServer();
if (CLIENT_InitThread()) return FALSE;
/* Initialize virtual memory management */ /* Initialize virtual memory management */
if (!VIRTUAL_Init()) return FALSE; if (!VIRTUAL_Init()) return FALSE;
/* Create the initial thread structure and socket pair */ /* Retrieve startup info from the server */
if (!(teb = THREAD_CreateInitialThread( &initial_pdb, server_fd ))) return FALSE; req = get_req_buffer();
req->ldt_copy = ldt_copy;
req->ldt_flags = ldt_flags_copy;
req->ppid = getppid();
if (server_call( REQ_INIT_PROCESS )) return FALSE;
initial_pdb.exe_file = req->exe_file;
initial_startup.dwFlags = req->start_flags;
initial_startup.wShowWindow = req->cmd_show;
initial_envdb.hStdin = initial_startup.hStdInput = req->hstdin;
initial_envdb.hStdout = initial_startup.hStdOutput = req->hstdout;
initial_envdb.hStderr = initial_startup.hStdError = req->hstderr;
initial_envdb.cmd_line = "";
/* Initialize signal handling */
if (!SIGNAL_Init()) return FALSE;
/* 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;
@ -342,24 +318,8 @@ BOOL PROCESS_Init( BOOL win32 )
initial_pdb.idle_event = CreateEventA ( NULL, TRUE, FALSE, NULL ); initial_pdb.idle_event = CreateEventA ( NULL, TRUE, FALSE, NULL );
initial_pdb.idle_event = ConvertToGlobalHandle ( initial_pdb.idle_event ); initial_pdb.idle_event = ConvertToGlobalHandle ( initial_pdb.idle_event );
/* Initialize signal handling */
if (!SIGNAL_Init()) return FALSE;
/* Retrieve startup info from the server */
req = get_req_buffer();
req->ldt_copy = ldt_copy;
req->ldt_flags = ldt_flags_copy;
if (server_call( REQ_INIT_PROCESS )) return FALSE;
initial_pdb.exe_file = req->exe_file;
initial_startup.dwFlags = req->start_flags;
initial_startup.wShowWindow = req->cmd_show;
initial_envdb.hStdin = initial_startup.hStdInput = req->hstdin;
initial_envdb.hStdout = initial_startup.hStdOutput = req->hstdout;
initial_envdb.hStderr = initial_startup.hStdError = req->hstderr;
initial_envdb.cmd_line = "";
/* Copy the parent environment */ /* Copy the parent environment */
if (!ENV_InheritEnvironment( NULL )) return FALSE; if (!ENV_BuildEnvironment()) return FALSE;
/* Create the SEGPTR heap */ /* Create the SEGPTR heap */
if (!(SegptrHeap = HeapCreate( HEAP_WINE_SEGPTR, 0, 0 ))) return FALSE; if (!(SegptrHeap = HeapCreate( HEAP_WINE_SEGPTR, 0, 0 ))) return FALSE;
@ -372,6 +332,33 @@ BOOL PROCESS_Init( BOOL win32 )
} }
/***********************************************************************
* load_system_dlls
*
* Load system DLLs into the initial process (and initialize them)
*/
static int load_system_dlls(void)
{
char driver[MAX_PATH];
if (!LoadLibraryA( "KERNEL32" )) return 0;
PROFILE_GetWineIniString( "Wine", "GraphicsDriver", "x11drv", driver, sizeof(driver) );
if (!LoadLibraryA( driver ))
{
MESSAGE( "Could not load graphics driver '%s'\n", driver );
return 0;
}
if (!LoadLibraryA("GDI32.DLL")) return 0;
if (!LoadLibrary16("GDI.EXE")) return 0;
if (!LoadLibrary16("USER.EXE")) return 0;
if (!LoadLibraryA("USER32.DLL")) return 0;
return 1;
}
/*********************************************************************** /***********************************************************************
* start_process * start_process
* *
@ -409,13 +396,8 @@ static void start_process(void)
if (pdb->flags & PDB32_CONSOLE_PROC) AllocConsole(); if (pdb->flags & PDB32_CONSOLE_PROC) AllocConsole();
/* Load system DLLs into the initial process (and initialize them) */ /* Load the system dlls */
if (!LoadLibraryA( "KERNEL32" )) goto error; if (!load_system_dlls()) goto error;
if (!LoadLibraryA( "x11drv" )) goto error;
if ( !LoadLibrary16("GDI.EXE" ) || !LoadLibraryA("GDI32.DLL" )
|| !LoadLibrary16("USER.EXE") || !LoadLibraryA("USER32.DLL"))
goto error;
/* Get pointers to USER routines called by KERNEL */ /* Get pointers to USER routines called by KERNEL */
THUNK_InitCallout(); THUNK_InitCallout();
@ -547,6 +529,250 @@ void PROCESS_InitWinelib( int argc, char *argv[] )
} }
/***********************************************************************
* build_argv
*
* Build an argv array from a command-line.
* The command-line is modified to insert nulls.
*/
static char **build_argv( char *cmdline, char *argv0 )
{
char **argv;
int count = 1;
char *p = cmdline;
while (*p)
{
while (*p && isspace(*p)) p++;
if (!*p) break;
count++;
while (*p && !isspace(*p)) p++;
}
if (argv0) count++;
if ((argv = malloc( count * sizeof(*argv) )))
{
char **argvptr = argv;
if (argv0) *argvptr++ = argv0;
p = cmdline;
while (*p)
{
while (*p && isspace(*p)) *p++ = 0;
if (!*p) break;
*argvptr++ = p;
while (*p && !isspace(*p)) p++;
}
*argvptr = 0;
}
return argv;
}
/***********************************************************************
* build_envp
*
* Build the environment of a new child process.
*/
static char **build_envp( const char *env )
{
const char *p;
char **envp;
int count;
for (p = env, count = 0; *p; count++) p += strlen(p) + 1;
count += 3;
if ((envp = malloc( count * sizeof(*envp) )))
{
extern char **environ;
char **envptr = envp;
char **unixptr = environ;
/* first put PATH, HOME and WINEPREFIX from the unix env */
for (unixptr = environ; unixptr && *unixptr; unixptr++)
if (!memcmp( *unixptr, "PATH=", 5 ) ||
!memcmp( *unixptr, "HOME=", 5 ) ||
!memcmp( *unixptr, "WINEPREFIX=", 11 )) *envptr++ = *unixptr;
/* now put the Windows environment strings */
for (p = env; *p; p += strlen(p) + 1)
{
if (memcmp( p, "PATH=", 5 ) &&
memcmp( p, "HOME=", 5 ) &&
memcmp( p, "WINEPREFIX=", 11 )) *envptr++ = (char *)p;
}
*envptr = 0;
}
return envp;
}
/***********************************************************************
* find_wine_binary
*
* Locate the Wine binary to exec for a new Win32 process.
*/
static void exec_wine_binary( char **argv, char **envp )
{
const char *path, *pos, *ptr;
/* first try bin directory */
argv[0] = BINDIR "/wine";
execve( argv[0], argv, envp );
/* now try the path of argv0 of the current binary */
if (!(argv[0] = malloc( strlen(argv0) + 6 ))) return;
if ((ptr = strrchr( argv0, '/' )))
{
memcpy( argv[0], argv0, ptr - argv0 );
strcpy( argv[0] + (ptr - argv0), "/wine" );
execve( argv[0], argv, envp );
}
free( argv[0] );
/* now search in the Unix path */
if ((path = getenv( "PATH" )))
{
if (!(argv[0] = malloc( strlen(path) + 6 ))) return;
pos = path;
for (;;)
{
while (*pos == ':') pos++;
if (!*pos) break;
if (!(ptr = strchr( pos, ':' ))) ptr = pos + strlen(pos);
memcpy( argv[0], pos, ptr - pos );
strcpy( argv[0] + (ptr - pos), "/wine" );
execve( argv[0], argv, envp );
pos = ptr;
}
}
free( argv[0] );
/* finally try the current directory */
argv[0] = "./wine";
execve( argv[0], argv, envp );
}
/***********************************************************************
* fork_and_exec
*
* Fork and exec a new Unix process, checking for errors.
*/
static int fork_and_exec( const char *filename, const char *cmdline, const char *env )
{
int fd[2];
int pid, err;
if (pipe(fd) == -1)
{
FILE_SetDosError();
return -1;
}
fcntl( fd[1], F_SETFD, 1 ); /* set close on exec */
if (!(pid = fork())) /* child */
{
char **argv = build_argv( (char *)cmdline, NULL );
char **envp = build_envp( env );
close( fd[0] );
if (argv && envp) execve( filename, argv, envp );
err = errno;
write( fd[1], &err, sizeof(err) );
_exit(1);
}
close( fd[1] );
if ((pid != -1) && (read( fd[0], &err, sizeof(err) ) > 0)) /* exec failed */
{
errno = err;
pid = -1;
}
if (pid == -1) FILE_SetDosError();
close( fd[0] );
return pid;
}
/***********************************************************************
* PROCESS_CreateUnixProcess
*/
BOOL PROCESS_CreateUnixProcess( LPCSTR filename, LPCSTR cmd_line, LPCSTR env,
LPSECURITY_ATTRIBUTES psa, LPSECURITY_ATTRIBUTES tsa,
BOOL inherit, DWORD flags, LPSTARTUPINFOA startup,
LPPROCESS_INFORMATION info )
{
int pid;
const char *unixfilename = filename;
DOS_FULL_NAME full_name;
HANDLE load_done_evt = -1;
struct new_process_request *req = get_req_buffer();
struct wait_process_request *wait_req = get_req_buffer();
info->hThread = info->hProcess = INVALID_HANDLE_VALUE;
if (DOSFS_GetFullName( filename, TRUE, &full_name )) unixfilename = full_name.long_name;
/* create the process on the server side */
req->inherit_all = inherit;
req->create_flags = flags;
req->start_flags = startup->dwFlags;
req->exe_file = -1;
if (startup->dwFlags & STARTF_USESTDHANDLES)
{
req->hstdin = startup->hStdInput;
req->hstdout = startup->hStdOutput;
req->hstderr = startup->hStdError;
}
else
{
req->hstdin = GetStdHandle( STD_INPUT_HANDLE );
req->hstdout = GetStdHandle( STD_OUTPUT_HANDLE );
req->hstderr = GetStdHandle( STD_ERROR_HANDLE );
}
req->cmd_show = startup->wShowWindow;
req->alloc_fd = 0;
if (server_call( REQ_NEW_PROCESS )) return FALSE;
/* fork and execute */
pid = fork_and_exec( unixfilename, cmd_line, env ? env : GetEnvironmentStringsA() );
wait_req->cancel = (pid == -1);
wait_req->pinherit = (psa && (psa->nLength >= sizeof(*psa)) && psa->bInheritHandle);
wait_req->tinherit = (tsa && (tsa->nLength >= sizeof(*tsa)) && tsa->bInheritHandle);
wait_req->timeout = 2000;
if (server_call( REQ_WAIT_PROCESS ) || (pid == -1)) goto error;
info->dwProcessId = (DWORD)wait_req->pid;
info->dwThreadId = (DWORD)wait_req->tid;
info->hProcess = wait_req->phandle;
info->hThread = wait_req->thandle;
load_done_evt = wait_req->event;
/* Wait until process is initialized (or initialization failed) */
if (load_done_evt != -1)
{
DWORD res;
HANDLE handles[2];
handles[0] = info->hProcess;
handles[1] = load_done_evt;
res = WaitForMultipleObjects( 2, handles, FALSE, INFINITE );
CloseHandle( load_done_evt );
if (res == STATUS_WAIT_0) /* the process died */
{
DWORD exitcode;
if (GetExitCodeProcess( info->hProcess, &exitcode )) SetLastError( exitcode );
CloseHandle( info->hThread );
CloseHandle( info->hProcess );
return FALSE;
}
}
return TRUE;
error:
if (load_done_evt != -1) CloseHandle( load_done_evt );
if (info->hThread != INVALID_HANDLE_VALUE) CloseHandle( info->hThread );
if (info->hProcess != INVALID_HANDLE_VALUE) CloseHandle( info->hProcess );
return FALSE;
}
/*********************************************************************** /***********************************************************************
* PROCESS_Start * PROCESS_Start
* *
@ -691,6 +917,7 @@ PDB *PROCESS_Create( NE_MODULE *pModule, HFILE hFile, LPCSTR cmd_line, LPCSTR en
BOOL alloc_stack16; BOOL alloc_stack16;
int fd = -1; int fd = -1;
struct new_process_request *req = get_req_buffer(); struct new_process_request *req = get_req_buffer();
struct wait_process_request *wait_req = get_req_buffer();
TEB *teb = NULL; TEB *teb = NULL;
PDB *parent = PROCESS_Current(); PDB *parent = PROCESS_Current();
PDB *pdb = PROCESS_CreatePDB( parent, inherit ); PDB *pdb = PROCESS_CreatePDB( parent, inherit );
@ -698,10 +925,11 @@ PDB *PROCESS_Create( NE_MODULE *pModule, HFILE hFile, LPCSTR cmd_line, LPCSTR en
if (!pdb) return NULL; if (!pdb) return NULL;
info->hThread = info->hProcess = INVALID_HANDLE_VALUE; info->hThread = info->hProcess = INVALID_HANDLE_VALUE;
if (!(pdb->env_db->cmd_line = HEAP_strdupA( GetProcessHeap(), 0, cmd_line ))) goto error;
if (!ENV_InheritEnvironment( pdb, env ? env : GetEnvironmentStringsA() )) goto error;
/* Create the process on the server side */ /* Create the process on the server side */
req->pinherit = (psa && (psa->nLength >= sizeof(*psa)) && psa->bInheritHandle);
req->tinherit = (tsa && (tsa->nLength >= sizeof(*tsa)) && tsa->bInheritHandle);
req->inherit_all = 2 /*inherit*/; /* HACK! */ req->inherit_all = 2 /*inherit*/; /* HACK! */
req->create_flags = flags; req->create_flags = flags;
req->start_flags = startup->dwFlags; req->start_flags = startup->dwFlags;
@ -719,15 +947,8 @@ PDB *PROCESS_Create( NE_MODULE *pModule, HFILE hFile, LPCSTR cmd_line, LPCSTR en
req->hstderr = GetStdHandle( STD_ERROR_HANDLE ); req->hstderr = GetStdHandle( STD_ERROR_HANDLE );
} }
req->cmd_show = startup->wShowWindow; req->cmd_show = startup->wShowWindow;
req->env_ptr = (void*)env; /* FIXME: hack */ req->alloc_fd = 1;
lstrcpynA( req->cmdline, cmd_line, server_remaining(req->cmdline) );
if (server_call_fd( REQ_NEW_PROCESS, -1, &fd )) goto error; if (server_call_fd( REQ_NEW_PROCESS, -1, &fd )) goto error;
pdb->server_pid = req->pid;
info->hProcess = req->phandle;
info->dwProcessId = (DWORD)req->pid;
info->hThread = req->thandle;
info->dwThreadId = (DWORD)req->tid;
load_done_evt = req->event;
if (pModule->module32) /* Win32 process */ if (pModule->module32) /* Win32 process */
{ {
@ -752,13 +973,26 @@ PDB *PROCESS_Create( NE_MODULE *pModule, HFILE hFile, LPCSTR cmd_line, LPCSTR en
/* Create the main thread */ /* Create the main thread */
if (!(teb = THREAD_Create( pdb, req->pid, req->tid, fd, size, alloc_stack16 ))) goto error; if ((teb = THREAD_Create( pdb, fd, size, alloc_stack16 )))
teb->startup = PROCESS_Start; {
fd = -1; /* don't close it */ 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;
SYSDEPS_SpawnThread( teb ); SYSDEPS_SpawnThread( teb );
}
wait_req->cancel = !teb;
wait_req->pinherit = (psa && (psa->nLength >= sizeof(*psa)) && psa->bInheritHandle);
wait_req->tinherit = (tsa && (tsa->nLength >= sizeof(*tsa)) && tsa->bInheritHandle);
wait_req->timeout = 2000;
if (server_call( REQ_WAIT_PROCESS ) || !teb) goto error;
info->dwProcessId = (DWORD)wait_req->pid;
info->dwThreadId = (DWORD)wait_req->tid;
info->hProcess = wait_req->phandle;
info->hThread = wait_req->thandle;
load_done_evt = wait_req->event;
/* Wait until process is initialized (or initialization failed) */ /* Wait until process is initialized (or initialization failed) */
handles[0] = info->hProcess; handles[0] = info->hProcess;

View File

@ -85,6 +85,8 @@ static BOOL THREAD_InitTEB( TEB *teb, PDB *pdb )
teb->process = pdb; teb->process = pdb;
teb->exit_code = STILL_ACTIVE; teb->exit_code = STILL_ACTIVE;
teb->socket = -1; teb->socket = -1;
teb->stack_top = (void *)~0UL;
teb->StaticUnicodeString.MaximumLength = sizeof(teb->StaticUnicodeBuffer); teb->StaticUnicodeString.MaximumLength = sizeof(teb->StaticUnicodeBuffer);
teb->StaticUnicodeString.Buffer = (PWSTR)teb->StaticUnicodeBuffer; teb->StaticUnicodeString.Buffer = (PWSTR)teb->StaticUnicodeBuffer;
teb->teb_sel = SELECTOR_AllocBlock( teb, 0x1000, SEGMENT_DATA, TRUE, FALSE ); teb->teb_sel = SELECTOR_AllocBlock( teb, 0x1000, SEGMENT_DATA, TRUE, FALSE );
@ -194,20 +196,17 @@ error:
/*********************************************************************** /***********************************************************************
* THREAD_CreateInitialThread * THREAD_Init
* *
* Create the initial thread. * Setup the initial thread.
* *
* NOTES: The first allocated TEB on NT is at 0x7ffde000. * NOTES: The first allocated TEB on NT is at 0x7ffde000.
*/ */
TEB *THREAD_CreateInitialThread( PDB *pdb, int server_fd ) TEB *THREAD_Init( struct _PDB *pdb )
{ {
if (!THREAD_InitTEB( &initial_teb, pdb )) return NULL; if (!THREAD_InitTEB( &initial_teb, pdb )) return NULL;
SYSDEPS_SetCurThread( &initial_teb ); SYSDEPS_SetCurThread( &initial_teb );
initial_teb.socket = server_fd; return &initial_teb;
if (CLIENT_InitThread()) return NULL;
return THREAD_InitStack( &initial_teb, pdb, 0, TRUE );
} }
@ -215,15 +214,12 @@ TEB *THREAD_CreateInitialThread( PDB *pdb, int server_fd )
* THREAD_Create * THREAD_Create
* *
*/ */
TEB *THREAD_Create( PDB *pdb, void *pid, void *tid, int fd, TEB *THREAD_Create( PDB *pdb, int fd, DWORD stack_size, BOOL alloc_stack16 )
DWORD stack_size, BOOL alloc_stack16 )
{ {
TEB *teb; TEB *teb;
if ((teb = THREAD_InitStack( NULL, pdb, stack_size, alloc_stack16 ))) if ((teb = THREAD_InitStack( NULL, pdb, stack_size, alloc_stack16 )))
{ {
teb->pid = pid;
teb->tid = tid;
teb->socket = fd; teb->socket = fd;
fcntl( fd, F_SETFD, 1 ); /* set close on exec flag */ fcntl( fd, F_SETFD, 1 ); /* set close on exec flag */
TRACE("(%p) succeeded\n", teb); TRACE("(%p) succeeded\n", teb);
@ -266,14 +262,15 @@ HANDLE WINAPI CreateThread( SECURITY_ATTRIBUTES *sa, DWORD stack,
struct new_thread_request *req = get_req_buffer(); struct new_thread_request *req = get_req_buffer();
int socket, handle = -1; int socket, handle = -1;
TEB *teb; TEB *teb;
void *tid;
req->suspend = ((flags & CREATE_SUSPENDED) != 0); req->suspend = ((flags & CREATE_SUSPENDED) != 0);
req->inherit = (sa && (sa->nLength>=sizeof(*sa)) && sa->bInheritHandle); req->inherit = (sa && (sa->nLength>=sizeof(*sa)) && sa->bInheritHandle);
if (server_call_fd( REQ_NEW_THREAD, -1, &socket )) return 0; if (server_call_fd( REQ_NEW_THREAD, -1, &socket )) return 0;
handle = req->handle; handle = req->handle;
tid = req->tid;
if (!(teb = THREAD_Create( PROCESS_Current(), (void *)GetCurrentProcessId(), if (!(teb = THREAD_Create( PROCESS_Current(), socket, stack, TRUE )))
req->tid, socket, stack, TRUE )))
{ {
close( socket ); close( socket );
return 0; return 0;
@ -282,7 +279,7 @@ HANDLE WINAPI CreateThread( SECURITY_ATTRIBUTES *sa, DWORD stack,
teb->entry_point = start; teb->entry_point = start;
teb->entry_arg = param; teb->entry_arg = param;
teb->startup = THREAD_Start; teb->startup = THREAD_Start;
if (id) *id = (DWORD)teb->tid; if (id) *id = (DWORD)tid;
if (SYSDEPS_SpawnThread( teb ) == -1) if (SYSDEPS_SpawnThread( teb ) == -1)
{ {
CloseHandle( handle ); CloseHandle( handle );

View File

@ -55,47 +55,54 @@ static const struct object_ops process_ops =
process_destroy /* destroy */ process_destroy /* destroy */
}; };
/* set the process creation info */ /* process startup info */
static int set_creation_info( struct process *process, struct new_process_request *req,
const char *cmd_line, size_t len ) struct startup_info
{ {
if (!(process->info = mem_alloc( sizeof(*process->info) + len ))) return 0; struct object obj; /* object header */
if (req) int inherit_all; /* inherit all handles from parent */
{ int create_flags; /* creation flags */
/* copy the request structure */ int start_flags; /* flags from startup info */
memcpy( process->info, req, sizeof(*req) ); int exe_file; /* file handle for main exe */
} int hstdin; /* handle for stdin */
else /* no request, use defaults */ int hstdout; /* handle for stdout */
{ int hstderr; /* handle for stderr */
req = process->info; int cmd_show; /* main window show mode */
req->pinherit = 0; struct process *process; /* created process */
req->tinherit = 0; struct thread *thread; /* created thread */
req->inherit_all = 0; };
req->create_flags = CREATE_NEW_CONSOLE;
req->start_flags = STARTF_USESTDHANDLES; static void startup_info_dump( struct object *obj, int verbose );
req->exe_file = -1; static int startup_info_signaled( struct object *obj, struct thread *thread );
req->hstdin = -1; static void startup_info_destroy( struct object *obj );
req->hstdout = -1;
req->hstderr = -1; static const struct object_ops startup_info_ops =
req->cmd_show = 0; {
req->env_ptr = NULL; sizeof(struct startup_info), /* size */
} startup_info_dump, /* dump */
memcpy( process->info->cmdline, cmd_line, len ); add_queue, /* add_queue */
process->info->cmdline[len] = 0; remove_queue, /* remove_queue */
process->create_flags = process->info->create_flags; startup_info_signaled, /* signaled */
return 1; no_satisfied, /* satisfied */
} NULL, /* get_poll_events */
NULL, /* poll_event */
no_read_fd, /* get_read_fd */
no_write_fd, /* get_write_fd */
no_flush, /* flush */
no_get_file_info, /* get_file_info */
startup_info_destroy /* destroy */
};
/* set the console and stdio handles for a newly created process */ /* set the console and stdio handles for a newly created process */
static int set_process_console( struct process *process, struct process *parent ) static int set_process_console( struct process *process, struct process *parent,
struct startup_info *info, struct init_process_request *req )
{ {
struct new_process_request *info = process->info;
if (process->create_flags & CREATE_NEW_CONSOLE) if (process->create_flags & CREATE_NEW_CONSOLE)
{ {
if (!alloc_console( process )) return 0; if (!alloc_console( process )) return 0;
} }
else if (!(process->create_flags & DETACHED_PROCESS)) else if (parent && !(process->create_flags & DETACHED_PROCESS))
{ {
if (parent->console_in) process->console_in = grab_object( parent->console_in ); 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->console_out) process->console_out = grab_object( parent->console_out );
@ -105,31 +112,35 @@ static int set_process_console( struct process *process, struct process *parent
if (!info->inherit_all && !(info->start_flags & STARTF_USESTDHANDLES)) if (!info->inherit_all && !(info->start_flags & STARTF_USESTDHANDLES))
{ {
/* duplicate the handle from the parent into this process */ /* duplicate the handle from the parent into this process */
info->hstdin = duplicate_handle( parent, info->hstdin, process, req->hstdin = duplicate_handle( parent, info->hstdin, process,
0, TRUE, DUPLICATE_SAME_ACCESS ); 0, TRUE, DUPLICATE_SAME_ACCESS );
info->hstdout = duplicate_handle( parent, info->hstdout, process, req->hstdout = duplicate_handle( parent, info->hstdout, process,
0, TRUE, DUPLICATE_SAME_ACCESS ); 0, TRUE, DUPLICATE_SAME_ACCESS );
info->hstderr = duplicate_handle( parent, info->hstderr, process, req->hstderr = duplicate_handle( parent, info->hstderr, process,
0, TRUE, DUPLICATE_SAME_ACCESS ); 0, TRUE, DUPLICATE_SAME_ACCESS );
}
else
{
req->hstdin = info->hstdin;
req->hstdout = info->hstdout;
req->hstderr = info->hstderr;
} }
} }
else else
{ {
/* no parent, use handles to the console for stdio */ /* no parent, use handles to the console for stdio */
info->hstdin = alloc_handle( process, process->console_in, req->hstdin = alloc_handle( process, process->console_in,
GENERIC_READ | GENERIC_WRITE | SYNCHRONIZE, 1 ); GENERIC_READ | GENERIC_WRITE | SYNCHRONIZE, 1 );
info->hstdout = alloc_handle( process, process->console_out, req->hstdout = alloc_handle( process, process->console_out,
GENERIC_READ | GENERIC_WRITE | SYNCHRONIZE, 1 ); GENERIC_READ | GENERIC_WRITE | SYNCHRONIZE, 1 );
info->hstderr = alloc_handle( process, process->console_out, req->hstderr = alloc_handle( process, process->console_out,
GENERIC_READ | GENERIC_WRITE | SYNCHRONIZE, 1 ); GENERIC_READ | GENERIC_WRITE | SYNCHRONIZE, 1 );
} }
return 1; return 1;
} }
/* create a new process and its main thread */ /* create a new process and its main thread */
struct thread *create_process( int fd, struct process *parent, struct thread *create_process( int fd )
struct new_process_request *req,
const char *cmd_line, size_t len )
{ {
struct process *process; struct process *process;
struct thread *thread = NULL; struct thread *thread = NULL;
@ -153,7 +164,6 @@ struct thread *create_process( int fd, struct process *parent,
process->console_in = NULL; process->console_in = NULL;
process->console_out = NULL; process->console_out = NULL;
process->init_event = NULL; process->init_event = NULL;
process->info = NULL;
process->ldt_copy = NULL; process->ldt_copy = NULL;
process->ldt_flags = NULL; process->ldt_flags = NULL;
process->exe.next = NULL; process->exe.next = NULL;
@ -165,54 +175,99 @@ struct thread *create_process( int fd, struct process *parent,
if ((process->next = first_process) != NULL) process->next->prev = process; if ((process->next = first_process) != NULL) process->next->prev = process;
first_process = process; first_process = process;
/* copy the request structure */
if (!set_creation_info( process, req, cmd_line, len )) goto error;
if (process->info->inherit_all == 2) /* HACK! */
process->handles = grab_object( parent->handles );
else if (process->info->inherit_all)
process->handles = copy_handle_table( process, parent );
else
process->handles = alloc_handle_table( process, 0 );
if (!process->handles) goto error;
/* retrieve the main exe file */
if (process->info->exe_file != -1)
{
if (!(process->exe.file = get_file_obj( parent, process->info->exe_file,
GENERIC_READ ))) goto error;
process->info->exe_file = -1;
}
/* create the main thread */ /* create the main thread */
if (!(thread = create_thread( fd, process, (process->create_flags & CREATE_SUSPENDED) != 0))) if (!(thread = create_thread( fd, process ))) goto error;
goto error;
/* create the init done event */ /* create the init done event */
if (!(process->init_event = create_event( NULL, 0, 1, 0 ))) goto error; if (!(process->init_event = create_event( NULL, 0, 1, 0 ))) goto error;
/* set the process console */
if (!set_process_console( process, parent )) goto error;
/* attach to the debugger if requested */
if (process->create_flags & (DEBUG_PROCESS | DEBUG_ONLY_THIS_PROCESS))
set_process_debugger( process, current );
else if (parent && parent->debugger && !(parent->create_flags & DEBUG_ONLY_THIS_PROCESS))
set_process_debugger( process, parent->debugger );
add_process_thread( process, thread ); add_process_thread( process, thread );
release_object( process ); release_object( process );
return thread; return thread;
error: error:
close( fd );
free_console( process );
if (process->handles) release_object( process->handles );
if (thread) release_object( thread ); if (thread) release_object( thread );
release_object( process ); release_object( process );
return NULL; return NULL;
} }
/* initialize the current process and fill in the request */
static void init_process( int ppid, struct init_process_request *req )
{
struct process *process = current->process;
struct thread *parent_thread = get_thread_from_pid( ppid );
struct process *parent = NULL;
struct startup_info *info = NULL;
if (parent_thread)
{
parent = parent_thread->process;
info = parent_thread->info;
if (!info)
{
fatal_protocol_error( current, "init_process: parent but no info\n" );
return;
}
if (info->thread)
{
fatal_protocol_error( current, "init_process: called twice?\n" );
return;
}
}
/* set the process flags */
process->create_flags = info ? info->create_flags : CREATE_NEW_CONSOLE;
/* create the handle table */
if (parent && info->inherit_all == 2) /* HACK! */
process->handles = grab_object( parent->handles );
else if (parent && info->inherit_all)
process->handles = copy_handle_table( process, parent );
else
process->handles = alloc_handle_table( process, 0 );
if (!process->handles) goto error;
/* retrieve the main exe file */
req->exe_file = -1;
if (parent && info->exe_file != -1)
{
if (!(process->exe.file = get_file_obj( parent, info->exe_file, GENERIC_READ )))
goto error;
if ((req->exe_file = alloc_handle( process, process->exe.file, GENERIC_READ, 0 )) == -1)
goto error;
}
/* set the process console */
if (!set_process_console( process, parent, info, req )) goto error;
if (parent)
{
/* attach to the debugger if requested */
if (process->create_flags & (DEBUG_PROCESS | DEBUG_ONLY_THIS_PROCESS))
set_process_debugger( process, parent_thread );
else if (parent && parent->debugger && !(parent->create_flags & DEBUG_ONLY_THIS_PROCESS))
set_process_debugger( process, parent->debugger );
}
/* thread will be actually suspended in init_done */
if (process->create_flags & CREATE_SUSPENDED) current->suspend++;
if (info)
{
req->start_flags = info->start_flags;
req->cmd_show = info->cmd_show;
info->process = (struct process *)grab_object( process );
info->thread = (struct thread *)grab_object( current );
wake_up( &info->obj, 0 );
}
else
{
req->start_flags = STARTF_USESTDHANDLES;
req->cmd_show = 0;
}
error:
}
/* 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 )
{ {
@ -224,7 +279,6 @@ static void process_destroy( struct object *obj )
if (process->next) process->next->prev = process->prev; if (process->next) process->next->prev = process->prev;
if (process->prev) process->prev->next = process->next; if (process->prev) process->prev->next = process->next;
else first_process = process->next; else first_process = process->next;
if (process->info) free( process->info );
if (process->init_event) release_object( process->init_event ); if (process->init_event) release_object( process->init_event );
if (process->exe.file) release_object( process->exe.file ); if (process->exe.file) release_object( process->exe.file );
} }
@ -247,6 +301,57 @@ static int process_signaled( struct object *obj, struct thread *thread )
} }
static void startup_info_destroy( struct object *obj )
{
struct startup_info *info = (struct startup_info *)obj;
assert( obj->ops == &startup_info_ops );
if (info->process) release_object( info->process );
if (info->thread) release_object( info->thread );
}
static void startup_info_dump( struct object *obj, int verbose )
{
struct startup_info *info = (struct startup_info *)obj;
assert( obj->ops == &startup_info_ops );
fprintf( stderr, "Startup info flags=%x in=%d out=%d err=%d\n",
info->start_flags, info->hstdin, info->hstdout, info->hstderr );
}
static int startup_info_signaled( struct object *obj, struct thread *thread )
{
struct startup_info *info = (struct startup_info *)obj;
return (info->thread != NULL);
}
/* build a reply for the wait_process request */
static void build_wait_process_reply( struct thread *thread, struct object *obj, int signaled )
{
struct wait_process_request *req = get_req_ptr( thread );
if (obj)
{
struct startup_info *info = (struct startup_info *)obj;
assert( obj->ops == &startup_info_ops );
req->pid = get_process_id( info->process );
req->tid = get_thread_id( info->thread );
req->phandle = alloc_handle( thread->process, info->process,
PROCESS_ALL_ACCESS, req->pinherit );
req->thandle = alloc_handle( thread->process, info->thread,
THREAD_ALL_ACCESS, req->tinherit );
if (info->process->init_event)
req->event = alloc_handle( thread->process, info->process->init_event,
EVENT_ALL_ACCESS, 0 );
else
req->event = -1;
/* FIXME: set_error */
}
release_object( thread->info );
thread->info = NULL;
}
/* get a process from an id (and increment the refcount) */ /* get a process from an id (and increment the refcount) */
struct process *get_process_from_id( void *id ) struct process *get_process_from_id( void *id )
{ {
@ -314,7 +419,7 @@ static void process_killed( struct process *process )
{ {
assert( !process->thread_list ); assert( !process->thread_list );
gettimeofday( &process->end_time, NULL ); gettimeofday( &process->end_time, NULL );
release_object( process->handles ); if (process->handles) release_object( process->handles );
process->handles = NULL; process->handles = NULL;
free_console( process ); free_console( process );
while (process->exe.next) while (process->exe.next)
@ -594,83 +699,83 @@ struct module_snapshot *module_snap( struct process *process, int *count )
/* create a new process */ /* create a new process */
DECL_HANDLER(new_process) DECL_HANDLER(new_process)
{ {
size_t len = get_req_strlen( req, req->cmdline ); struct startup_info *info;
struct thread *thread;
int sock[2]; int sock[2];
int event = -1, phandle = -1;
req->phandle = -1; if (current->info)
req->thandle = -1;
req->event = -1;
req->pid = NULL;
req->tid = NULL;
if (socketpair( AF_UNIX, SOCK_STREAM, 0, sock ) == -1)
{ {
file_set_error(); fatal_protocol_error( current, "new_process: another process is being created\n" );
return; return;
} }
if (!(thread = create_process( sock[0], current->process, req, req->cmdline, len ))) /* build the startup info for a new process */
goto error; if (!(info = alloc_object( &startup_info_ops, -1 ))) return;
info->inherit_all = req->inherit_all;
info->create_flags = req->create_flags;
info->start_flags = req->start_flags;
info->exe_file = req->exe_file;
info->hstdin = req->hstdin;
info->hstdout = req->hstdout;
info->hstderr = req->hstderr;
info->cmd_show = req->cmd_show;
info->process = NULL;
info->thread = NULL;
if ((event = alloc_handle( current->process, thread->process->init_event, if (req->alloc_fd)
EVENT_ALL_ACCESS, 0 )) == -1) {
goto error; if (socketpair( AF_UNIX, SOCK_STREAM, 0, sock ) == -1)
{
file_set_error();
release_object( info );
return;
}
if (!create_process( sock[0] ))
{
release_object( info );
close( sock[1] );
return;
}
/* thread object will be released when the thread gets killed */
set_reply_fd( current, sock[1] );
}
current->info = info;
}
if ((phandle = alloc_handle( current->process, thread->process, /* Wait for the new process to start */
PROCESS_ALL_ACCESS, req->pinherit )) == -1) DECL_HANDLER(wait_process)
goto error; {
if (!current->info)
if ((req->thandle = alloc_handle( current->process, thread, {
THREAD_ALL_ACCESS, req->tinherit )) == -1) fatal_protocol_error( current, "wait_process: no process is being created\n" );
goto error; return;
}
/* thread object will be released when the thread gets killed */ req->pid = 0;
set_reply_fd( current, sock[1] ); req->tid = 0;
req->pid = get_process_id( thread->process ); req->phandle = -1;
req->tid = get_thread_id( thread ); req->thandle = -1;
req->phandle = phandle; if (req->cancel)
req->event = event; {
return; release_object( current->info );
current->info = NULL;
error: }
if (phandle != -1) close_handle( current->process, phandle ); else
if (event != -1) close_handle( current->process, event ); {
if (thread) release_object( thread ); struct object *obj = &current->info->obj;
close( sock[1] ); sleep_on( 1, &obj, SELECT_TIMEOUT, req->timeout, build_wait_process_reply );
}
} }
/* initialize a new process */ /* initialize a new process */
DECL_HANDLER(init_process) DECL_HANDLER(init_process)
{ {
struct new_process_request *info;
if (!current->unix_pid) if (!current->unix_pid)
{ {
fatal_protocol_error( current, "init_process: init_thread not called yet\n" ); fatal_protocol_error( current, "init_process: init_thread not called yet\n" );
return; return;
} }
if (!(info = current->process->info))
{
fatal_protocol_error( current, "init_process: called twice\n" );
return;
}
current->process->ldt_copy = req->ldt_copy; current->process->ldt_copy = req->ldt_copy;
current->process->ldt_flags = req->ldt_flags; current->process->ldt_flags = req->ldt_flags;
current->process->info = NULL; init_process( req->ppid, req );
req->exe_file = -1;
req->start_flags = info->start_flags;
req->hstdin = info->hstdin;
req->hstdout = info->hstdout;
req->hstderr = info->hstderr;
req->cmd_show = info->cmd_show;
req->env_ptr = info->env_ptr;
strcpy( req->cmdline, info->cmdline );
if (current->process->exe.file)
req->exe_file = alloc_handle( current->process, current->process->exe.file,
GENERIC_READ, 0 );
free( info );
} }
/* signal the end of the process initialization */ /* signal the end of the process initialization */

View File

@ -48,7 +48,6 @@ struct process
struct process_dll exe; /* main exe file */ struct process_dll exe; /* main exe file */
void *ldt_copy; /* pointer to LDT copy in client addr space */ void *ldt_copy; /* pointer to LDT copy in client addr space */
void *ldt_flags; /* pointer to LDT flags in client addr space */ void *ldt_flags; /* pointer to LDT flags in client addr space */
struct new_process_request *info; /* startup info (freed after startup) */
}; };
struct process_snapshot struct process_snapshot
@ -67,9 +66,7 @@ struct module_snapshot
/* process functions */ /* process functions */
extern struct thread *create_process( int fd, struct process *parent, extern struct thread *create_process( int fd );
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

@ -289,7 +289,7 @@ static void master_socket_poll_event( struct object *obj, int event )
struct sockaddr_un dummy; struct sockaddr_un dummy;
int len = sizeof(dummy); int len = sizeof(dummy);
int client = accept( master_socket->obj.fd, (struct sockaddr *) &dummy, &len ); int client = accept( master_socket->obj.fd, (struct sockaddr *) &dummy, &len );
if (client != -1) create_process( client, NULL, NULL, "", 1 ); if (client != -1) create_process( client );
} }
} }

View File

@ -71,6 +71,7 @@ static inline size_t get_req_strlenW( const void *req, const WCHAR *str )
/* ### make_requests begin ### */ /* ### make_requests begin ### */
DECL_HANDLER(new_process); DECL_HANDLER(new_process);
DECL_HANDLER(wait_process);
DECL_HANDLER(new_thread); DECL_HANDLER(new_thread);
DECL_HANDLER(boot_done); DECL_HANDLER(boot_done);
DECL_HANDLER(init_process); DECL_HANDLER(init_process);
@ -179,6 +180,7 @@ typedef void (*req_handler)( void *req );
static const req_handler req_handlers[REQ_NB_REQUESTS] = static const req_handler req_handlers[REQ_NB_REQUESTS] =
{ {
(req_handler)req_new_process, (req_handler)req_new_process,
(req_handler)req_wait_process,
(req_handler)req_new_thread, (req_handler)req_new_thread,
(req_handler)req_boot_done, (req_handler)req_boot_done,
(req_handler)req_init_process, (req_handler)req_init_process,

View File

@ -116,7 +116,7 @@ static int alloc_client_buffer( struct thread *thread )
} }
/* create a new thread */ /* create a new thread */
struct thread *create_thread( int fd, struct process *process, int suspend ) struct thread *create_thread( int fd, struct process *process )
{ {
struct thread *thread; struct thread *thread;
@ -131,6 +131,7 @@ struct thread *create_thread( int fd, struct process *process, int suspend )
thread->mutex = NULL; thread->mutex = NULL;
thread->debug_ctx = NULL; thread->debug_ctx = NULL;
thread->debug_event = NULL; thread->debug_event = NULL;
thread->info = NULL;
thread->wait = NULL; thread->wait = NULL;
thread->apc = NULL; thread->apc = NULL;
thread->apc_count = 0; thread->apc_count = 0;
@ -143,7 +144,7 @@ struct thread *create_thread( int fd, struct process *process, int suspend )
thread->prev = NULL; thread->prev = NULL;
thread->priority = THREAD_PRIORITY_NORMAL; thread->priority = THREAD_PRIORITY_NORMAL;
thread->affinity = 1; thread->affinity = 1;
thread->suspend = (suspend != 0); thread->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 ); thread->process = (struct process *)grab_object( process );
@ -194,6 +195,7 @@ static void destroy_thread( struct object *obj )
if (thread->prev) thread->prev->next = thread->next; if (thread->prev) thread->prev->next = thread->next;
else first_thread = thread->next; else first_thread = thread->next;
if (thread->apc) free( thread->apc ); if (thread->apc) free( thread->apc );
if (thread->info) release_object( thread->info );
if (thread->buffer != (void *)-1) munmap( thread->buffer, MAX_REQUEST_LENGTH ); if (thread->buffer != (void *)-1) munmap( thread->buffer, MAX_REQUEST_LENGTH );
if (thread->pass_fd != -1) close( thread->pass_fd ); if (thread->pass_fd != -1) close( thread->pass_fd );
} }
@ -625,8 +627,9 @@ DECL_HANDLER(new_thread)
if (socketpair( AF_UNIX, SOCK_STREAM, 0, sock ) != -1) if (socketpair( AF_UNIX, SOCK_STREAM, 0, sock ) != -1)
{ {
if ((thread = create_thread( sock[0], current->process, req->suspend ))) if ((thread = create_thread( sock[0], current->process )))
{ {
if (req->suspend) thread->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)

View File

@ -21,6 +21,7 @@ struct thread_apc;
struct mutex; struct mutex;
struct debug_ctx; struct debug_ctx;
struct debug_event; struct debug_event;
struct startup_info;
enum run_state enum run_state
{ {
@ -40,6 +41,7 @@ struct thread
struct mutex *mutex; /* list of currently owned mutexes */ struct mutex *mutex; /* list of currently owned mutexes */
struct debug_ctx *debug_ctx; /* debugger context if this thread is a debugger */ struct debug_ctx *debug_ctx; /* debugger context if this thread is a debugger */
struct debug_event *debug_event; /* debug event being sent to debugger */ struct debug_event *debug_event; /* debug event being sent to debugger */
struct startup_info*info; /* startup info for child process */
struct thread_wait *wait; /* current wait condition if sleeping */ struct thread_wait *wait; /* current wait condition if sleeping */
struct thread_apc *apc; /* list of async procedure calls */ struct thread_apc *apc; /* list of async procedure calls */
int apc_count; /* number of outstanding APCs */ int apc_count; /* number of outstanding APCs */
@ -72,7 +74,7 @@ extern struct thread *current;
/* thread functions */ /* thread functions */
extern struct thread *create_thread( int fd, struct process *process, int suspend ); extern struct thread *create_thread( int fd, struct process *process );
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,8 +215,6 @@ typedef void (*dump_func)( const void *req );
static void dump_new_process_request( const struct new_process_request *req ) static void dump_new_process_request( const struct new_process_request *req )
{ {
fprintf( stderr, " pinherit=%d,", req->pinherit );
fprintf( stderr, " tinherit=%d,", req->tinherit );
fprintf( stderr, " inherit_all=%d,", req->inherit_all ); fprintf( stderr, " inherit_all=%d,", req->inherit_all );
fprintf( stderr, " create_flags=%d,", req->create_flags ); fprintf( stderr, " create_flags=%d,", req->create_flags );
fprintf( stderr, " start_flags=%d,", req->start_flags ); fprintf( stderr, " start_flags=%d,", req->start_flags );
@ -225,12 +223,18 @@ static void dump_new_process_request( const struct new_process_request *req )
fprintf( stderr, " hstdout=%d,", req->hstdout ); fprintf( stderr, " hstdout=%d,", req->hstdout );
fprintf( stderr, " hstderr=%d,", req->hstderr ); fprintf( stderr, " hstderr=%d,", req->hstderr );
fprintf( stderr, " cmd_show=%d,", req->cmd_show ); fprintf( stderr, " cmd_show=%d,", req->cmd_show );
fprintf( stderr, " env_ptr=%p,", req->env_ptr ); fprintf( stderr, " alloc_fd=%d", req->alloc_fd );
fprintf( stderr, " cmdline=" );
dump_string( req, req->cmdline );
} }
static void dump_new_process_reply( const struct new_process_request *req ) static void dump_wait_process_request( const struct wait_process_request *req )
{
fprintf( stderr, " pinherit=%d,", req->pinherit );
fprintf( stderr, " tinherit=%d,", req->tinherit );
fprintf( stderr, " timeout=%d,", req->timeout );
fprintf( stderr, " cancel=%d", req->cancel );
}
static void dump_wait_process_reply( const struct wait_process_request *req )
{ {
fprintf( stderr, " pid=%p,", req->pid ); fprintf( stderr, " pid=%p,", req->pid );
fprintf( stderr, " phandle=%d,", req->phandle ); fprintf( stderr, " phandle=%d,", req->phandle );
@ -259,7 +263,8 @@ static void dump_boot_done_request( const struct boot_done_request *req )
static void dump_init_process_request( const struct init_process_request *req ) static void dump_init_process_request( const struct init_process_request *req )
{ {
fprintf( stderr, " ldt_copy=%p,", req->ldt_copy ); fprintf( stderr, " ldt_copy=%p,", req->ldt_copy );
fprintf( stderr, " ldt_flags=%p", req->ldt_flags ); fprintf( stderr, " ldt_flags=%p,", req->ldt_flags );
fprintf( stderr, " ppid=%d", req->ppid );
} }
static void dump_init_process_reply( const struct init_process_request *req ) static void dump_init_process_reply( const struct init_process_request *req )
@ -269,10 +274,7 @@ static void dump_init_process_reply( const struct init_process_request *req )
fprintf( stderr, " hstdin=%d,", req->hstdin ); fprintf( stderr, " hstdin=%d,", req->hstdin );
fprintf( stderr, " hstdout=%d,", req->hstdout ); fprintf( stderr, " hstdout=%d,", req->hstdout );
fprintf( stderr, " hstderr=%d,", req->hstderr ); fprintf( stderr, " hstderr=%d,", req->hstderr );
fprintf( stderr, " cmd_show=%d,", req->cmd_show ); fprintf( stderr, " cmd_show=%d", req->cmd_show );
fprintf( stderr, " env_ptr=%p,", req->env_ptr );
fprintf( stderr, " cmdline=" );
dump_string( req, req->cmdline );
} }
static void dump_init_process_done_request( const struct init_process_done_request *req ) static void dump_init_process_done_request( const struct init_process_done_request *req )
@ -1326,6 +1328,7 @@ static void dump_get_atom_name_reply( const struct get_atom_name_request *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_wait_process_request,
(dump_func)dump_new_thread_request, (dump_func)dump_new_thread_request,
(dump_func)dump_boot_done_request, (dump_func)dump_boot_done_request,
(dump_func)dump_init_process_request, (dump_func)dump_init_process_request,
@ -1430,7 +1433,8 @@ static const dump_func req_dumpers[REQ_NB_REQUESTS] = {
}; };
static const dump_func reply_dumpers[REQ_NB_REQUESTS] = { static const dump_func reply_dumpers[REQ_NB_REQUESTS] = {
(dump_func)dump_new_process_reply, (dump_func)0,
(dump_func)dump_wait_process_reply,
(dump_func)dump_new_thread_reply, (dump_func)dump_new_thread_reply,
(dump_func)0, (dump_func)0,
(dump_func)dump_init_process_reply, (dump_func)dump_init_process_reply,
@ -1536,6 +1540,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",
"wait_process",
"new_thread", "new_thread",
"boot_done", "boot_done",
"init_process", "init_process",

View File

@ -1533,7 +1533,7 @@ DWORD WINAPI WaitForInputIdle (HANDLE hProcess, DWORD dwTimeOut)
return 0; return 0;
} }
pdb = PROCESS_IdToPDB( pid ); if (!(pdb = PROCESS_IdToPDB( pid ))) return 0;
/* check whether we are waiting for a win32 process or the win16 subsystem */ /* check whether we are waiting for a win32 process or the win16 subsystem */
if ( pdb->flags & PDB32_WIN16_PROC ) { if ( pdb->flags & PDB32_WIN16_PROC ) {