* child_info.h (child_info_spawn::hexec_proc): Eliminate.

* dcrt0.cc (dll_crt0_0): Remove hexec_proc stuff.
* fork.cc (fork_child): Remove call to pinfo_fixup_after_fork.
* pinfo.cc (set_myself): Close and zero pid_handle if set.
(pinfo_fixup_after_fork): Delete.
(proc_waiter): Don't close vchild.hProcess here.  Do that when we are remove
the vchild from procs.  Save hProcess as pid_handle only on first reparent
operation.
(pinfo::wait): Don't set pid_handle here.
(pinfo::alert_parent): Always try to send signal.  If unsuccessful then close
and zero wr_proc_pipe.
* pinfo.h (pinfo::pinfo): Make sure that appropriate parts of the class are
zeroed on construction.
(pinfo::alert_parent): Take char argument.
(pinfo_fixup_after_fork): Delete declaration.
(hexec_proc): Ditto.
* sigproc.cc (remove_proc): Close pid_handle and hProcess if appropriate.
* spawn.cc (spawn_guts): Set cygheap->pid_handle on first exec.
* cygheap.h (init_cygheap::pid_handle): New element.
* pinfo.cc (set_myself): Clear previously existing cygheap->pid_handle when a
new process has been started.
(pinfo::wait): Make sure that a handle to the newly forked/spawned process is
kept around so that the pid will not be reused.
* pinfo.h (_pinfo::pid_handle): Move.
(pinfo::pid_handle): to here.
* spawn.cc (spawn_guts): Create a pid_handle in cygheap prior to spawning to
ensure that the pid does not get reused during the lifetime of the "cygwin
pid".
* pinfo.h (pinfo::alert_parent): New function.
* exceptions.cc (sig_handle_tty_stop): Use alert_parent to send "signals" to
parent.
* fork.cc (fork_parent): Don't close pi.hProcess.  Let the waiter thread do
that.
* pinfo.cc (proc_waiter): Detect case where process exits without setting the
exit code and use value from GetExitCodeProcess.  Reluctantly implement
__SIGREPARENT.
(pinfo::alert_parent): Define.
* sigproc.h (__SIGREPARENT): New enum.
* spawn.cc (spawn_guts): Send reparent signal to parent on exec.  Always create
process in suspended state to avoid races.  Remove cygthread.h in favor of
cygtls.h throughout since cygtls now includes cygthread.h.  Eliminate
ppid_handle usage throughout.
* child_info.h: Regenerate magic number
(child_info): Remove pppid_handle.
* cygthread.h (cygthread::release): New method.  Frees thread without waiting.
* cygthread.cc (cygthread::stub): Set _ctinfo in _mytls to point to information
for executing thread.  Don't call SetEvent if thread is no longer in use.
(cygthread::simplestub): Ditto.
* cygtls.h (_cygtls::_ctinfo): New element contains pointer to information
about executing cygthread, if any.
* dcrt0.cc: Remove last vestiges of per_thread stuff.
(dll_crt0_0): Ditto.  Remove accommodation for ppid_handle.
(do_exit): Remove obsolete reparenting test.
(_exit): Exit with a more SUSv3-like exit value.
* dtable.cc (dtable::stdio_init): Check for myself->cygstarted rather than
myself->ppid_handle to see if we were started by a cygwin process.
* exceptions.cc (open_stackdumpfile): Ditto.
(handle_exceptions): Ditto.
(ctrl_c_handler): Ditto.
(sig_handle_tty_stop): Ditto.  Let parent send signal to itself on STOP.
(sigpacket::process): Comment out vfork test.
(signal_exit): Use more SUSv3-like exit value on signal.
* external.cc (fillout_pinfo): Don't set hProcess.
* fork.cc: Remove VFORK cruft.
(per_thread::set): Delete.
(fork_child): Remove perthread stuff.
(fork_parent): Remove obsolete subproc_init.  Accommodate new method for
tracking subprocesses.
* pinfo.cc (set_myself): Accommodate new pinfo/_pinfo layout.  Set some things
here that used to be set in wait_sig.
(_pinfo::exit): Set exitcode here.  Close process pipe.
(_pinfo::commune_send): Accommodeate new pinfo/_pinfo layout.
(proc_waiter): New function.  Waits, in a thread for subprocess to go away.
(pinfo::wait): New function.  Initialization for proc_waiter.
* pinfo.h (_pinfo::exitcode): New element.
(_pinfo::cygstarted): Ditto.
(_pinfo::wr_proc_pipe): Ditto.
(_pinfo::ppid_handle): Delete.
(_pinfo::hProcess): Delete.
(_pinfo::lock): Delete.
(pinfo::hProcess): New element.
(pinfo::lock): Ditto.
(pinfo::wait): Declare new function.
(pinfo::preserve): Define new function.
* sigproc.cc: Remove old stuff from wait_subproc thread based method.
(zombies): Remove.
(procs): New.
(my_parent_is_alive): Just check that the parent pid exists.
(mychild): Just use pinfo methods to determine if child is mine.
(proc_subproc): Revamp PROC_ADDCHILD to use pinfo::wait.  Remove
PROC_CHILDTERMINATED logic.  Use different method to remove processes from list
when SIGCHLD == SIG_IGN.
(proc_terminate): Gut.
(subproc_init): Delete.
(init_child_info): Remove setting of pppid_handle.
(checkstate): Revamp to only scan procs array.
(remove_proc): Rename from remove_zombie.  Don't close hProcess or pid_handle.
Don't release memory if it's myself.
(stopped_or_terminated): Change logic to handle new consolidated proc/zombie
array.
(wait_subproc): Delete.
* sigproc.h: Remove obsolete EXIT_* defines.
(subproc_init): Remove declaration.
* spawn.cc (spawn_guts): Remove reparenting stuff.  Use standard wait logic to
wait for child if started from a non-cygwin process.
* tlsoffsets.h: Regenerate.
* tty.cc (tty_init): Check for myself->cygstarted rather than
myself->ppid_handle to see if we were started by a cygwin process.
* include/sys/signal.h (external_pinfo::exitcode): Replace hProcess.
* include/sys/wait.h (WCOREDUMP): Define.
* fhandler_tty.cc (fhandler_tty_slave::read): Add debugging output for timeout
case.
* signal.cc (abort): Flag that we are exiting with the ABORT signal.
This commit is contained in:
Christopher Faylor
2004-11-26 04:15:10 +00:00
parent c1ab3396dc
commit 8cb359d947
33 changed files with 656 additions and 798 deletions

