* 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:
parent
d54b79d351
commit
54dd79bb44
@ -1,3 +1,65 @@
|
||||
2004-12-05 Christopher Faylor <cgf@timesys.com>
|
||||
|
||||
* sigproc.cc (mychild): Reimplement as list scan.
|
||||
(proc_subproc): Don't mess with pinfo if it's myself.
|
||||
|
||||
2004-12-05 Christopher Faylor <cgf@timesys.com>
|
||||
|
||||
* 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.
|
||||
|
||||
2004-12-05 Bas van Gompel <cygwin-patch@bavag.tmfweb.nl>
|
||||
|
||||
* fhandler.cc (fhandler_base::read): Remove superfluous check in
|
||||
|
@ -10,7 +10,7 @@ details. */
|
||||
|
||||
#include <setjmp.h>
|
||||
|
||||
enum
|
||||
enum child_info_types
|
||||
{
|
||||
_PROC_EXEC,
|
||||
_PROC_SPAWN,
|
||||
@ -51,6 +51,10 @@ public:
|
||||
HANDLE cygheap_h;
|
||||
HANDLE parent_wr_proc_pipe;
|
||||
unsigned fhandler_union_cb;
|
||||
child_info (unsigned, child_info_types);
|
||||
~child_info ();
|
||||
void ready (bool);
|
||||
bool sync (pinfo&, DWORD);
|
||||
};
|
||||
|
||||
class mount_info;
|
||||
@ -64,6 +68,7 @@ public:
|
||||
jmp_buf jmp; // where child will jump to
|
||||
void *stacktop; // location of top of parent stack
|
||||
void *stackbottom; // location of bottom of parent stack
|
||||
child_info_fork ();
|
||||
};
|
||||
|
||||
class fhandler_base;
|
||||
@ -84,7 +89,6 @@ class child_info_spawn: public child_info
|
||||
public:
|
||||
cygheap_exec_info *moreinfo;
|
||||
|
||||
child_info_spawn (): moreinfo (NULL) {}
|
||||
~child_info_spawn ()
|
||||
{
|
||||
if (moreinfo)
|
||||
@ -101,6 +105,7 @@ public:
|
||||
cfree (moreinfo);
|
||||
}
|
||||
}
|
||||
child_info_spawn (child_info_types);
|
||||
};
|
||||
|
||||
void __stdcall init_child_info (DWORD, child_info *, HANDLE);
|
||||
|
@ -618,13 +618,15 @@ dll_crt0_0 ()
|
||||
case _PROC_SPAWN:
|
||||
case _PROC_EXEC:
|
||||
if (!should_be_cb)
|
||||
should_be_cb = sizeof (child_info);
|
||||
should_be_cb = sizeof (child_info_spawn);
|
||||
if (should_be_cb != child_proc_info->cb)
|
||||
multiple_cygwin_problem ("proc size", child_proc_info->cb, should_be_cb);
|
||||
else if (sizeof (fhandler_union) != child_proc_info->fhandler_union_cb)
|
||||
multiple_cygwin_problem ("fhandler size", child_proc_info->fhandler_union_cb, sizeof (fhandler_union));
|
||||
else
|
||||
{
|
||||
if (child_proc_info->type != _PROC_FORK)
|
||||
child_proc_info->ready (true);
|
||||
cygwin_user_h = child_proc_info->user_h;
|
||||
break;
|
||||
}
|
||||
|
@ -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);
|
||||
|
@ -87,24 +87,24 @@ unsigned long cygwin_internal (cygwin_getinfo_types, ...);
|
||||
/* Flags associated with process_state */
|
||||
enum
|
||||
{
|
||||
PID_IN_USE = 0x0001, /* Entry in use. */
|
||||
PID_ZOMBIE = 0x0002, /* Child exited: no parent wait. */
|
||||
PID_STOPPED = 0x0004, /* Waiting for SIGCONT. */
|
||||
PID_TTYIN = 0x0008, /* Waiting for terminal input. */
|
||||
PID_TTYOU = 0x0010, /* Waiting for terminal output. */
|
||||
PID_ORPHANED = 0x0020, /* Member of an orphaned process group. */
|
||||
PID_ACTIVE = 0x0040, /* Pid accepts signals. */
|
||||
PID_CYGPARENT = 0x0080, /* Set if parent was a cygwin app. */
|
||||
PID_MAP_RW = 0x0100, /* Flag to open map rw. */
|
||||
PID_MYSELF = 0x0200, /* Flag that pid is me. */
|
||||
PID_NOCLDSTOP = 0x0400, /* Set if no SIGCHLD signal on stop. */
|
||||
PID_INITIALIZING = 0x0800, /* Set until ready to receive signals. */
|
||||
PID_USETTY = 0x1000, /* Setting this enables or disables cygwin's */
|
||||
/* tty support. This is inherited by */
|
||||
/* all execed or forked processes. */
|
||||
PID_ALLPIDS = 0x2000, /* child has execed */
|
||||
PID_EXECED = 0x4000, /* redirect to original pid info block */
|
||||
PID_NOREDIR = 0x8000, /* don't redirect if execed */
|
||||
PID_IN_USE = 0x00001, /* Entry in use. */
|
||||
PID_ZOMBIE = 0x00002, /* Child exited: no parent wait. */
|
||||
PID_STOPPED = 0x00004, /* Waiting for SIGCONT. */
|
||||
PID_TTYIN = 0x00008, /* Waiting for terminal input. */
|
||||
PID_TTYOU = 0x00010, /* Waiting for terminal output. */
|
||||
PID_ORPHANED = 0x00020, /* Member of an orphaned process group. */
|
||||
PID_ACTIVE = 0x00040, /* Pid accepts signals. */
|
||||
PID_CYGPARENT = 0x00080, /* Set if parent was a cygwin app. */
|
||||
PID_MAP_RW = 0x00100, /* Flag to open map rw. */
|
||||
PID_MYSELF = 0x00200, /* Flag that pid is me. */
|
||||
PID_NOCLDSTOP = 0x00400, /* Set if no SIGCHLD signal on stop. */
|
||||
PID_INITIALIZING = 0x00800, /* Set until ready to receive signals. */
|
||||
PID_USETTY = 0x01000, /* Setting this enables or disables cygwin's
|
||||
tty support. This is inherited by
|
||||
all execed or forked processes. */
|
||||
PID_ALLPIDS = 0x02000, /* used by pinfo scanner */
|
||||
PID_EXECED = 0x04000, /* redirect to original pid info block */
|
||||
PID_NOREDIR = 0x08000, /* don't redirect if execed */
|
||||
PID_EXITED = 0x80000000 /* Free entry. */
|
||||
};
|
||||
|
||||
|
@ -50,21 +50,25 @@ set_myself (HANDLE h)
|
||||
cygheap->pid = cygwin_pid (GetCurrentProcessId ());
|
||||
myself.init (cygheap->pid, PID_IN_USE | PID_MYSELF, h);
|
||||
myself->process_state |= PID_IN_USE;
|
||||
myself->start_time = time (NULL); /* Register our starting time. */
|
||||
myself->dwProcessId = GetCurrentProcessId ();
|
||||
|
||||
(void) GetModuleFileName (NULL, myself->progname, sizeof (myself->progname));
|
||||
if (!strace.active)
|
||||
strace.hello ();
|
||||
debug_printf ("myself->dwProcessId %u", myself->dwProcessId);
|
||||
InitializeCriticalSection (&myself.lock);
|
||||
myself->dwProcessId = GetCurrentProcessId ();
|
||||
myself.initialize_lock ();
|
||||
if (h)
|
||||
{
|
||||
/* here if execed */
|
||||
static pinfo NO_COPY myself_identity;
|
||||
myself_identity.init (cygwin_pid (myself->dwProcessId), PID_EXECED);
|
||||
myself->start_time = time (NULL); /* Register our starting time. */
|
||||
myself->exec_sendsig = NULL;
|
||||
myself->exec_dwProcessId = 0;
|
||||
}
|
||||
else if (myself->wr_proc_pipe)
|
||||
else if (!myself->wr_proc_pipe)
|
||||
myself->start_time = time (NULL); /* Register our starting time. */
|
||||
else
|
||||
{
|
||||
/* We've inherited the parent's wr_proc_pipe. We don't need it,
|
||||
so close it. */
|
||||
@ -522,7 +526,7 @@ _pinfo::commune_send (DWORD code, ...)
|
||||
__seterrno ();
|
||||
goto err;
|
||||
}
|
||||
EnterCriticalSection (&myself.lock);
|
||||
myself.lock ();
|
||||
myself->tothem = tome;
|
||||
myself->fromthem = fromme;
|
||||
myself->hello_pid = pid;
|
||||
@ -626,7 +630,7 @@ err:
|
||||
|
||||
out:
|
||||
myself->hello_pid = 0;
|
||||
LeaveCriticalSection (&myself.lock);
|
||||
myself.unlock ();
|
||||
return res;
|
||||
}
|
||||
|
||||
@ -710,13 +714,6 @@ proc_waiter (void *arg)
|
||||
/* Child exited. Do some cleanup and signal myself. */
|
||||
CloseHandle (vchild.rd_proc_pipe);
|
||||
vchild.rd_proc_pipe = NULL;
|
||||
|
||||
if (vchild->process_state != PID_EXITED && vchild.hProcess)
|
||||
{
|
||||
DWORD exit_code;
|
||||
if (GetExitCodeProcess (vchild.hProcess, &exit_code))
|
||||
vchild->exitcode = (exit_code & 0xff) << 8;
|
||||
}
|
||||
if (WIFEXITED (vchild->exitcode))
|
||||
si.si_sigval.sival_int = CLD_EXITED;
|
||||
else if (WCOREDUMP (vchild->exitcode))
|
||||
@ -730,33 +727,13 @@ proc_waiter (void *arg)
|
||||
case SIGTTOU:
|
||||
case SIGTSTP:
|
||||
case SIGSTOP:
|
||||
if (ISSTATE (myself, PID_NOCLDSTOP)) // FIXME: No need for this flag to be in _pinfo any longer
|
||||
continue;
|
||||
/* Child stopped. Signal myself. */
|
||||
si.si_sigval.sival_int = CLD_STOPPED;
|
||||
break;
|
||||
case SIGCONT:
|
||||
continue;
|
||||
case __ALERT_REPARENT: /* sigh */
|
||||
/* spawn_guts has signalled us that it has just started a new
|
||||
subprocess which will take over this cygwin pid. */
|
||||
|
||||
/* We need to keep a handle to the original windows process which
|
||||
represents the cygwin process around to make sure that the
|
||||
windows pid is not reused before we are through with it.
|
||||
So, detect the first time that a subprocess calls exec
|
||||
and save the current hprocess in the pid_handle field.
|
||||
On subsequent execs just close the handle. */
|
||||
if (!vchild.hProcess)
|
||||
/* something went wrong. oh well. */;
|
||||
else if (vchild.pid_handle)
|
||||
ForceCloseHandle1 (vchild.hProcess, childhProc);
|
||||
else
|
||||
vchild.pid_handle = vchild.hProcess;
|
||||
vchild.hProcess = OpenProcess (PROCESS_QUERY_INFORMATION, FALSE,
|
||||
vchild->dwProcessId);
|
||||
vchild->cygstarted++;
|
||||
if (vchild.hProcess)
|
||||
ProtectHandle1 (vchild.hProcess, childhProc);
|
||||
continue;
|
||||
default:
|
||||
system_printf ("unknown value %d on proc pipe", buf);
|
||||
continue;
|
||||
@ -790,6 +767,40 @@ proc_waiter (void *arg)
|
||||
return 0;
|
||||
}
|
||||
|
||||
void
|
||||
proc_pipe::set (bool closeem)
|
||||
{
|
||||
myself.lock ();
|
||||
if (!CreatePipe (&in, &out, &sec_none_nih, 16))
|
||||
{
|
||||
system_printf ("couldn't create pipe, %E");
|
||||
return;
|
||||
}
|
||||
/* Duplicate the write end of the pipe into the subprocess. Make it inheritable
|
||||
so that all of the execed children get it. */
|
||||
if (!DuplicateHandle (hMainProc, out, hMainProc, &out, 0, TRUE,
|
||||
DUPLICATE_SAME_ACCESS | DUPLICATE_CLOSE_SOURCE))
|
||||
{
|
||||
CloseHandle (in);
|
||||
in = out = NULL;
|
||||
system_printf ("couldn't make handle %p noninheritable, %E", out);
|
||||
return;
|
||||
}
|
||||
_closeem = closeem;
|
||||
}
|
||||
|
||||
proc_pipe::~proc_pipe ()
|
||||
{
|
||||
if (_closeem)
|
||||
{
|
||||
if (in)
|
||||
CloseHandle (in);
|
||||
if (out)
|
||||
CloseHandle (out);
|
||||
}
|
||||
myself.unlock ();
|
||||
}
|
||||
|
||||
/* function to set up the process pipe and kick off proc_waiter */
|
||||
int
|
||||
pinfo::wait ()
|
||||
|
@ -111,6 +111,8 @@ public:
|
||||
|
||||
/* signals */
|
||||
HANDLE sendsig;
|
||||
HANDLE exec_sendsig;
|
||||
DWORD exec_dwProcessId;
|
||||
private:
|
||||
sigset_t sig_mask;
|
||||
public:
|
||||
@ -132,14 +134,14 @@ class pinfo
|
||||
public:
|
||||
HANDLE rd_proc_pipe;
|
||||
HANDLE hProcess;
|
||||
CRITICAL_SECTION lock;
|
||||
CRITICAL_SECTION _lock;
|
||||
/* Handle associated with initial Windows pid which started it all. */
|
||||
HANDLE pid_handle;
|
||||
void init (pid_t, DWORD, HANDLE = NULL) __attribute__ ((regparm(3)));
|
||||
pinfo () {}
|
||||
pinfo (_pinfo *x): procinfo (x), hProcess (NULL), pid_handle (NULL) {}
|
||||
pinfo (pid_t n) : rd_proc_pipe (NULL), hProcess (NULL), pid_handle (NULL) {init (n, 0);}
|
||||
pinfo (pid_t n, DWORD flag) : rd_proc_pipe (NULL), hProcess (NULL), pid_handle (NULL) {init (n, flag);}
|
||||
pinfo (pid_t n, DWORD flag) : rd_proc_pipe (NULL), hProcess (NULL), pid_handle (NULL) {init (n, flag);}
|
||||
void release ();
|
||||
int wait () __attribute__ ((regparm (1)));
|
||||
~pinfo ()
|
||||
@ -147,7 +149,9 @@ public:
|
||||
if (destroy && procinfo)
|
||||
release ();
|
||||
}
|
||||
|
||||
void initialize_lock () {InitializeCriticalSection (&_lock);}
|
||||
void lock () {EnterCriticalSection (&_lock);}
|
||||
void unlock () {LeaveCriticalSection (&_lock);}
|
||||
_pinfo *operator -> () const {return procinfo;}
|
||||
int operator == (pinfo *x) const {return x->procinfo == procinfo;}
|
||||
int operator == (pinfo &x) const {return x.procinfo == procinfo;}
|
||||
@ -175,6 +179,20 @@ public:
|
||||
void set_acl();
|
||||
};
|
||||
|
||||
class proc_pipe
|
||||
{
|
||||
bool _closeem;
|
||||
public:
|
||||
HANDLE in;
|
||||
HANDLE out;
|
||||
void set (bool);
|
||||
proc_pipe (bool closeem) {set (closeem);}
|
||||
proc_pipe () : _closeem (false), in (NULL), out (NULL) {};
|
||||
void close () {_closeem = true;}
|
||||
~proc_pipe ();
|
||||
int operator == (int x) {return (int) in == x;}
|
||||
};
|
||||
|
||||
#define ISSTATE(p, f) (!!((p)->process_state & f))
|
||||
#define NOTSTATE(p, f) (!((p)->process_state & f))
|
||||
|
||||
|
@ -200,19 +200,18 @@ proc_exists (_pinfo *p)
|
||||
return p && !(p->process_state & (PID_EXITED | PID_ZOMBIE));
|
||||
}
|
||||
|
||||
/* Return 1 if this is one of our children, zero otherwise.
|
||||
FIXME: This really should be integrated with the rest of the proc_subproc
|
||||
testing. Scanning these lists twice is inefficient. */
|
||||
bool __stdcall
|
||||
/* Return true if this is one of our children, false otherwise. */
|
||||
static inline bool __stdcall
|
||||
mychild (int pid)
|
||||
{
|
||||
pinfo p (pid);
|
||||
return p && p->ppid == myself->pid;
|
||||
for (int i = 0; i < nprocs; i++)
|
||||
if (procs[i]->pid == pid)
|
||||
return true;
|
||||
return false;
|
||||
}
|
||||
|
||||
/* Handle all subprocess requests
|
||||
*/
|
||||
#define vchild (*((pinfo *) val))
|
||||
int __stdcall
|
||||
proc_subproc (DWORD what, DWORD val)
|
||||
{
|
||||
@ -223,6 +222,7 @@ proc_subproc (DWORD what, DWORD val)
|
||||
waitq *w;
|
||||
|
||||
#define wval ((waitq *) val)
|
||||
#define vchild (*((pinfo *) val))
|
||||
|
||||
sigproc_printf ("args: %x, %d", what, val);
|
||||
|
||||
@ -244,18 +244,21 @@ proc_subproc (DWORD what, DWORD val)
|
||||
sigproc_printf ("proc table overflow: hit %d processes, pid %d\n",
|
||||
nprocs, vchild->pid);
|
||||
rc = 0;
|
||||
set_errno (EMFILE); // FIXMENOW - what's the right errno?
|
||||
set_errno (EAGAIN);
|
||||
break;
|
||||
}
|
||||
|
||||
vchild->ppid = myself->pid;
|
||||
vchild->uid = myself->uid;
|
||||
vchild->gid = myself->gid;
|
||||
vchild->pgid = myself->pgid;
|
||||
vchild->sid = myself->sid;
|
||||
vchild->ctty = myself->ctty;
|
||||
vchild->cygstarted = true;
|
||||
vchild->process_state |= PID_INITIALIZING | (myself->process_state & PID_USETTY);
|
||||
if (vchild != myself)
|
||||
{
|
||||
vchild->ppid = myself->pid;
|
||||
vchild->uid = myself->uid;
|
||||
vchild->gid = myself->gid;
|
||||
vchild->pgid = myself->pgid;
|
||||
vchild->sid = myself->sid;
|
||||
vchild->ctty = myself->ctty;
|
||||
vchild->cygstarted = true;
|
||||
vchild->process_state |= PID_INITIALIZING | (myself->process_state & PID_USETTY);
|
||||
}
|
||||
procs[nprocs] = vchild;
|
||||
rc = procs[nprocs].wait ();
|
||||
if (rc)
|
||||
@ -353,6 +356,8 @@ out:
|
||||
out1:
|
||||
sigproc_printf ("returning %d", rc);
|
||||
return rc;
|
||||
#undef wval
|
||||
#undef vchild
|
||||
}
|
||||
|
||||
// FIXME: This is inelegant
|
||||
@ -566,9 +571,27 @@ sig_send (_pinfo *p, siginfo_t& si, _cygtls *tls)
|
||||
sendsig = myself->sendsig;
|
||||
else
|
||||
{
|
||||
for (int i = 0; !p->dwProcessId && i < 10000; i++)
|
||||
HANDLE dupsig;
|
||||
DWORD dwProcessId;
|
||||
for (int i = 0; !p->sendsig && i < 10000; i++)
|
||||
low_priority_sleep (0);
|
||||
HANDLE hp = OpenProcess (PROCESS_DUP_HANDLE, false, p->dwProcessId);
|
||||
if (p->sendsig)
|
||||
{
|
||||
dupsig = p->sendsig;
|
||||
dwProcessId = p->dwProcessId;
|
||||
}
|
||||
else
|
||||
{
|
||||
dupsig = p->exec_sendsig;
|
||||
dwProcessId = p->exec_dwProcessId;
|
||||
}
|
||||
if (!dupsig)
|
||||
{
|
||||
set_errno (EAGAIN);
|
||||
sigproc_printf ("sendsig handle never materialized");
|
||||
goto out;
|
||||
}
|
||||
HANDLE hp = OpenProcess (PROCESS_DUP_HANDLE, false, dwProcessId);
|
||||
if (!hp)
|
||||
{
|
||||
sigproc_printf ("OpenProcess failed, %E");
|
||||
@ -576,14 +599,12 @@ sig_send (_pinfo *p, siginfo_t& si, _cygtls *tls)
|
||||
goto out;
|
||||
}
|
||||
VerifyHandle (hp);
|
||||
for (int i = 0; !p->sendsig && i < 10000; i++)
|
||||
low_priority_sleep (0);
|
||||
if (!DuplicateHandle (hp, p->sendsig, hMainProc, &sendsig, false, 0,
|
||||
if (!DuplicateHandle (hp, dupsig, hMainProc, &sendsig, false, 0,
|
||||
DUPLICATE_SAME_ACCESS) || !sendsig)
|
||||
{
|
||||
CloseHandle (hp);
|
||||
sigproc_printf ("DuplicateHandle failed, %E");
|
||||
__seterrno ();
|
||||
sigproc_printf ("DuplicateHandle failed, %E");
|
||||
CloseHandle (hp);
|
||||
goto out;
|
||||
}
|
||||
CloseHandle (hp);
|
||||
@ -695,17 +716,98 @@ out:
|
||||
/* Initialize some of the memory block passed to child processes
|
||||
by fork/spawn/exec. */
|
||||
|
||||
void __stdcall
|
||||
init_child_info (DWORD chtype, child_info *ch, HANDLE subproc_ready)
|
||||
child_info::child_info (unsigned in_cb, child_info_types chtype)
|
||||
{
|
||||
memset (ch, 0, sizeof *ch);
|
||||
ch->cb = chtype == PROC_FORK ? sizeof (child_info_fork) : sizeof (child_info);
|
||||
ch->intro = PROC_MAGIC_GENERIC;
|
||||
ch->magic = CHILD_INFO_MAGIC;
|
||||
ch->type = chtype;
|
||||
ch->subproc_ready = subproc_ready;
|
||||
ch->fhandler_union_cb = sizeof (fhandler_union);
|
||||
ch->user_h = cygwin_user_h;
|
||||
memset (this, 0, in_cb);
|
||||
cb = in_cb;
|
||||
intro = PROC_MAGIC_GENERIC;
|
||||
magic = CHILD_INFO_MAGIC;
|
||||
type = chtype;
|
||||
fhandler_union_cb = sizeof (fhandler_union);
|
||||
user_h = cygwin_user_h;
|
||||
if (chtype != PROC_SPAWN)
|
||||
subproc_ready = CreateEvent (&sec_all, FALSE, FALSE, NULL);
|
||||
sigproc_printf ("subproc_ready %p", subproc_ready);
|
||||
if (chtype != PROC_EXEC && myself->wr_proc_pipe != INVALID_HANDLE_VALUE)
|
||||
parent_wr_proc_pipe = myself->wr_proc_pipe;
|
||||
}
|
||||
|
||||
child_info::~child_info ()
|
||||
{
|
||||
if (subproc_ready)
|
||||
CloseHandle (subproc_ready);
|
||||
}
|
||||
|
||||
child_info_fork::child_info_fork () :
|
||||
child_info (sizeof *this, _PROC_FORK)
|
||||
{
|
||||
}
|
||||
|
||||
child_info_spawn::child_info_spawn (child_info_types chtype) :
|
||||
child_info (sizeof *this, chtype)
|
||||
{
|
||||
}
|
||||
|
||||
void
|
||||
child_info::ready (bool execed)
|
||||
{
|
||||
if (!subproc_ready)
|
||||
{
|
||||
sigproc_printf ("subproc_ready not set");
|
||||
return;
|
||||
}
|
||||
|
||||
if (!SetEvent (subproc_ready))
|
||||
api_fatal ("SetEvent failed");
|
||||
else
|
||||
sigproc_printf ("signalled %p that I was ready", subproc_ready);
|
||||
|
||||
if (execed)
|
||||
{
|
||||
CloseHandle (subproc_ready);
|
||||
subproc_ready = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
bool
|
||||
child_info::sync (pinfo& vchild, DWORD howlong)
|
||||
{
|
||||
if (!subproc_ready)
|
||||
{
|
||||
sigproc_printf ("not waiting. subproc_ready is NULL");
|
||||
return false;
|
||||
}
|
||||
|
||||
HANDLE w4[2];
|
||||
w4[0] = subproc_ready;
|
||||
w4[1] = vchild.hProcess;
|
||||
|
||||
bool res;
|
||||
sigproc_printf ("waiting for subproc_ready(%p) and child process(%p)", w4[0], w4[1]);
|
||||
switch (WaitForMultipleObjects (2, w4, FALSE, howlong))
|
||||
{
|
||||
case WAIT_OBJECT_0:
|
||||
sigproc_printf ("got subproc_ready for pid %d", vchild->pid);
|
||||
res = true;
|
||||
break;
|
||||
case WAIT_OBJECT_0 + 1:
|
||||
if (WaitForSingleObject (subproc_ready, 0) == WAIT_OBJECT_0)
|
||||
sigproc_printf ("should never happen. noticed subproc_ready after process exit");
|
||||
else
|
||||
{
|
||||
DWORD exitcode = 0;
|
||||
(void) GetExitCodeProcess (vchild.hProcess, &exitcode);
|
||||
vchild->exitcode = (exitcode & 0xff) << 8;
|
||||
sigproc_printf ("non-cygwin exit value is %p", exitcode);
|
||||
}
|
||||
res = false;
|
||||
break;
|
||||
default:
|
||||
system_printf ("wait failed, pid %d, %E", vchild->pid);
|
||||
res = false;
|
||||
break;
|
||||
}
|
||||
return res;
|
||||
}
|
||||
|
||||
/* Check the state of all of our children to see if any are stopped or
|
||||
|
@ -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);
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user