* 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:
Christopher Faylor
2004-12-05 19:41:26 +00:00
parent d54b79d351
commit 54dd79bb44
9 changed files with 501 additions and 376 deletions

View File

@@ -107,68 +107,8 @@ fork_copy (PROCESS_INFORMATION &pi, const char *what, ...)
return 0;
}
/* Wait for child to finish what it's doing and signal us.
We don't want to wait forever here.If there's a problem somewhere
it'll hang the entire system (since all forks are mutex'd). If we
time out, set errno = EAGAIN and hope the app tries again. */
static int
sync_with_child (PROCESS_INFORMATION &pi, HANDLE subproc_ready,
bool hang_child, const char *s)
{
/* We also add the child process handle to the wait. If the child fails
to initialize (eg. because of a missing dll). Then this
handle will become signalled. This stops a *looong* timeout wait.
*/
HANDLE w4[2];
debug_printf ("waiting for child. reason: %s, hang_child %d", s,
hang_child);
w4[1] = pi.hProcess;
w4[0] = subproc_ready;
DWORD rc = WaitForMultipleObjects (2, w4, FALSE, FORK_WAIT_TIMEOUT);
if (rc == WAIT_OBJECT_0 ||
WaitForSingleObject (subproc_ready, 0) == WAIT_OBJECT_0)
/* That's ok */;
else if (rc == WAIT_FAILED || rc == WAIT_TIMEOUT)
{
if (rc != WAIT_FAILED)
system_printf ("WaitForMultipleObjects timed out");
else
system_printf ("WaitForMultipleObjects failed, %E");
set_errno (EAGAIN);
syscall_printf ("-1 = fork(), WaitForMultipleObjects failed");
TerminateProcess (pi.hProcess, 1);
return 0;
}
else
{
/* Child died. Clean up and exit. */
DWORD errcode;
GetExitCodeProcess (pi.hProcess, &errcode);
/* Fix me. This is not enough. The fork should not be considered
* to have failed if the process was essentially killed by a signal.
*/
if (errcode != STATUS_CONTROL_C_EXIT)
{
system_printf ("child %u(%p) died before initialization with status code %p",
cygwin_pid (pi.dwProcessId), pi.hProcess, errcode);
system_printf ("*** child state %s", s);
#ifdef DEBUGGING
try_to_debug ();
#endif
}
set_errno (EAGAIN);
syscall_printf ("Child died before subproc_ready signalled");
return 0;
}
debug_printf ("child signalled me");
return 1;
}
static int
resume_child (PROCESS_INFORMATION &pi, HANDLE forker_finished)
resume_child (HANDLE forker_finished)
{
SetEvent (forker_finished);
debug_printf ("signalled child");
@@ -182,9 +122,7 @@ static void __stdcall
sync_with_parent (const char *s, bool hang_self)
{
debug_printf ("signalling parent: %s", s);
/* Tell our parent we're waiting. */
if (!SetEvent (fork_info->subproc_ready))
api_fatal ("fork child - SetEvent for %s failed, %E", s);
fork_info->ready (false);
if (hang_self)
{
HANDLE h = fork_info->forker_finished;
@@ -281,7 +219,6 @@ fork_child (HANDLE& hParent, dll *&first_dll, bool& load_dlls)
}
ForceCloseHandle (hParent);
(void) ForceCloseHandle1 (fork_info->subproc_ready, subproc_ready);
(void) ForceCloseHandle1 (fork_info->forker_finished, forker_finished);
_my_tls.fixup_after_fork ();
@@ -308,7 +245,7 @@ slow_pid_reuse (HANDLE h)
if (nfork_procs >= (sizeof (last_fork_procs) / sizeof (last_fork_procs [0])))
nfork_procs = 0;
/* Keep a list of handles to forked processes sitting around to prevent
/* Keep a list of handles to child processes sitting around to prevent
Windows from reusing the same pid n times in a row. Having the same pids
close in succesion confuses bash. Keeping a handle open will stop
windows from reusing the same pid. */
@@ -330,7 +267,7 @@ static int __stdcall
fork_parent (HANDLE& hParent, dll *&first_dll,
bool& load_dlls, void *stack_here, child_info_fork &ch)
{
HANDLE subproc_ready, forker_finished;
HANDLE forker_finished;
DWORD rc;
PROCESS_INFORMATION pi = {0, NULL, 0, 0};
@@ -379,35 +316,22 @@ fork_parent (HANDLE& hParent, dll *&first_dll,
/* This will help some of the confusion. */
fflush (stdout);
subproc_ready = CreateEvent (&sec_all, FALSE, FALSE, NULL);
if (subproc_ready == NULL)
{
CloseHandle (hParent);
system_printf ("unable to allocate subproc_ready event, %E");
return -1;
}
forker_finished = CreateEvent (&sec_all, FALSE, FALSE, NULL);
if (forker_finished == NULL)
{
CloseHandle (hParent);
CloseHandle (subproc_ready);
system_printf ("unable to allocate forker_finished event, %E");
return -1;
}
ProtectHandleINH (subproc_ready);
ProtectHandleINH (forker_finished);
init_child_info (PROC_FORK, &ch, subproc_ready);
ch.forker_finished = forker_finished;
ch.parent_wr_proc_pipe = myself->wr_proc_pipe == INVALID_HANDLE_VALUE
? NULL : myself->wr_proc_pipe;
stack_base (ch);
si.cb = sizeof (STARTUPINFO);
si.lpReserved2 = (LPBYTE)&ch;
si.lpReserved2 = (LPBYTE) &ch;
si.cbReserved2 = sizeof (ch);
/* Remove impersonation */
@@ -437,7 +361,6 @@ fork_parent (HANDLE& hParent, dll *&first_dll,
{
__seterrno ();
syscall_printf ("CreateProcessA failed, %E");
ForceCloseHandle (subproc_ready);
ForceCloseHandle (forker_finished);
/* Restore impersonation */
cygheap->user.reimpersonate ();
@@ -457,10 +380,11 @@ fork_parent (HANDLE& hParent, dll *&first_dll,
ResumeThread (pi.hThread);
}
int forked_pid = cygwin_pid (pi.dwProcessId);
pinfo forked (forked_pid, 1);
int child_pid = cygwin_pid (pi.dwProcessId);
pinfo child (child_pid, 1);
child->start_time = time (NULL); /* Register child's starting time. */
if (!forked)
if (!child)
{
syscall_printf ("pinfo failed");
if (get_errno () != ENOMEM)
@@ -470,7 +394,7 @@ fork_parent (HANDLE& hParent, dll *&first_dll,
/* Initialize things that are done later in dll_crt0_1 that aren't done
for the forkee. */
strcpy (forked->progname, myself->progname);
strcpy (child->progname, myself->progname);
/* Restore impersonation */
cygheap->user.reimpersonate ();
@@ -478,18 +402,18 @@ fork_parent (HANDLE& hParent, dll *&first_dll,
ProtectHandle (pi.hThread);
/* Protect the handle but name it similarly to the way it will
be called in subproc handling. */
ProtectHandle1 (pi.hProcess, childhProc);
ProtectHandle (pi.hProcess);
/* Fill in fields in the child's process table entry. */
forked->dwProcessId = pi.dwProcessId;
forked.hProcess = pi.hProcess;
child->dwProcessId = pi.dwProcessId;
child.hProcess = pi.hProcess;
/* Hopefully, this will succeed. The alternative to doing things this
way is to reserve space prior to calling CreateProcess and then fill
it in afterwards. This requires more bookkeeping than I like, though,
so we'll just do it the easy way. So, terminate any child process if
we can't actually record the pid in the internal table. */
if (!forked.remember ())
if (!child.remember ())
{
TerminateProcess (pi.hProcess, 1);
set_errno (EAGAIN);
@@ -501,8 +425,11 @@ fork_parent (HANDLE& hParent, dll *&first_dll,
#endif
/* Wait for subproc to initialize itself. */
if (!sync_with_child (pi, subproc_ready, true, "waiting for longjmp"))
goto cleanup;
if (!ch.sync (child, FORK_WAIT_TIMEOUT))
{
system_printf ("child %d died waiting for longjmp before initialization", child_pid);
goto cleanup;
}
/* CHILD IS STOPPED */
debug_printf ("child is alive (but stopped)");
@@ -547,9 +474,13 @@ fork_parent (HANDLE& hParent, dll *&first_dll,
}
/* Start thread, and wait for it to reload dlls. */
if (!resume_child (pi, forker_finished) ||
!sync_with_child (pi, subproc_ready, load_dlls, "child loading dlls"))
if (!resume_child (forker_finished))
goto cleanup;
else if (!ch.sync (child, FORK_WAIT_TIMEOUT))
{
system_printf ("child %d died waiting for dll loading", child_pid);
goto cleanup;
}
/* If DLLs were loaded in the parent, then the child has reloaded all
of them and is now waiting to have all of the individual data and
@@ -567,17 +498,17 @@ fork_parent (HANDLE& hParent, dll *&first_dll,
goto cleanup;
}
/* Start the child up again. */
(void) resume_child (pi, forker_finished);
(void) resume_child (forker_finished);
}
ForceCloseHandle (subproc_ready);
ForceCloseHandle (pi.hProcess);
ForceCloseHandle (pi.hThread);
ForceCloseHandle (forker_finished);
forker_finished = NULL;
pi.hThread = NULL;
pthread::atforkparent ();
return forked_pid;
return child_pid;
/* Common cleanup code for failure cases */
cleanup:
@@ -589,8 +520,6 @@ fork_parent (HANDLE& hParent, dll *&first_dll,
ForceCloseHandle1 (pi.hProcess, childhProc);
if (pi.hThread)
ForceCloseHandle (pi.hThread);
if (subproc_ready)
ForceCloseHandle (subproc_ready);
if (forker_finished)
ForceCloseHandle (forker_finished);
return -1;
@@ -618,6 +547,11 @@ fork ()
myself->set_has_pgid_children ();
child_info_fork ch;
if (ch.subproc_ready == NULL)
{
system_printf ("unable to allocate subproc_ready event, %E");
return -1;
}
sig_send (NULL, __SIGHOLD);
int res = setjmp (ch.jmp);