* sigproc.cc (mychild): Reimplement as list scan.
(proc_subproc): Don't mess with pinfo if it's myself. * child_info.h (child_info_types): Label enum for _PROC constants. (child_info::child_info): New constructor. (child_info::~child_info): New destructor. (child_info::sync): Declare new function. (child_info_fork::child_info_fork): New constructor. (child_info_spawn::child_info_spawn): Remove old constructor. (child_info_spawn::child_info_spawn): New constructor. * dcrt0.cc (dll_crt0_0): Use correct sizeof when doing sanity check on passed in child_info. Signal readiness to parent when not forking (and not spawning). * fork.cc (sync_with_child): Delete. (resume_child): Remove extra argument. (sync_with_parent): Use child_info method to sync with parent. (fork_child): Don't close fork_info->subproc_ready since that is now handled by the destructor. (fork_parent): Remove subproc_ready stuff. Use child_info sync method for waiting.. Set start time here for child. Rename "forked" to "child". (fork): Check ch.subproc_ready for validity here. * pinfo.h (_pinfo::exec_sendsig): Temp storage for exec stub which may be staying around to handle non-cygwin captive process. (_pinfo::exec_dwProcessId): Ditto. (_pinfo::_lock): Renamed from lock. (_pinfo::lock): New method. (_pinfo::unlock): Ditto. (_pinfo::initialize_lock): Ditto. * pinfo.cc (set_myself): Use initialize_lock method to initialize myself lock. Set "exec" fields in _pinfo to zero to indicate that we've started successfully. Set start time here when appropriate. (_pinfo::commune_send): Use pinfo lock/unlock methods. (proc_waiter): Remove special case for non-cywin processes. Reinstitute handling for PID_NOCLDSTOP. * sigproc.cc (proc_subproc): Set proper EAGAIN errno when process table is filled. (sig_send): Use exec_* fields from _pinfo for sending signals if the the _pinfo sendsig never materializes. (child_info::child_info): New constructor, renamed from init_child_info. Zeroes child_info structure and sets appropriate fields in structure based on chtype. (child_info::~child_info): New destructor. Closes subproc_ready if it exists. (child_info_fork::child_info_fork): New constructor. (child_info_spawn::child_info_spawn): New constructor. (child_info::ready): New function. Signals parent when child is ready. (child_info::sync): New function. Wait for child to signal us or process to die. (remove_proc): Remove closing of hProcess since this should now be handled shortly after process creation. * spawn.cc (spawn_guts): Use child_info_spawn constructor rather than init_child_info. Save exec_sendsig and exec_dwProcessId in execing _pinfo. Rely on child_info constructor to properly set parent_wr_proc_pipe in ciresrv. Revert to previous determination on whether to start a process in suspended mode. Remove reparenting stuff. Just keep a stub around if starting a non-cygwin process.
This commit is contained in:
@@ -372,17 +372,15 @@ spawn_guts (const char * prog_arg, const char *const *argv,
|
||||
|
||||
STARTUPINFO si = {0, NULL, NULL, NULL, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, NULL, NULL, NULL, NULL};
|
||||
|
||||
child_info_spawn ciresrv;
|
||||
si.lpReserved2 = (LPBYTE) &ciresrv;
|
||||
si.cbReserved2 = sizeof (ciresrv);
|
||||
|
||||
DWORD chtype;
|
||||
child_info_types chtype;
|
||||
if (mode != _P_OVERLAY)
|
||||
chtype = PROC_SPAWN;
|
||||
else
|
||||
chtype = PROC_EXEC;
|
||||
|
||||
init_child_info (chtype, &ciresrv, NULL);
|
||||
child_info_spawn ciresrv (chtype);
|
||||
si.lpReserved2 = (LPBYTE) &ciresrv;
|
||||
si.cbReserved2 = sizeof (ciresrv);
|
||||
|
||||
ciresrv.moreinfo = (cygheap_exec_info *) ccalloc (HEAP_1_EXEC, 1, sizeof (cygheap_exec_info));
|
||||
ciresrv.moreinfo->old_title = NULL;
|
||||
@@ -616,16 +614,21 @@ spawn_guts (const char * prog_arg, const char *const *argv,
|
||||
if (mode == _P_DETACH || !set_console_state_for_spawn ())
|
||||
flags |= DETACHED_PROCESS;
|
||||
|
||||
HANDLE saved_sendsig;
|
||||
bool reset_sendsig = false;
|
||||
if (mode != _P_OVERLAY)
|
||||
saved_sendsig = NULL;
|
||||
myself->exec_sendsig = NULL;
|
||||
else
|
||||
{
|
||||
/* Reset sendsig so that any process which wants to send a signal
|
||||
to this pid will wait for the new process to become active.
|
||||
Save the old value in case the exec fails. */
|
||||
saved_sendsig = myself->sendsig;
|
||||
myself->sendsig = INVALID_HANDLE_VALUE;
|
||||
if (!myself->exec_sendsig)
|
||||
{
|
||||
myself->exec_sendsig = myself->sendsig;
|
||||
myself->exec_dwProcessId = myself->dwProcessId;
|
||||
myself->sendsig = NULL;
|
||||
reset_sendsig = true;
|
||||
}
|
||||
/* Save a copy of a handle to the current process around the first time we
|
||||
exec so that the pid will not be reused. Why did I stop cygwin from
|
||||
generating its own pids again? */
|
||||
@@ -636,15 +639,13 @@ spawn_guts (const char * prog_arg, const char *const *argv,
|
||||
ProtectHandle (cygheap->pid_handle);
|
||||
else
|
||||
system_printf ("duplicate to pid_handle failed, %E");
|
||||
ciresrv.parent_wr_proc_pipe = myself->wr_proc_pipe;
|
||||
}
|
||||
|
||||
/* Start the process in a suspended state. Needed so that any potential parent will
|
||||
be able to take notice of the new "execed" process. This is only really needed
|
||||
to handle exec'ed windows processes since cygwin processes are smart enough that
|
||||
the parent doesn't have to bother but what are you gonna do? Cygwin lives in
|
||||
a windows world. */
|
||||
if (mode != _P_OVERLAY || !real_path.iscygexec ())
|
||||
/* Some file types (currently only sockets) need extra effort in the parent
|
||||
after CreateProcess and before copying the datastructures to the child.
|
||||
So we have to start the child in suspend state, unfortunately, to avoid
|
||||
a race condition. */
|
||||
if (mode != _P_OVERLAY || cygheap->fdtab.need_fixup_before ())
|
||||
flags |= CREATE_SUSPENDED;
|
||||
|
||||
const char *runpath = null_app_name ? NULL : (const char *) real_path;
|
||||
@@ -739,8 +740,11 @@ spawn_guts (const char * prog_arg, const char *const *argv,
|
||||
__seterrno ();
|
||||
syscall_printf ("CreateProcess failed, %E");
|
||||
/* If this was a failed exec, restore the saved sendsig. */
|
||||
if (saved_sendsig)
|
||||
myself->sendsig = saved_sendsig;
|
||||
if (reset_sendsig)
|
||||
{
|
||||
myself->sendsig = myself->exec_sendsig;
|
||||
myself->exec_sendsig = NULL;
|
||||
}
|
||||
cygheap_setup_for_child_cleanup (newheap, &ciresrv, 0);
|
||||
return -1;
|
||||
}
|
||||
@@ -780,41 +784,32 @@ spawn_guts (const char * prog_arg, const char *const *argv,
|
||||
rc ? cygpid : (unsigned int) -1, prog_arg, one_line.buf);
|
||||
|
||||
/* Name the handle similarly to proc_subproc. */
|
||||
ProtectHandle1 (pi.hProcess, childhProc);
|
||||
ProtectHandle (pi.hProcess);
|
||||
|
||||
int wait_for_myself = false;
|
||||
DWORD exec_cygstarted;
|
||||
bool wait_for_myself = false;
|
||||
if (mode == _P_OVERLAY)
|
||||
{
|
||||
if (!real_path.iscygexec ())
|
||||
{
|
||||
/* Store the old exec_cygstarted since this is used as a crude semaphore for
|
||||
detecting when the parent has noticed the change in windows pid for this
|
||||
cygwin pid. */
|
||||
exec_cygstarted = myself->cygstarted;
|
||||
myself->dwProcessId = dwExeced = pi.dwProcessId; /* Reparenting needs this */
|
||||
myself.alert_parent (__ALERT_REPARENT);
|
||||
}
|
||||
CloseHandle (saved_sendsig);
|
||||
myself->dwProcessId = dwExeced = pi.dwProcessId;
|
||||
strace.execing = 1;
|
||||
hExeced = pi.hProcess;
|
||||
myself.hProcess = hExeced = pi.hProcess;
|
||||
strcpy (myself->progname, real_path); // FIXME: race?
|
||||
sigproc_printf ("new process name %s", myself->progname);
|
||||
close_all_files ();
|
||||
/* If wr_proc_pipe is NULL then this process was not started by a cygwin
|
||||
process. So, we need to wait around until the process we've just "execed"
|
||||
dies. Use our own wait facility to wait for our own pid to exit (there
|
||||
is some minor special case code in proc_waiter and friends to accommodate
|
||||
this). */
|
||||
/* If wr_proc_pipe doesn't exist then this process was not started by a cygwin
|
||||
process. So, we need to wait around until the process we've just "execed"
|
||||
dies. Use our own wait facility to wait for our own pid to exit (there
|
||||
is some minor special case code in proc_waiter and friends to accommodeate
|
||||
this). */
|
||||
if (!myself->wr_proc_pipe)
|
||||
{
|
||||
myself.hProcess = pi.hProcess;
|
||||
myself.remember ();
|
||||
wait_for_myself = true;
|
||||
}
|
||||
{
|
||||
myself.hProcess = pi.hProcess;
|
||||
myself.remember ();
|
||||
wait_for_myself = true;
|
||||
myself->wr_proc_pipe = INVALID_HANDLE_VALUE;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
exec_cygstarted = 0;
|
||||
myself->set_has_pgid_children ();
|
||||
ProtectHandle (pi.hThread);
|
||||
pinfo child (cygpid, PID_IN_USE);
|
||||
@@ -830,8 +825,9 @@ spawn_guts (const char * prog_arg, const char *const *argv,
|
||||
child.hProcess = pi.hProcess;
|
||||
if (!child.remember ())
|
||||
{
|
||||
syscall_printf ("process table full");
|
||||
set_errno (EAGAIN);
|
||||
/* FIXME: Child in strange state now. */
|
||||
CloseHandle (pi.hProcess);
|
||||
CloseHandle (pi.hThread);
|
||||
res = -1;
|
||||
goto out;
|
||||
}
|
||||
@@ -844,222 +840,217 @@ spawn_guts (const char * prog_arg, const char *const *argv,
|
||||
However, we should try to find another way to do this eventually. */
|
||||
(void) DuplicateHandle (hMainProc, child.shared_handle (), pi.hProcess,
|
||||
NULL, 0, 0, DUPLICATE_SAME_ACCESS);
|
||||
child->start_time = time (NULL); /* Register child's starting time. */
|
||||
}
|
||||
|
||||
/* Start the child running */
|
||||
if (flags & CREATE_SUSPENDED)
|
||||
ResumeThread (pi.hThread);
|
||||
ForceCloseHandle (pi.hThread);
|
||||
// ForceCloseHandle (pi.hProcess); // handled by proc_subproc and friends
|
||||
/* Start the child running */
|
||||
if (flags & CREATE_SUSPENDED)
|
||||
ResumeThread (pi.hThread);
|
||||
ForceCloseHandle (pi.hThread);
|
||||
|
||||
sigproc_printf ("spawned windows pid %d", pi.dwProcessId);
|
||||
sigproc_printf ("spawned windows pid %d", pi.dwProcessId);
|
||||
|
||||
if (wait_for_myself)
|
||||
waitpid (myself->pid, &res, 0);
|
||||
else
|
||||
{
|
||||
/* Loop, waiting for parent to notice pid change, if exec_cygstarted.
|
||||
In theory this wait should usually be a no-op. */
|
||||
if (exec_cygstarted)
|
||||
while (myself->cygstarted == exec_cygstarted && myself.parent_alive ())
|
||||
low_priority_sleep (0);
|
||||
res = 42;
|
||||
}
|
||||
if (wait_for_myself)
|
||||
waitpid (myself->pid, &res, 0);
|
||||
else
|
||||
ciresrv.sync (myself, INFINITE);
|
||||
|
||||
switch (mode)
|
||||
{
|
||||
case _P_OVERLAY:
|
||||
myself->exit (res, 1);
|
||||
break;
|
||||
case _P_WAIT:
|
||||
case _P_SYSTEM:
|
||||
if (waitpid (cygpid, (int *) &res, 0) != cygpid)
|
||||
res = -1;
|
||||
break;
|
||||
case _P_DETACH:
|
||||
res = 0; /* Lose all memory of this child. */
|
||||
break;
|
||||
case _P_NOWAIT:
|
||||
case _P_NOWAITO:
|
||||
case _P_VFORK:
|
||||
res = cygpid;
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
ForceCloseHandle (pi.hProcess);
|
||||
|
||||
switch (mode)
|
||||
{
|
||||
case _P_OVERLAY:
|
||||
myself->exit (res, 1);
|
||||
break;
|
||||
case _P_WAIT:
|
||||
case _P_SYSTEM:
|
||||
if (waitpid (cygpid, (int *) &res, 0) != cygpid)
|
||||
res = -1;
|
||||
break;
|
||||
case _P_DETACH:
|
||||
res = 0; /* Lose all memory of this child. */
|
||||
break;
|
||||
case _P_NOWAIT:
|
||||
case _P_NOWAITO:
|
||||
case _P_VFORK:
|
||||
res = cygpid;
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
out:
|
||||
pthread_cleanup_pop (1);
|
||||
return (int) res;
|
||||
pthread_cleanup_pop (1);
|
||||
return (int) res;
|
||||
}
|
||||
|
||||
extern "C" int
|
||||
cwait (int *result, int pid, int)
|
||||
{
|
||||
return waitpid (pid, result, 0);
|
||||
return waitpid (pid, result, 0);
|
||||
}
|
||||
|
||||
/*
|
||||
* Helper function for spawn runtime calls.
|
||||
* Doesn't search the path.
|
||||
*/
|
||||
* Helper function for spawn runtime calls.
|
||||
* Doesn't search the path.
|
||||
*/
|
||||
|
||||
extern "C" int
|
||||
spawnve (int mode, const char *path, const char *const *argv,
|
||||
const char *const *envp)
|
||||
const char *const *envp)
|
||||
{
|
||||
int ret;
|
||||
int ret;
|
||||
#ifdef NEWVFORK
|
||||
vfork_save *vf = vfork_storage.val ();
|
||||
vfork_save *vf = vfork_storage.val ();
|
||||
|
||||
if (vf != NULL && (vf->pid < 0) && mode == _P_OVERLAY)
|
||||
mode = _P_NOWAIT;
|
||||
else
|
||||
vf = NULL;
|
||||
if (vf != NULL && (vf->pid < 0) && mode == _P_OVERLAY)
|
||||
mode = _P_NOWAIT;
|
||||
else
|
||||
vf = NULL;
|
||||
#endif
|
||||
|
||||
syscall_printf ("spawnve (%s, %s, %x)", path, argv[0], envp);
|
||||
syscall_printf ("spawnve (%s, %s, %x)", path, argv[0], envp);
|
||||
|
||||
switch (mode)
|
||||
{
|
||||
case _P_OVERLAY:
|
||||
/* We do not pass _P_SEARCH_PATH here. execve doesn't search PATH.*/
|
||||
/* Just act as an exec if _P_OVERLAY set. */
|
||||
spawn_guts (path, argv, envp, mode);
|
||||
/* Errno should be set by spawn_guts. */
|
||||
ret = -1;
|
||||
break;
|
||||
case _P_VFORK:
|
||||
case _P_NOWAIT:
|
||||
case _P_NOWAITO:
|
||||
case _P_WAIT:
|
||||
case _P_DETACH:
|
||||
case _P_SYSTEM:
|
||||
ret = spawn_guts (path, argv, envp, mode);
|
||||
switch (mode)
|
||||
{
|
||||
case _P_OVERLAY:
|
||||
/* We do not pass _P_SEARCH_PATH here. execve doesn't search PATH.*/
|
||||
/* Just act as an exec if _P_OVERLAY set. */
|
||||
spawn_guts (path, argv, envp, mode);
|
||||
/* Errno should be set by spawn_guts. */
|
||||
ret = -1;
|
||||
break;
|
||||
case _P_VFORK:
|
||||
case _P_NOWAIT:
|
||||
case _P_NOWAITO:
|
||||
case _P_WAIT:
|
||||
case _P_DETACH:
|
||||
case _P_SYSTEM:
|
||||
ret = spawn_guts (path, argv, envp, mode);
|
||||
#ifdef NEWVFORK
|
||||
if (vf)
|
||||
{
|
||||
if (ret > 0)
|
||||
{
|
||||
debug_printf ("longjmping due to vfork");
|
||||
vf->restore_pid (ret);
|
||||
}
|
||||
}
|
||||
if (vf)
|
||||
{
|
||||
if (ret > 0)
|
||||
{
|
||||
debug_printf ("longjmping due to vfork");
|
||||
vf->restore_pid (ret);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
break;
|
||||
default:
|
||||
set_errno (EINVAL);
|
||||
ret = -1;
|
||||
break;
|
||||
}
|
||||
return ret;
|
||||
break;
|
||||
default:
|
||||
set_errno (EINVAL);
|
||||
ret = -1;
|
||||
break;
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
/*
|
||||
* spawn functions as implemented in the MS runtime library.
|
||||
* Most of these based on (and copied from) newlib/libc/posix/execXX.c
|
||||
*/
|
||||
* spawn functions as implemented in the MS runtime library.
|
||||
* Most of these based on (and copied from) newlib/libc/posix/execXX.c
|
||||
*/
|
||||
|
||||
extern "C" int
|
||||
spawnl (int mode, const char *path, const char *arg0, ...)
|
||||
{
|
||||
int i;
|
||||
va_list args;
|
||||
const char *argv[256];
|
||||
int i;
|
||||
va_list args;
|
||||
const char *argv[256];
|
||||
|
||||
va_start (args, arg0);
|
||||
argv[0] = arg0;
|
||||
i = 1;
|
||||
va_start (args, arg0);
|
||||
argv[0] = arg0;
|
||||
i = 1;
|
||||
|
||||
do
|
||||
argv[i] = va_arg (args, const char *);
|
||||
while (argv[i++] != NULL);
|
||||
do
|
||||
argv[i] = va_arg (args, const char *);
|
||||
while (argv[i++] != NULL);
|
||||
|
||||
va_end (args);
|
||||
va_end (args);
|
||||
|
||||
return spawnve (mode, path, (char * const *) argv, cur_environ ());
|
||||
return spawnve (mode, path, (char * const *) argv, cur_environ ());
|
||||
}
|
||||
|
||||
extern "C" int
|
||||
spawnle (int mode, const char *path, const char *arg0, ...)
|
||||
{
|
||||
int i;
|
||||
va_list args;
|
||||
const char * const *envp;
|
||||
const char *argv[256];
|
||||
int i;
|
||||
va_list args;
|
||||
const char * const *envp;
|
||||
const char *argv[256];
|
||||
|
||||
va_start (args, arg0);
|
||||
argv[0] = arg0;
|
||||
i = 1;
|
||||
va_start (args, arg0);
|
||||
argv[0] = arg0;
|
||||
i = 1;
|
||||
|
||||
do
|
||||
argv[i] = va_arg (args, const char *);
|
||||
while (argv[i++] != NULL);
|
||||
do
|
||||
argv[i] = va_arg (args, const char *);
|
||||
while (argv[i++] != NULL);
|
||||
|
||||
envp = va_arg (args, const char * const *);
|
||||
va_end (args);
|
||||
envp = va_arg (args, const char * const *);
|
||||
va_end (args);
|
||||
|
||||
return spawnve (mode, path, (char * const *) argv, (char * const *) envp);
|
||||
return spawnve (mode, path, (char * const *) argv, (char * const *) envp);
|
||||
}
|
||||
|
||||
extern "C" int
|
||||
spawnlp (int mode, const char *path, const char *arg0, ...)
|
||||
{
|
||||
int i;
|
||||
va_list args;
|
||||
const char *argv[256];
|
||||
int i;
|
||||
va_list args;
|
||||
const char *argv[256];
|
||||
|
||||
va_start (args, arg0);
|
||||
argv[0] = arg0;
|
||||
i = 1;
|
||||
va_start (args, arg0);
|
||||
argv[0] = arg0;
|
||||
i = 1;
|
||||
|
||||
do
|
||||
argv[i] = va_arg (args, const char *);
|
||||
while (argv[i++] != NULL);
|
||||
do
|
||||
argv[i] = va_arg (args, const char *);
|
||||
while (argv[i++] != NULL);
|
||||
|
||||
va_end (args);
|
||||
va_end (args);
|
||||
|
||||
return spawnvpe (mode, path, (char * const *) argv, cur_environ ());
|
||||
return spawnvpe (mode, path, (char * const *) argv, cur_environ ());
|
||||
}
|
||||
|
||||
extern "C" int
|
||||
spawnlpe (int mode, const char *path, const char *arg0, ...)
|
||||
{
|
||||
int i;
|
||||
va_list args;
|
||||
const char * const *envp;
|
||||
const char *argv[256];
|
||||
int i;
|
||||
va_list args;
|
||||
const char * const *envp;
|
||||
const char *argv[256];
|
||||
|
||||
va_start (args, arg0);
|
||||
argv[0] = arg0;
|
||||
i = 1;
|
||||
va_start (args, arg0);
|
||||
argv[0] = arg0;
|
||||
i = 1;
|
||||
|
||||
do
|
||||
argv[i] = va_arg (args, const char *);
|
||||
while (argv[i++] != NULL);
|
||||
do
|
||||
argv[i] = va_arg (args, const char *);
|
||||
while (argv[i++] != NULL);
|
||||
|
||||
envp = va_arg (args, const char * const *);
|
||||
va_end (args);
|
||||
envp = va_arg (args, const char * const *);
|
||||
va_end (args);
|
||||
|
||||
return spawnvpe (mode, path, (char * const *) argv, envp);
|
||||
return spawnvpe (mode, path, (char * const *) argv, envp);
|
||||
}
|
||||
|
||||
extern "C" int
|
||||
spawnv (int mode, const char *path, const char * const *argv)
|
||||
{
|
||||
return spawnve (mode, path, argv, cur_environ ());
|
||||
return spawnve (mode, path, argv, cur_environ ());
|
||||
}
|
||||
|
||||
extern "C" int
|
||||
spawnvp (int mode, const char *path, const char * const *argv)
|
||||
{
|
||||
return spawnvpe (mode, path, argv, cur_environ ());
|
||||
return spawnvpe (mode, path, argv, cur_environ ());
|
||||
}
|
||||
|
||||
extern "C" int
|
||||
spawnvpe (int mode, const char *file, const char * const *argv,
|
||||
const char * const *envp)
|
||||
const char * const *envp)
|
||||
{
|
||||
path_conv buf;
|
||||
return spawnve (mode, find_exec (file, buf), argv, envp);
|
||||
path_conv buf;
|
||||
return spawnve (mode, find_exec (file, buf), argv, envp);
|
||||
}
|
||||
|
Reference in New Issue
Block a user