View File

@@ -29,8 +29,6 @@ details. */
#include "child_info.h"
#include "shared_info.h"
#include "pinfo.h"
#define NEED_VFORK
#include "perthread.h"
#include "registry.h"
#include "environ.h"
#include "cygthread.h"
@@ -384,16 +382,7 @@ spawn_guts (const char * prog_arg, const char *const *argv,
else
chtype = PROC_EXEC;
HANDLE subproc_ready;
if (chtype != PROC_EXEC)
subproc_ready = NULL;
else
{
subproc_ready = CreateEvent (&sec_all, TRUE, FALSE, NULL);
ProtectHandleINH (subproc_ready);
}
init_child_info (chtype, &ciresrv, subproc_ready);
init_child_info (chtype, &ciresrv, NULL);
ciresrv.moreinfo = (cygheap_exec_info *) ccalloc (HEAP_1_EXEC, 1, sizeof (cygheap_exec_info));
ciresrv.moreinfo->old_title = NULL;
@@ -603,7 +592,6 @@ spawn_guts (const char * prog_arg, const char *const *argv,
ciresrv.moreinfo->argc = newargv.argc;
ciresrv.moreinfo->argv = newargv;
ciresrv.hexec_proc = hexec_proc;
if (mode != _P_OVERLAY ||
!DuplicateHandle (hMainProc, myself.shared_handle (), hMainProc,
@@ -627,19 +615,35 @@ spawn_guts (const char * prog_arg, const char *const *argv,
if (mode == _P_DETACH || !set_console_state_for_spawn ())
flags |= DETACHED_PROCESS;
if (mode != _P_OVERLAY)
flags |= CREATE_SUSPENDED;
#if 0 //someday
else
myself->dwProcessId = 0;
#endif
/* 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 (cygheap->fdtab.need_fixup_before ())
flags |= CREATE_SUSPENDED;
HANDLE saved_sendsig;
if (mode != _P_OVERLAY)
saved_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;
/* 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? */
if (cygheap->pid_handle)
/* already done previously */;
else if (DuplicateHandle (hMainProc, hMainProc, hMainProc, &cygheap->pid_handle,
PROCESS_QUERY_INFORMATION, TRUE, 0))
ProtectHandle (cygheap->pid_handle);
else
system_printf ("duplicate to pid_handle failed, %E");
}
/* 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. */
flags |= CREATE_SUSPENDED;
const char *runpath = null_app_name ? NULL : (const char *) real_path;
@@ -718,7 +722,7 @@ spawn_guts (const char * prog_arg, const char *const *argv,
/* Restore impersonation. In case of _P_OVERLAY this isn't
allowed since it would overwrite child data. */
if (mode != _P_OVERLAY || !rc)
cygheap->user.reimpersonate ();
cygheap->user.reimpersonate ();
MALLOC_CHECK;
if (envblock)
@@ -732,12 +736,9 @@ spawn_guts (const char * prog_arg, const char *const *argv,
{
__seterrno ();
syscall_printf ("CreateProcess failed, %E");
#if 0 // someday
if (mode == _P_OVERLAY)
myself->dwProcessId = GetCurrentProcessId ();
#endif
if (subproc_ready)
ForceCloseHandle (subproc_ready);
/* If this was a failed exec, restore the saved sendsig. */
if (saved_sendsig)
myself->sendsig = saved_sendsig;
cygheap_setup_for_child_cleanup (newheap, &ciresrv, 0);
return -1;
}
@@ -765,11 +766,6 @@ spawn_guts (const char * prog_arg, const char *const *argv,
{
cygheap->fdtab.fixup_before_exec (pi.dwProcessId);
cygheap_setup_for_child_cleanup (newheap, &ciresrv, 1);
if (mode == _P_OVERLAY)
{
ResumeThread (pi.hThread);
cygthread::terminate ();
}
}
if (mode != _P_OVERLAY)
@@ -784,18 +780,36 @@ spawn_guts (const char * prog_arg, const char *const *argv,
/* Name the handle similarly to proc_subproc. */
ProtectHandle1 (pi.hProcess, childhProc);
int wait_for_myself = false;
DWORD exec_cygstarted;
if (mode == _P_OVERLAY)
{
/* These are both duplicated in the child code. We do this here,
primarily for strace. */
/* 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 (__SIGREPARENT);
CloseHandle (saved_sendsig);
strace.execing = 1;
hExeced = pi.hProcess;
dwExeced = pi.dwProcessId;
strcpy (myself->progname, real_path);
close_all_files ();
/* 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;
}
}
else
{
exec_cygstarted = 0;
myself->set_has_pgid_children ();
ProtectHandle (pi.hThread);
pinfo child (cygpid, PID_IN_USE);
@@ -808,7 +822,7 @@ spawn_guts (const char * prog_arg, const char *const *argv,
goto out;
}
child->dwProcessId = pi.dwProcessId;
child->hProcess = pi.hProcess;
child.hProcess = pi.hProcess;
if (!child.remember ())
{
syscall_printf ("process table full");
@@ -825,101 +839,31 @@ 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);
/* Start the child running */
ResumeThread (pi.hThread);
}
/* Start the child running */
if (flags & CREATE_SUSPENDED)
ResumeThread (pi.hThread);
ForceCloseHandle (pi.hThread);
// ForceCloseHandle (pi.hProcess); // handled by proc_subproc and friends
sigproc_printf ("spawned windows pid %d", pi.dwProcessId);
bool exited;
res = 0;
exited = false;
MALLOC_CHECK;
if (mode == _P_OVERLAY)
if (wait_for_myself)
waitpid (myself->pid, &res, 0);
else
{
int nwait = 3;
HANDLE waitbuf[3] = {pi.hProcess, signal_arrived, subproc_ready};
for (int i = 0; i < 100; i++)
{
switch (WaitForMultipleObjects (nwait, waitbuf, FALSE, INFINITE))
{
case WAIT_OBJECT_0:
sigproc_printf ("subprocess exited");
DWORD exitcode;
if (!GetExitCodeProcess (pi.hProcess, &exitcode))
exitcode = 1;
res |= exitcode;
exited = true;
break;
case WAIT_OBJECT_0 + 1:
sigproc_printf ("signal arrived");
reset_signal_arrived ();
continue;
case WAIT_OBJECT_0 + 2:
if (my_parent_is_alive ())
res |= EXIT_REPARENTING;
else if (!myself->ppid_handle)
{
nwait = 2;
sigproc_terminate ();
continue;
}
break;
case WAIT_FAILED:
system_printf ("wait failed: nwait %d, pid %d, winpid %d, %E",
nwait, myself->pid, myself->dwProcessId);
system_printf ("waitbuf[0] %p %d", waitbuf[0],
WaitForSingleObject (waitbuf[0], 0));
system_printf ("waitbuf[1] %p %d", waitbuf[1],
WaitForSingleObject (waitbuf[1], 0));
system_printf ("waitbuf[w] %p %d", waitbuf[2],
WaitForSingleObject (waitbuf[2], 0));
set_errno (ECHILD);
try_to_debug ();
return -1;
}
break;
}
ForceCloseHandle (subproc_ready);
sigproc_printf ("res %p", res);
if (res & EXIT_REPARENTING)
{
/* Try to reparent child process.
* Make handles to child available to parent process and exit with
* EXIT_REPARENTING status. Wait() syscall in parent will then wait
* for newly created child.
*/
HANDLE oldh = myself->hProcess;
HANDLE h = myself->ppid_handle;
sigproc_printf ("parent handle %p", h);
int rc = DuplicateHandle (hMainProc, pi.hProcess, h, &myself->hProcess,
0, FALSE, DUPLICATE_SAME_ACCESS);
sigproc_printf ("%d = DuplicateHandle, oldh %p, newh %p",
rc, oldh, myself->hProcess);
VerifyHandle (myself->hProcess);
if (!rc && my_parent_is_alive ())
{
system_printf ("Reparent failed, parent handle %p, %E", h);
system_printf ("my dwProcessId %d, myself->dwProcessId %d",
GetCurrentProcessId (), myself->dwProcessId);
system_printf ("old hProcess %p, hProcess %p", oldh, myself->hProcess);
}
}
/* Loop, waiting for parent to notice pid change, if exec_cygstarted.
In theory this wait should be a no-op. */
if (exec_cygstarted)
while (myself->cygstarted == exec_cygstarted)
low_priority_sleep (0);
res = 42;
}
MALLOC_CHECK;
switch (mode)
{
case _P_OVERLAY:
ForceCloseHandle1 (pi.hProcess, childhProc);
myself->exit (res, 1);
break;
case _P_WAIT:
@@ -986,7 +930,6 @@ spawnve (int mode, const char *path, const char *const *argv,
case _P_WAIT:
case _P_DETACH:
case _P_SYSTEM:
subproc_init ();
ret = spawn_guts (path, argv, envp, mode);
#ifdef NEWVFORK
if (vf)