From 5b4f3e8d6de11383a1881ab65da5bd41d4942024 Mon Sep 17 00:00:00 2001 From: Alexandre Julliard Date: Mon, 1 May 2000 16:24:22 +0000 Subject: [PATCH] Rewrote Unix process launching to allow passing startup information to Winelib apps. Improved handling of execve() failures. --- include/process.h | 9 +- include/server.h | 21 ++- include/thread.h | 5 +- loader/main.c | 11 -- loader/module.c | 59 +----- memory/environ.c | 15 +- miscemu/main.c | 13 ++ scheduler/process.c | 428 ++++++++++++++++++++++++++++++++++---------- scheduler/thread.c | 25 ++- server/process.c | 387 ++++++++++++++++++++++++--------------- server/process.h | 5 +- server/request.c | 2 +- server/request.h | 2 + server/thread.c | 9 +- server/thread.h | 4 +- server/trace.c | 29 +-- windows/queue.c | 2 +- 17 files changed, 662 insertions(+), 364 deletions(-) diff --git a/include/process.h b/include/process.h index 341b54cc984..78adfdddbd9 100644 --- a/include/process.h +++ b/include/process.h @@ -148,8 +148,9 @@ extern DWORD WINAPI GetProcessDword( DWORD dwProcessID, INT offset ); void WINAPI SetProcessDword( DWORD dwProcessID, INT offset, DWORD value ); extern DWORD WINAPI MapProcessHandle( HANDLE handle ); -/* scheduler/environ.c */ -extern BOOL ENV_InheritEnvironment( LPCSTR env ); +/* memory/environ.c */ +extern BOOL ENV_BuildEnvironment(void); +extern BOOL ENV_InheritEnvironment( PDB *pdb, LPCSTR env ); extern void ENV_FreeEnvironment( PDB *pdb ); /* scheduler/process.c */ @@ -161,6 +162,10 @@ extern PDB *PROCESS_Create( struct _NE_MODULE *pModule, HFILE hFile, LPSECURITY_ATTRIBUTES psa, LPSECURITY_ATTRIBUTES tsa, BOOL inherit, DWORD flags, 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_WalkProcess( void ); diff --git a/include/server.h b/include/server.h index 72b2442c649..2e5f7f1a43a 100644 --- a/include/server.h +++ b/include/server.h @@ -104,8 +104,6 @@ typedef struct /* Create a new process from the context of the parent */ 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 create_flags; /* creation flags */ IN int start_flags; /* flags from startup info */ @@ -114,13 +112,22 @@ struct new_process_request IN int hstdout; /* handle for stdout */ IN int hstderr; /* handle for stderr */ 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 int phandle; /* process handle (in the current process) */ OUT void* tid; /* thread id */ OUT int thandle; /* thread handle (in the current process) */ 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_flags; /* addr of LDT flags */ + IN int ppid; /* parent Unix pid */ OUT int start_flags; /* flags from startup info */ OUT int exe_file; /* file handle for main exe */ OUT int hstdin; /* handle for stdin */ OUT int hstdout; /* handle for stdout */ OUT int hstderr; /* handle for stderr */ 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 { REQ_NEW_PROCESS, + REQ_WAIT_PROCESS, REQ_NEW_THREAD, REQ_BOOT_DONE, REQ_INIT_PROCESS, @@ -1246,7 +1253,7 @@ enum request REQ_NB_REQUESTS }; -#define SERVER_PROTOCOL_VERSION 9 +#define SERVER_PROTOCOL_VERSION 10 /* ### make_requests end ### */ /* Everything above this line is generated automatically by tools/make_requests */ diff --git a/include/thread.h b/include/thread.h index 0c709c036f2..596dae63655 100644 --- a/include/thread.h +++ b/include/thread.h @@ -119,9 +119,8 @@ typedef struct _TEB /* scheduler/thread.c */ -extern TEB *THREAD_CreateInitialThread( struct _PDB *pdb, int server_fd ); -extern TEB *THREAD_Create( struct _PDB *pdb, void *pid, void *tid, int fd, - DWORD stack_size, BOOL alloc_stack16 ); +extern TEB *THREAD_Init( struct _PDB *pdb ); +extern TEB *THREAD_Create( struct _PDB *pdb, int fd, 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 TEB *THREAD_IdToTEB( DWORD id ); diff --git a/loader/main.c b/loader/main.c index 1fb3b91308d..a036a08e430 100644 --- a/loader/main.c +++ b/loader/main.c @@ -62,8 +62,6 @@ DEFAULT_DEBUG_CHANNEL(server); */ BOOL MAIN_MainInit( int argc, char *argv[], BOOL win32 ) { - char szGraphicsDriver[MAX_PATH]; - /* store the program name */ argv0 = argv[0]; @@ -94,15 +92,6 @@ BOOL MAIN_MainInit( int argc, char *argv[], BOOL win32 ) /* Initialize module loadorder */ 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; } diff --git a/loader/module.c b/loader/module.c index 79ff9bb79d4..65a9624ac96 100644 --- a/loader/module.c +++ b/loader/module.c @@ -684,60 +684,6 @@ BOOL WINAPI GetBinaryTypeW( LPCWSTR lpApplicationName, LPDWORD lpBinaryType ) 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) @@ -1027,7 +973,10 @@ BOOL WINAPI CreateProcessA( LPCSTR lpApplicationName, LPSTR lpCommandLine, { CloseHandle( hFile ); /* 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; } diff --git a/memory/environ.c b/memory/environ.c index a41f0e51150..2fa96b32065 100644 --- a/memory/environ.c +++ b/memory/environ.c @@ -67,7 +67,7 @@ static LPCSTR ENV_FindVariable( LPCSTR env, LPCSTR name, INT len ) * * Build the environment for the initial process */ -static BOOL ENV_BuildEnvironment( PDB *pdb ) +BOOL ENV_BuildEnvironment(void) { extern char **environ; LPSTR p, *e; @@ -81,7 +81,7 @@ static BOOL ENV_BuildEnvironment( PDB *pdb ) /* Now allocate the environment */ 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 */ @@ -104,20 +104,11 @@ static BOOL ENV_BuildEnvironment( PDB *pdb ) * Make a process inherit the environment from its parent or from an * explicit environment. */ -BOOL ENV_InheritEnvironment( LPCSTR env ) +BOOL ENV_InheritEnvironment( PDB *pdb, LPCSTR env ) { DWORD size; LPCSTR src; 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 */ diff --git a/miscemu/main.c b/miscemu/main.c index e4bdd3d824b..3b15e1806b1 100644 --- a/miscemu/main.c +++ b/miscemu/main.c @@ -42,6 +42,13 @@ void MAIN_EmulatorRun( void ) char startProg[256], defProg[256]; int i, tasks = 0; 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) */ if ( !LoadLibrary16("GDI.EXE" ) || !LoadLibraryA("GDI32.DLL" ) @@ -102,6 +109,12 @@ int main( int argc, char *argv[] ) /* Initialize everything */ 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 */ if ( !(pModule = NE_GetPtr( GetModuleHandle16( "KERNEL" ) )) ) return 1; if ( !TASK_Create( pModule, FALSE ) ) return 1; diff --git a/scheduler/process.c b/scheduler/process.c index b7cd744828c..8bdf146bb0f 100644 --- a/scheduler/process.c +++ b/scheduler/process.c @@ -5,6 +5,8 @@ */ #include +#include +#include #include #include #include @@ -43,31 +45,6 @@ static STARTUPINFOA initial_startup; 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 * @@ -210,27 +187,15 @@ void PROCESS_CallUserSignalProc( UINT uCode, HMODULE hModule ) static BOOL PROCESS_CreateEnvDB(void) { struct init_process_request *req = get_req_buffer(); - STARTUPINFOA *startup; - ENVDB *env_db; - char cmd_line[4096]; PDB *pdb = PROCESS_Current(); - - /* Allocate the env DB */ - - 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; + ENVDB *env_db = pdb->env_db; + STARTUPINFOA *startup = env_db->startup_info; /* Retrieve startup info from the server */ req->ldt_copy = ldt_copy; req->ldt_flags = ldt_flags_copy; + req->ppid = getppid(); if (server_call( REQ_INIT_PROCESS )) return FALSE; pdb->exe_file = req->exe_file; startup->dwFlags = req->start_flags; @@ -238,16 +203,6 @@ static BOOL PROCESS_CreateEnvDB(void) env_db->hStdin = startup->hStdInput = req->hstdin; env_db->hStdout = startup->hStdOutput = req->hstdout; 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; } @@ -277,7 +232,8 @@ void PROCESS_FreePDB( PDB *pdb ) */ 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; pdb->exit_code = STILL_ACTIVE; @@ -291,6 +247,11 @@ static PDB *PROCESS_CreatePDB( PDB *parent, BOOL inherit ) pdb->next = PROCESS_First; pdb->winver = 0xffff; /* to be determined */ 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; return pdb; } @@ -303,10 +264,6 @@ BOOL PROCESS_Init( BOOL win32 ) { struct init_process_request *req; TEB *teb; - int server_fd; - - /* Start the server */ - server_fd = CLIENT_InitServer(); /* Fill the initial process structure */ initial_pdb.exit_code = STILL_ACTIVE; @@ -320,12 +277,31 @@ BOOL PROCESS_Init( BOOL win32 ) initial_pdb.winver = 0xffff; /* to be determined */ initial_pdb.main_queue = INVALID_HANDLE_VALUE16; 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 */ if (!VIRTUAL_Init()) return FALSE; - /* Create the initial thread structure and socket pair */ - if (!(teb = THREAD_CreateInitialThread( &initial_pdb, server_fd ))) return FALSE; + /* Retrieve startup info from the server */ + 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 */ 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 = 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 */ - if (!ENV_InheritEnvironment( NULL )) return FALSE; + if (!ENV_BuildEnvironment()) return FALSE; /* Create the SEGPTR heap */ 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 * @@ -409,13 +396,8 @@ static void start_process(void) if (pdb->flags & PDB32_CONSOLE_PROC) AllocConsole(); - /* Load system DLLs into the initial process (and initialize them) */ - if (!LoadLibraryA( "KERNEL32" )) goto error; - if (!LoadLibraryA( "x11drv" )) goto error; - - if ( !LoadLibrary16("GDI.EXE" ) || !LoadLibraryA("GDI32.DLL" ) - || !LoadLibrary16("USER.EXE") || !LoadLibraryA("USER32.DLL")) - goto error; + /* Load the system dlls */ + if (!load_system_dlls()) goto error; /* Get pointers to USER routines called by KERNEL */ 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 * @@ -691,6 +917,7 @@ PDB *PROCESS_Create( NE_MODULE *pModule, HFILE hFile, LPCSTR cmd_line, LPCSTR en BOOL alloc_stack16; int fd = -1; struct new_process_request *req = get_req_buffer(); + struct wait_process_request *wait_req = get_req_buffer(); TEB *teb = NULL; PDB *parent = PROCESS_Current(); 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; 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 */ - 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->create_flags = flags; 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->cmd_show = startup->wShowWindow; - req->env_ptr = (void*)env; /* FIXME: hack */ - lstrcpynA( req->cmdline, cmd_line, server_remaining(req->cmdline) ); + req->alloc_fd = 1; 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 */ { @@ -752,13 +973,26 @@ PDB *PROCESS_Create( NE_MODULE *pModule, HFILE hFile, LPCSTR cmd_line, LPCSTR en /* Create the main thread */ - if (!(teb = THREAD_Create( pdb, req->pid, req->tid, fd, size, alloc_stack16 ))) goto error; - teb->startup = PROCESS_Start; - fd = -1; /* don't close it */ + if ((teb = THREAD_Create( pdb, fd, size, alloc_stack16 ))) + { + teb->startup = PROCESS_Start; + fd = -1; /* don't close it */ - /* Pass module to new process (FIXME: hack) */ - pdb->module = pModule->self; - SYSDEPS_SpawnThread( teb ); + /* Pass module to new process (FIXME: hack) */ + pdb->module = pModule->self; + 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) */ handles[0] = info->hProcess; diff --git a/scheduler/thread.c b/scheduler/thread.c index 046ae0438fd..3e541ac434f 100644 --- a/scheduler/thread.c +++ b/scheduler/thread.c @@ -85,6 +85,8 @@ static BOOL THREAD_InitTEB( TEB *teb, PDB *pdb ) teb->process = pdb; teb->exit_code = STILL_ACTIVE; teb->socket = -1; + teb->stack_top = (void *)~0UL; + teb->StaticUnicodeString.MaximumLength = sizeof(teb->StaticUnicodeBuffer); teb->StaticUnicodeString.Buffer = (PWSTR)teb->StaticUnicodeBuffer; 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. */ -TEB *THREAD_CreateInitialThread( PDB *pdb, int server_fd ) +TEB *THREAD_Init( struct _PDB *pdb ) { if (!THREAD_InitTEB( &initial_teb, pdb )) return NULL; SYSDEPS_SetCurThread( &initial_teb ); - initial_teb.socket = server_fd; - - if (CLIENT_InitThread()) return NULL; - return THREAD_InitStack( &initial_teb, pdb, 0, TRUE ); + return &initial_teb; } @@ -215,15 +214,12 @@ TEB *THREAD_CreateInitialThread( PDB *pdb, int server_fd ) * THREAD_Create * */ -TEB *THREAD_Create( PDB *pdb, void *pid, void *tid, int fd, - DWORD stack_size, BOOL alloc_stack16 ) +TEB *THREAD_Create( PDB *pdb, int fd, DWORD stack_size, BOOL alloc_stack16 ) { TEB *teb; if ((teb = THREAD_InitStack( NULL, pdb, stack_size, alloc_stack16 ))) { - teb->pid = pid; - teb->tid = tid; teb->socket = fd; fcntl( fd, F_SETFD, 1 ); /* set close on exec flag */ 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(); int socket, handle = -1; TEB *teb; + void *tid; req->suspend = ((flags & CREATE_SUSPENDED) != 0); req->inherit = (sa && (sa->nLength>=sizeof(*sa)) && sa->bInheritHandle); if (server_call_fd( REQ_NEW_THREAD, -1, &socket )) return 0; handle = req->handle; + tid = req->tid; - if (!(teb = THREAD_Create( PROCESS_Current(), (void *)GetCurrentProcessId(), - req->tid, socket, stack, TRUE ))) + if (!(teb = THREAD_Create( PROCESS_Current(), socket, stack, TRUE ))) { close( socket ); return 0; @@ -282,7 +279,7 @@ HANDLE WINAPI CreateThread( SECURITY_ATTRIBUTES *sa, DWORD stack, teb->entry_point = start; teb->entry_arg = param; teb->startup = THREAD_Start; - if (id) *id = (DWORD)teb->tid; + if (id) *id = (DWORD)tid; if (SYSDEPS_SpawnThread( teb ) == -1) { CloseHandle( handle ); diff --git a/server/process.c b/server/process.c index c84672d2d67..57825e8684c 100644 --- a/server/process.c +++ b/server/process.c @@ -55,47 +55,54 @@ static const struct object_ops process_ops = process_destroy /* destroy */ }; -/* set the process creation info */ -static int set_creation_info( struct process *process, struct new_process_request *req, - const char *cmd_line, size_t len ) +/* process startup info */ + +struct startup_info { - 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->pinherit = 0; - req->tinherit = 0; - req->inherit_all = 0; - req->create_flags = CREATE_NEW_CONSOLE; - req->start_flags = STARTF_USESTDHANDLES; - req->exe_file = -1; - req->hstdin = -1; - req->hstdout = -1; - req->hstderr = -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; -} + struct object obj; /* object header */ + int inherit_all; /* inherit all handles from parent */ + int create_flags; /* creation flags */ + int start_flags; /* flags from startup info */ + int exe_file; /* file handle for main exe */ + int hstdin; /* handle for stdin */ + int hstdout; /* handle for stdout */ + int hstderr; /* handle for stderr */ + int cmd_show; /* main window show mode */ + struct process *process; /* created process */ + struct thread *thread; /* created thread */ +}; + +static void startup_info_dump( struct object *obj, int verbose ); +static int startup_info_signaled( struct object *obj, struct thread *thread ); +static void startup_info_destroy( struct object *obj ); + +static const struct object_ops startup_info_ops = +{ + sizeof(struct startup_info), /* size */ + startup_info_dump, /* dump */ + add_queue, /* add_queue */ + remove_queue, /* remove_queue */ + startup_info_signaled, /* signaled */ + 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 */ -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 (!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_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)) { /* 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 ); + req->hstdin = duplicate_handle( parent, info->hstdin, process, + 0, TRUE, DUPLICATE_SAME_ACCESS ); + req->hstdout = duplicate_handle( parent, info->hstdout, process, + 0, TRUE, DUPLICATE_SAME_ACCESS ); + req->hstderr = duplicate_handle( parent, info->hstderr, process, + 0, TRUE, DUPLICATE_SAME_ACCESS ); + } + else + { + req->hstdin = info->hstdin; + req->hstdout = info->hstdout; + req->hstderr = info->hstderr; } } 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 ); + req->hstdin = alloc_handle( process, process->console_in, + GENERIC_READ | GENERIC_WRITE | SYNCHRONIZE, 1 ); + req->hstdout = alloc_handle( process, process->console_out, + GENERIC_READ | GENERIC_WRITE | SYNCHRONIZE, 1 ); + req->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 thread *create_process( int fd ) { struct process *process; struct thread *thread = NULL; @@ -153,7 +164,6 @@ struct thread *create_process( int fd, struct process *parent, process->console_in = NULL; process->console_out = NULL; process->init_event = NULL; - process->info = NULL; process->ldt_copy = NULL; process->ldt_flags = 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; 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 */ - if (!(thread = create_thread( fd, process, (process->create_flags & CREATE_SUSPENDED) != 0))) - goto error; + if (!(thread = create_thread( fd, process ))) goto error; /* create the init done event */ 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 ); release_object( process ); return thread; error: - close( fd ); - free_console( process ); - if (process->handles) release_object( process->handles ); if (thread) release_object( thread ); release_object( process ); 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 */ 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->prev) process->prev->next = process->next; else first_process = process->next; - if (process->info) free( process->info ); if (process->init_event) release_object( process->init_event ); 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) */ struct process *get_process_from_id( void *id ) { @@ -314,7 +419,7 @@ static void process_killed( struct process *process ) { assert( !process->thread_list ); gettimeofday( &process->end_time, NULL ); - release_object( process->handles ); + if (process->handles) release_object( process->handles ); process->handles = NULL; free_console( process ); while (process->exe.next) @@ -594,83 +699,83 @@ struct module_snapshot *module_snap( struct process *process, int *count ) /* create a new process */ DECL_HANDLER(new_process) { - size_t len = get_req_strlen( req, req->cmdline ); - struct thread *thread; + struct startup_info *info; int sock[2]; - int event = -1, phandle = -1; - req->phandle = -1; - req->thandle = -1; - req->event = -1; - req->pid = NULL; - req->tid = NULL; - - if (socketpair( AF_UNIX, SOCK_STREAM, 0, sock ) == -1) + if (current->info) { - file_set_error(); + fatal_protocol_error( current, "new_process: another process is being created\n" ); return; } - if (!(thread = create_process( sock[0], current->process, req, req->cmdline, len ))) - goto error; + /* build the startup info for a new process */ + 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, - EVENT_ALL_ACCESS, 0 )) == -1) - goto error; + if (req->alloc_fd) + { + 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, - PROCESS_ALL_ACCESS, req->pinherit )) == -1) - goto error; - - if ((req->thandle = alloc_handle( current->process, thread, - THREAD_ALL_ACCESS, req->tinherit )) == -1) - goto error; - - /* thread object will be released when the thread gets killed */ - set_reply_fd( current, sock[1] ); - req->pid = get_process_id( thread->process ); - req->tid = get_thread_id( thread ); - req->phandle = phandle; - req->event = event; - return; - - error: - if (phandle != -1) close_handle( current->process, phandle ); - if (event != -1) close_handle( current->process, event ); - if (thread) release_object( thread ); - close( sock[1] ); +/* Wait for the new process to start */ +DECL_HANDLER(wait_process) +{ + if (!current->info) + { + fatal_protocol_error( current, "wait_process: no process is being created\n" ); + return; + } + req->pid = 0; + req->tid = 0; + req->phandle = -1; + req->thandle = -1; + if (req->cancel) + { + release_object( current->info ); + current->info = NULL; + } + else + { + struct object *obj = ¤t->info->obj; + sleep_on( 1, &obj, SELECT_TIMEOUT, req->timeout, build_wait_process_reply ); + } } /* initialize a new process */ DECL_HANDLER(init_process) { - struct new_process_request *info; - if (!current->unix_pid) { fatal_protocol_error( current, "init_process: init_thread not called yet\n" ); 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_flags = req->ldt_flags; - current->process->info = NULL; - 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 ); + init_process( req->ppid, req ); } /* signal the end of the process initialization */ diff --git a/server/process.h b/server/process.h index 6e98a4792af..ae606a58591 100644 --- a/server/process.h +++ b/server/process.h @@ -48,7 +48,6 @@ struct process struct process_dll exe; /* main exe file */ void *ldt_copy; /* pointer to LDT copy 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 @@ -67,9 +66,7 @@ struct module_snapshot /* process functions */ -extern struct thread *create_process( int fd, struct process *parent, - struct new_process_request *req, - const char *cmd_line, size_t len ); +extern struct thread *create_process( int fd ); extern struct process *get_process_from_id( void *id ); extern struct process *get_process_from_handle( int handle, unsigned int access ); extern int process_set_debugger( struct process *process, struct thread *thread ); diff --git a/server/request.c b/server/request.c index dcb754359c1..cea639b57c6 100644 --- a/server/request.c +++ b/server/request.c @@ -289,7 +289,7 @@ static void master_socket_poll_event( struct object *obj, int event ) struct sockaddr_un dummy; int len = sizeof(dummy); 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 ); } } diff --git a/server/request.h b/server/request.h index c7b970b35fb..f87b4f5a129 100644 --- a/server/request.h +++ b/server/request.h @@ -71,6 +71,7 @@ static inline size_t get_req_strlenW( const void *req, const WCHAR *str ) /* ### make_requests begin ### */ DECL_HANDLER(new_process); +DECL_HANDLER(wait_process); DECL_HANDLER(new_thread); DECL_HANDLER(boot_done); DECL_HANDLER(init_process); @@ -179,6 +180,7 @@ typedef void (*req_handler)( void *req ); static const req_handler req_handlers[REQ_NB_REQUESTS] = { (req_handler)req_new_process, + (req_handler)req_wait_process, (req_handler)req_new_thread, (req_handler)req_boot_done, (req_handler)req_init_process, diff --git a/server/thread.c b/server/thread.c index eeedd2bf0a1..f98982daa81 100644 --- a/server/thread.c +++ b/server/thread.c @@ -116,7 +116,7 @@ static int alloc_client_buffer( struct thread *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; @@ -131,6 +131,7 @@ struct thread *create_thread( int fd, struct process *process, int suspend ) thread->mutex = NULL; thread->debug_ctx = NULL; thread->debug_event = NULL; + thread->info = NULL; thread->wait = NULL; thread->apc = NULL; thread->apc_count = 0; @@ -143,7 +144,7 @@ struct thread *create_thread( int fd, struct process *process, int suspend ) thread->prev = NULL; thread->priority = THREAD_PRIORITY_NORMAL; thread->affinity = 1; - thread->suspend = (suspend != 0); + thread->suspend = 0; thread->buffer = (void *)-1; thread->last_req = REQ_GET_THREAD_BUFFER; 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; else first_thread = thread->next; 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->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 ((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; if ((req->handle = alloc_handle( current->process, thread, THREAD_ALL_ACCESS, req->inherit )) != -1) diff --git a/server/thread.h b/server/thread.h index 6f836dc35bb..3340d5ee938 100644 --- a/server/thread.h +++ b/server/thread.h @@ -21,6 +21,7 @@ struct thread_apc; struct mutex; struct debug_ctx; struct debug_event; +struct startup_info; enum run_state { @@ -40,6 +41,7 @@ struct thread struct mutex *mutex; /* list of currently owned mutexes */ 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 startup_info*info; /* startup info for child process */ struct thread_wait *wait; /* current wait condition if sleeping */ struct thread_apc *apc; /* list of async procedure calls */ int apc_count; /* number of outstanding APCs */ @@ -72,7 +74,7 @@ extern struct thread *current; /* 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_handle( int handle, unsigned int access ); extern struct thread *get_thread_from_pid( int pid ); diff --git a/server/trace.c b/server/trace.c index 66b48bd0e89..1fca5cd0f22 100644 --- a/server/trace.c +++ b/server/trace.c @@ -215,8 +215,6 @@ typedef void (*dump_func)( const void *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, " create_flags=%d,", req->create_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, " hstderr=%d,", req->hstderr ); fprintf( stderr, " cmd_show=%d,", req->cmd_show ); - fprintf( stderr, " env_ptr=%p,", req->env_ptr ); - fprintf( stderr, " cmdline=" ); - dump_string( req, req->cmdline ); + fprintf( stderr, " alloc_fd=%d", req->alloc_fd ); } -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, " 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 ) { 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 ) @@ -269,10 +274,7 @@ static void dump_init_process_reply( const struct init_process_request *req ) fprintf( stderr, " hstdin=%d,", req->hstdin ); fprintf( stderr, " hstdout=%d,", req->hstdout ); fprintf( stderr, " hstderr=%d,", req->hstderr ); - fprintf( stderr, " cmd_show=%d,", req->cmd_show ); - fprintf( stderr, " env_ptr=%p,", req->env_ptr ); - fprintf( stderr, " cmdline=" ); - dump_string( req, req->cmdline ); + fprintf( stderr, " cmd_show=%d", req->cmd_show ); } 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] = { (dump_func)dump_new_process_request, + (dump_func)dump_wait_process_request, (dump_func)dump_new_thread_request, (dump_func)dump_boot_done_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] = { - (dump_func)dump_new_process_reply, + (dump_func)0, + (dump_func)dump_wait_process_reply, (dump_func)dump_new_thread_reply, (dump_func)0, (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] = { "new_process", + "wait_process", "new_thread", "boot_done", "init_process", diff --git a/windows/queue.c b/windows/queue.c index 4cbc329f4f7..34249e1c5c5 100644 --- a/windows/queue.c +++ b/windows/queue.c @@ -1533,7 +1533,7 @@ DWORD WINAPI WaitForInputIdle (HANDLE hProcess, DWORD dwTimeOut) 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 */ if ( pdb->flags & PDB32_WIN16_PROC ) {