* child_info.h (CURR_CHILD_INFO_MAGIC): Update.
(child_info::parent_wr_proc_pipe): Eliminate. * pinfo.h (_pinfo::alert_parent): Move here from pinfo class. (_pinfo::dup_proc_pipe): New method. (_pinfo::sync_proc_pipe): Ditto. * exceptions.cc (sig_handle_tty_stop): Reflect move of alert_parent. * init.cc (dll_entry): Exit with status one if main process called ExitProcess. * pinfo.cc (set_myself): Remove handling of parent_wr_proc_pipe. (_pinfo::exit): Reflect move of alert_parent. Set procinfo to NULL to flag that we are exiting normally. Always use exitcode when exiting (although this could be a little racy). (pinfo::init): Set default exit to SIGTERM. This will be the exit code reported if process is terminated. (_pinfo::dup_proc_pipe): New function. (pinfo::wait): Duplicate wr_proc_pipe to the right place. Use dup_proc_pipe to move the pipe to the child. (_pinfo::sync_proc_pipe): New function. (_pinfo::alert_parent): Move to _pinfo. Make sure that wr_proc_pipe is ours before using it. * sigproc.cc (child_info::child_info): Remove handling of parent_wr_proc_pipe. * spawn.cc (spawn_guts): Pass our wr_proc_pipe to the child when execing. Ensure that exit code of cygwin process started from windows is correctly set.
This commit is contained in:
parent
4697fbcd51
commit
e1736c2f13
|
@ -1,3 +1,31 @@
|
|||
2004-12-24 Christopher Faylor <cgf@timesys.com>
|
||||
|
||||
* child_info.h (CURR_CHILD_INFO_MAGIC): Update.
|
||||
(child_info::parent_wr_proc_pipe): Eliminate.
|
||||
* pinfo.h (_pinfo::alert_parent): Move here from pinfo class.
|
||||
(_pinfo::dup_proc_pipe): New method.
|
||||
(_pinfo::sync_proc_pipe): Ditto.
|
||||
* exceptions.cc (sig_handle_tty_stop): Reflect move of alert_parent.
|
||||
* init.cc (dll_entry): Exit with status one if main process called
|
||||
ExitProcess.
|
||||
* pinfo.cc (set_myself): Remove handling of parent_wr_proc_pipe.
|
||||
(_pinfo::exit): Reflect move of alert_parent. Set procinfo to NULL to
|
||||
flag that we are exiting normally. Always use exitcode when exiting
|
||||
(although this could be a little racy).
|
||||
(pinfo::init): Set default exit to SIGTERM. This will be the exit code
|
||||
reported if process is terminated.
|
||||
(_pinfo::dup_proc_pipe): New function.
|
||||
(pinfo::wait): Duplicate wr_proc_pipe to the right place. Use
|
||||
dup_proc_pipe to move the pipe to the child.
|
||||
(_pinfo::sync_proc_pipe): New function.
|
||||
(_pinfo::alert_parent): Move to _pinfo. Make sure that wr_proc_pipe is
|
||||
ours before using it.
|
||||
* sigproc.cc (child_info::child_info): Remove handling of
|
||||
parent_wr_proc_pipe.
|
||||
* spawn.cc (spawn_guts): Pass our wr_proc_pipe to the child when
|
||||
execing. Ensure that exit code of cygwin process started from windows
|
||||
is correctly set.
|
||||
|
||||
2004-12-23 Pierre Humblet <pierre.humblet@ieee.org>
|
||||
Christopher Faylor <cgf@timesys.com>
|
||||
|
||||
|
|
|
@ -29,7 +29,7 @@ enum child_info_types
|
|||
|
||||
#define EXEC_MAGIC_SIZE sizeof(child_info)
|
||||
|
||||
#define CURR_CHILD_INFO_MAGIC 0x17ad771aU
|
||||
#define CURR_CHILD_INFO_MAGIC 0xd079e02U
|
||||
|
||||
/* NOTE: Do not make gratuitous changes to the names or organization of the
|
||||
below class. The layout is checksummed to determine compatibility between
|
||||
|
@ -49,7 +49,6 @@ public:
|
|||
void *cygheap_max;
|
||||
DWORD cygheap_reserve_sz;
|
||||
HANDLE cygheap_h;
|
||||
HANDLE parent_wr_proc_pipe;
|
||||
unsigned fhandler_union_cb;
|
||||
child_info (unsigned, child_info_types);
|
||||
~child_info ();
|
||||
|
|
|
@ -600,7 +600,7 @@ sig_handle_tty_stop (int sig)
|
|||
}
|
||||
|
||||
myself->stopsig = sig;
|
||||
myself.alert_parent (sig);
|
||||
myself->alert_parent (sig);
|
||||
sigproc_printf ("process %d stopped by signal %d", myself->pid, sig);
|
||||
HANDLE w4[2];
|
||||
w4[0] = sigCONT;
|
||||
|
@ -610,7 +610,7 @@ sig_handle_tty_stop (int sig)
|
|||
case WAIT_OBJECT_0:
|
||||
case WAIT_OBJECT_0 + 1:
|
||||
reset_signal_arrived ();
|
||||
myself.alert_parent (SIGCONT);
|
||||
myself->alert_parent (SIGCONT);
|
||||
break;
|
||||
default:
|
||||
api_fatal ("WaitSingleObject failed, %E");
|
||||
|
|
|
@ -13,6 +13,7 @@ details. */
|
|||
#include "thread.h"
|
||||
#include "perprocess.h"
|
||||
#include "cygtls.h"
|
||||
#include "pinfo.h"
|
||||
|
||||
int NO_COPY dynamically_loaded;
|
||||
static char *search_for = (char *) cygthread::stub;
|
||||
|
@ -126,6 +127,8 @@ dll_entry (HANDLE h, DWORD reason, void *static_load)
|
|||
dll_crt0_0 ();
|
||||
break;
|
||||
case DLL_PROCESS_DETACH:
|
||||
if (myself)
|
||||
myself->exitcode = 1 << 8;
|
||||
break;
|
||||
case DLL_THREAD_ATTACH:
|
||||
munge_threadfunc ();
|
||||
|
|
|
@ -44,8 +44,6 @@ pinfo NO_COPY myself ((_pinfo *)&pinfo_dummy); // Avoid myself != NULL checks
|
|||
void __stdcall
|
||||
set_myself (HANDLE h)
|
||||
{
|
||||
extern child_info *child_proc_info;
|
||||
|
||||
if (!h)
|
||||
cygheap->pid = cygwin_pid (GetCurrentProcessId ());
|
||||
myself.init (cygheap->pid, PID_IN_USE | PID_MYSELF, h);
|
||||
|
@ -68,19 +66,11 @@ set_myself (HANDLE h)
|
|||
}
|
||||
else if (!myself->wr_proc_pipe)
|
||||
myself->start_time = time (NULL); /* Register our starting time. */
|
||||
else
|
||||
else if (cygheap->pid_handle)
|
||||
{
|
||||
/* We've inherited the parent's wr_proc_pipe. We don't need it,
|
||||
so close it. */
|
||||
if (child_proc_info->parent_wr_proc_pipe)
|
||||
CloseHandle (child_proc_info->parent_wr_proc_pipe);
|
||||
if (cygheap->pid_handle)
|
||||
{
|
||||
ForceCloseHandle (cygheap->pid_handle);
|
||||
cygheap->pid_handle = NULL;
|
||||
}
|
||||
ForceCloseHandle (cygheap->pid_handle);
|
||||
cygheap->pid_handle = NULL;
|
||||
}
|
||||
# undef child_proc_info
|
||||
return;
|
||||
}
|
||||
|
||||
|
@ -117,9 +107,9 @@ _pinfo::exit (UINT n, bool norecord)
|
|||
exit_state = ES_FINAL;
|
||||
cygthread::terminate ();
|
||||
if (norecord)
|
||||
sigproc_terminate (); /* Just terminate signal and process stuff */
|
||||
sigproc_terminate (); /* Just terminate signal and process stuff */
|
||||
else
|
||||
exitcode = n; /* We're really exiting. Record the UNIX exit code. */
|
||||
exitcode = n; /* We're really exiting. Record the UNIX exit code. */
|
||||
|
||||
if (this)
|
||||
{
|
||||
|
@ -135,7 +125,7 @@ _pinfo::exit (UINT n, bool norecord)
|
|||
/* We could just let this happen automatically when the process
|
||||
exits but this should gain us a microsecond or so by notifying
|
||||
the parent early. */
|
||||
myself.alert_parent (0);
|
||||
myself->alert_parent (0);
|
||||
|
||||
}
|
||||
}
|
||||
|
@ -143,7 +133,8 @@ _pinfo::exit (UINT n, bool norecord)
|
|||
sigproc_printf ("Calling ExitProcess %d", n);
|
||||
_my_tls.stacklock = 0;
|
||||
_my_tls.stackptr = _my_tls.stack;
|
||||
ExitProcess (n);
|
||||
myself.procinfo = NULL; // This breaks the abstraction a little doesn't it?
|
||||
ExitProcess (exitcode);
|
||||
}
|
||||
|
||||
void
|
||||
|
@ -273,7 +264,10 @@ pinfo::init (pid_t n, DWORD flag, HANDLE in_h)
|
|||
if (!created)
|
||||
/* nothing */;
|
||||
else if (!(flag & PID_EXECED))
|
||||
procinfo->pid = n;
|
||||
{
|
||||
procinfo->pid = n;
|
||||
procinfo->exitcode = SIGTERM;
|
||||
}
|
||||
else
|
||||
{
|
||||
procinfo->process_state |= PID_IN_USE | PID_EXECED;
|
||||
|
@ -664,15 +658,10 @@ _pinfo::cmdline (size_t& n)
|
|||
}
|
||||
|
||||
/* This is the workhorse which waits for the write end of the pipe
|
||||
created during new process creation. If the pipe is closed, it is
|
||||
assumed that the cygwin pid has exited. Otherwise, various "signals"
|
||||
can be sent to the parent to inform the parent to perform a certain
|
||||
action.
|
||||
|
||||
This code was originally written to eliminate the need for "reparenting"
|
||||
but, unfortunately, reparenting is still needed in order to get the
|
||||
exit code of an execed windows process. Otherwise, the exit code of
|
||||
a cygwin process comes from the exitcode field in _pinfo. */
|
||||
created during new process creation. If the pipe is closed or a zero
|
||||
is received on the pipe, it is assumed that the cygwin pid has exited.
|
||||
Otherwise, various "signals" can be sent to the parent to inform the
|
||||
parent to perform a certain action. */
|
||||
static DWORD WINAPI
|
||||
proc_waiter (void *arg)
|
||||
{
|
||||
|
@ -768,29 +757,41 @@ proc_waiter (void *arg)
|
|||
return 0;
|
||||
}
|
||||
|
||||
bool
|
||||
_pinfo::dup_proc_pipe (HANDLE hProcess)
|
||||
{
|
||||
bool res = DuplicateHandle (hMainProc, wr_proc_pipe, hProcess, &wr_proc_pipe,
|
||||
0, FALSE,
|
||||
DUPLICATE_SAME_ACCESS | DUPLICATE_CLOSE_SOURCE);
|
||||
if (!res)
|
||||
sigproc_printf ("DuplicateHandle failed, pid %d, hProcess %p, %E", pid, hProcess);
|
||||
else
|
||||
{
|
||||
wr_proc_pipe_owner = dwProcessId;
|
||||
sigproc_printf ("closed wr_proc_pipe %p for pid %d(%u)", wr_proc_pipe,
|
||||
pid, dwProcessId);
|
||||
}
|
||||
return res;
|
||||
}
|
||||
|
||||
/* function to set up the process pipe and kick off proc_waiter */
|
||||
int
|
||||
pinfo::wait ()
|
||||
{
|
||||
HANDLE out;
|
||||
/* FIXME: execed processes should be able to wait for pids that were started
|
||||
by the process which execed them. */
|
||||
if (!CreatePipe (&rd_proc_pipe, &out, &sec_none_nih, 16))
|
||||
if (!CreatePipe (&rd_proc_pipe, &((*this)->wr_proc_pipe), &sec_none_nih, 16))
|
||||
{
|
||||
system_printf ("Couldn't create pipe tracker for pid %d, %E",
|
||||
(*this)->pid);
|
||||
return 0;
|
||||
}
|
||||
/* 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, hProcess, &((*this)->wr_proc_pipe), 0,
|
||||
TRUE, DUPLICATE_SAME_ACCESS))
|
||||
|
||||
if (!(*this)->dup_proc_pipe (hProcess))
|
||||
{
|
||||
system_printf ("Couldn't duplicate pipe topid %d(%p), %E", (*this)->pid,
|
||||
hProcess);
|
||||
system_printf ("Couldn't duplicate pipe topid %d(%p), %E", (*this)->pid, hProcess);
|
||||
return 0;
|
||||
}
|
||||
CloseHandle (out); /* Don't need this end in this proces */
|
||||
|
||||
preserve (); /* Preserve the shared memory associated with the pinfo */
|
||||
|
||||
|
@ -808,26 +809,38 @@ pinfo::wait ()
|
|||
return 1;
|
||||
}
|
||||
|
||||
void
|
||||
_pinfo::sync_proc_pipe ()
|
||||
{
|
||||
if (wr_proc_pipe && wr_proc_pipe != INVALID_HANDLE_VALUE)
|
||||
while (wr_proc_pipe_owner != GetCurrentProcessId ())
|
||||
low_priority_sleep (0);
|
||||
}
|
||||
|
||||
/* function to send a "signal" to the parent when something interesting happens
|
||||
in the child. */
|
||||
bool
|
||||
pinfo::alert_parent (char sig)
|
||||
_pinfo::alert_parent (char sig)
|
||||
{
|
||||
DWORD nb = 0;
|
||||
/* Send something to our parent. If the parent has gone away,
|
||||
close the pipe. */
|
||||
if (myself->wr_proc_pipe == INVALID_HANDLE_VALUE
|
||||
if (wr_proc_pipe == INVALID_HANDLE_VALUE
|
||||
|| !myself->wr_proc_pipe)
|
||||
/* no parent */;
|
||||
else if (WriteFile (myself->wr_proc_pipe, &sig, 1, &nb, NULL))
|
||||
/* all is well */;
|
||||
else if (GetLastError () != ERROR_BROKEN_PIPE)
|
||||
debug_printf ("sending %d notification to parent failed, %E", sig);
|
||||
else
|
||||
{
|
||||
HANDLE closeit = myself->wr_proc_pipe;
|
||||
myself->wr_proc_pipe = INVALID_HANDLE_VALUE;
|
||||
CloseHandle (closeit);
|
||||
sync_proc_pipe ();
|
||||
if (WriteFile (wr_proc_pipe, &sig, 1, &nb, NULL))
|
||||
/* all is well */;
|
||||
else if (GetLastError () != ERROR_BROKEN_PIPE)
|
||||
debug_printf ("sending %d notification to parent failed, %E", sig);
|
||||
else
|
||||
{
|
||||
HANDLE closeit = wr_proc_pipe;
|
||||
wr_proc_pipe = INVALID_HANDLE_VALUE;
|
||||
CloseHandle (closeit);
|
||||
}
|
||||
}
|
||||
return (bool) nb;
|
||||
}
|
||||
|
|
|
@ -106,6 +106,9 @@ public:
|
|||
bool alive ();
|
||||
char *cmdline (size_t &);
|
||||
void set_ctty (class tty_min *, int, class fhandler_tty_slave *);
|
||||
bool dup_proc_pipe (HANDLE) __attribute__ ((regparm(2)));
|
||||
void sync_proc_pipe ();
|
||||
bool alert_parent (char);
|
||||
|
||||
friend void __stdcall set_myself (HANDLE);
|
||||
|
||||
|
@ -117,6 +120,7 @@ private:
|
|||
sigset_t sig_mask;
|
||||
public:
|
||||
HANDLE wr_proc_pipe;
|
||||
DWORD wr_proc_pipe_owner;
|
||||
friend class pinfo;
|
||||
};
|
||||
|
||||
|
@ -163,8 +167,6 @@ public:
|
|||
operator _pinfo * () const {return procinfo;}
|
||||
// operator bool () const {return (int) h;}
|
||||
void preserve () { destroy = false; }
|
||||
bool alert_parent (char);
|
||||
bool parent_alive () { return alert_parent (__ALERT_ALIVE); }
|
||||
#ifndef _SIGPROC_H
|
||||
int remember () {system_printf ("remember is not here"); return 0;}
|
||||
#else
|
||||
|
@ -178,6 +180,7 @@ public:
|
|||
#endif
|
||||
HANDLE shared_handle () {return h;}
|
||||
void set_acl();
|
||||
friend class _pinfo;
|
||||
};
|
||||
|
||||
#define ISSTATE(p, f) (!!((p)->process_state & f))
|
||||
|
|
|
@ -735,8 +735,6 @@ child_info::child_info (unsigned in_cb, child_info_types chtype)
|
|||
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 ()
|
||||
|
|
|
@ -796,16 +796,28 @@ spawn_guts (const char * prog_arg, const char *const *argv,
|
|||
sigproc_printf ("new process name %s", myself->progname);
|
||||
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). */
|
||||
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 exists, then it should be duplicated to the child.
|
||||
If the child has exited already, that's ok. The parent will pick up
|
||||
on this fact when we exit. dup_proc_pipe also closes our end of the pipe.
|
||||
Note that wr_proc_pipe may also be == INVALID_HANDLE_VALUE. That will make
|
||||
dup_proc_pipe essentially a no-op. */
|
||||
if (!myself->wr_proc_pipe)
|
||||
{
|
||||
myself.remember (true);
|
||||
wait_for_myself = true;
|
||||
myself->wr_proc_pipe = INVALID_HANDLE_VALUE;
|
||||
}
|
||||
{
|
||||
myself.remember (false);
|
||||
wait_for_myself = true;
|
||||
}
|
||||
else
|
||||
{
|
||||
/* Make sure that we own wr_proc_pipe just in case we've been
|
||||
previously execed. */
|
||||
myself->sync_proc_pipe ();
|
||||
(void) myself->dup_proc_pipe (pi.hProcess);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
|
@ -849,14 +861,13 @@ ForceCloseHandle (pi.hThread);
|
|||
|
||||
sigproc_printf ("spawned windows pid %d", pi.dwProcessId);
|
||||
|
||||
if (wait_for_myself)
|
||||
waitpid (myself->pid, &res, 0);
|
||||
else
|
||||
ciresrv.sync (myself, INFINITE);
|
||||
ciresrv.sync (myself, INFINITE);
|
||||
|
||||
switch (mode)
|
||||
{
|
||||
case _P_OVERLAY:
|
||||
if (wait_for_myself)
|
||||
waitpid (myself->pid, &res, 0);
|
||||
myself->exit (res, 1);
|
||||
break;
|
||||
case _P_WAIT:
|
||||
|
|
Loading…
Reference in New Issue