* 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:
Christopher Faylor 2004-12-24 18:31:23 +00:00
parent 4697fbcd51
commit e1736c2f13
8 changed files with 121 additions and 66 deletions

View File

@ -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>

View File

@ -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 ();

View File

@ -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");

View File

@ -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 ();

View File

@ -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
{
/* 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)
else if (cygheap->pid_handle)
{
ForceCloseHandle (cygheap->pid_handle);
cygheap->pid_handle = NULL;
}
}
# undef child_proc_info
return;
}
@ -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->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,27 +809,39 @@ 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))
else
{
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 = myself->wr_proc_pipe;
myself->wr_proc_pipe = INVALID_HANDLE_VALUE;
HANDLE closeit = wr_proc_pipe;
wr_proc_pipe = INVALID_HANDLE_VALUE;
CloseHandle (closeit);
}
}
return (bool) nb;
}

View File

@ -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))

View File

@ -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 ()

View File

@ -798,13 +798,25 @@ spawn_guts (const char * prog_arg, const char *const *argv,
/* 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). */
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);
myself.remember (false);
wait_for_myself = true;
myself->wr_proc_pipe = INVALID_HANDLE_VALUE;
}
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: