* 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> 2004-12-23 Pierre Humblet <pierre.humblet@ieee.org>
Christopher Faylor <cgf@timesys.com> Christopher Faylor <cgf@timesys.com>

View File

@ -29,7 +29,7 @@ enum child_info_types
#define EXEC_MAGIC_SIZE sizeof(child_info) #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 /* NOTE: Do not make gratuitous changes to the names or organization of the
below class. The layout is checksummed to determine compatibility between below class. The layout is checksummed to determine compatibility between
@ -49,7 +49,6 @@ public:
void *cygheap_max; void *cygheap_max;
DWORD cygheap_reserve_sz; DWORD cygheap_reserve_sz;
HANDLE cygheap_h; HANDLE cygheap_h;
HANDLE parent_wr_proc_pipe;
unsigned fhandler_union_cb; unsigned fhandler_union_cb;
child_info (unsigned, child_info_types); child_info (unsigned, child_info_types);
~child_info (); ~child_info ();

View File

@ -600,7 +600,7 @@ sig_handle_tty_stop (int sig)
} }
myself->stopsig = sig; myself->stopsig = sig;
myself.alert_parent (sig); myself->alert_parent (sig);
sigproc_printf ("process %d stopped by signal %d", myself->pid, sig); sigproc_printf ("process %d stopped by signal %d", myself->pid, sig);
HANDLE w4[2]; HANDLE w4[2];
w4[0] = sigCONT; w4[0] = sigCONT;
@ -610,7 +610,7 @@ sig_handle_tty_stop (int sig)
case WAIT_OBJECT_0: case WAIT_OBJECT_0:
case WAIT_OBJECT_0 + 1: case WAIT_OBJECT_0 + 1:
reset_signal_arrived (); reset_signal_arrived ();
myself.alert_parent (SIGCONT); myself->alert_parent (SIGCONT);
break; break;
default: default:
api_fatal ("WaitSingleObject failed, %E"); api_fatal ("WaitSingleObject failed, %E");

View File

@ -13,6 +13,7 @@ details. */
#include "thread.h" #include "thread.h"
#include "perprocess.h" #include "perprocess.h"
#include "cygtls.h" #include "cygtls.h"
#include "pinfo.h"
int NO_COPY dynamically_loaded; int NO_COPY dynamically_loaded;
static char *search_for = (char *) cygthread::stub; static char *search_for = (char *) cygthread::stub;
@ -126,6 +127,8 @@ dll_entry (HANDLE h, DWORD reason, void *static_load)
dll_crt0_0 (); dll_crt0_0 ();
break; break;
case DLL_PROCESS_DETACH: case DLL_PROCESS_DETACH:
if (myself)
myself->exitcode = 1 << 8;
break; break;
case DLL_THREAD_ATTACH: case DLL_THREAD_ATTACH:
munge_threadfunc (); munge_threadfunc ();

View File

@ -44,8 +44,6 @@ pinfo NO_COPY myself ((_pinfo *)&pinfo_dummy); // Avoid myself != NULL checks
void __stdcall void __stdcall
set_myself (HANDLE h) set_myself (HANDLE h)
{ {
extern child_info *child_proc_info;
if (!h) if (!h)
cygheap->pid = cygwin_pid (GetCurrentProcessId ()); cygheap->pid = cygwin_pid (GetCurrentProcessId ());
myself.init (cygheap->pid, PID_IN_USE | PID_MYSELF, h); myself.init (cygheap->pid, PID_IN_USE | PID_MYSELF, h);
@ -68,19 +66,11 @@ set_myself (HANDLE h)
} }
else if (!myself->wr_proc_pipe) else if (!myself->wr_proc_pipe)
myself->start_time = time (NULL); /* Register our starting time. */ 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, ForceCloseHandle (cygheap->pid_handle);
so close it. */ cygheap->pid_handle = NULL;
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;
}
} }
# undef child_proc_info
return; return;
} }
@ -117,9 +107,9 @@ _pinfo::exit (UINT n, bool norecord)
exit_state = ES_FINAL; exit_state = ES_FINAL;
cygthread::terminate (); cygthread::terminate ();
if (norecord) if (norecord)
sigproc_terminate (); /* Just terminate signal and process stuff */ sigproc_terminate (); /* Just terminate signal and process stuff */
else 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) if (this)
{ {
@ -135,7 +125,7 @@ _pinfo::exit (UINT n, bool norecord)
/* We could just let this happen automatically when the process /* We could just let this happen automatically when the process
exits but this should gain us a microsecond or so by notifying exits but this should gain us a microsecond or so by notifying
the parent early. */ 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); sigproc_printf ("Calling ExitProcess %d", n);
_my_tls.stacklock = 0; _my_tls.stacklock = 0;
_my_tls.stackptr = _my_tls.stack; _my_tls.stackptr = _my_tls.stack;
ExitProcess (n); myself.procinfo = NULL; // This breaks the abstraction a little doesn't it?
ExitProcess (exitcode);
} }
void void
@ -273,7 +264,10 @@ pinfo::init (pid_t n, DWORD flag, HANDLE in_h)
if (!created) if (!created)
/* nothing */; /* nothing */;
else if (!(flag & PID_EXECED)) else if (!(flag & PID_EXECED))
procinfo->pid = n; {
procinfo->pid = n;
procinfo->exitcode = SIGTERM;
}
else else
{ {
procinfo->process_state |= PID_IN_USE | PID_EXECED; 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 /* 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 created during new process creation. If the pipe is closed or a zero
assumed that the cygwin pid has exited. Otherwise, various "signals" is received on the pipe, it is assumed that the cygwin pid has exited.
can be sent to the parent to inform the parent to perform a certain Otherwise, various "signals" can be sent to the parent to inform the
action. 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. */
static DWORD WINAPI static DWORD WINAPI
proc_waiter (void *arg) proc_waiter (void *arg)
{ {
@ -768,29 +757,41 @@ proc_waiter (void *arg)
return 0; 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 */ /* function to set up the process pipe and kick off proc_waiter */
int int
pinfo::wait () pinfo::wait ()
{ {
HANDLE out;
/* FIXME: execed processes should be able to wait for pids that were started /* FIXME: execed processes should be able to wait for pids that were started
by the process which execed them. */ 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", system_printf ("Couldn't create pipe tracker for pid %d, %E",
(*this)->pid); (*this)->pid);
return 0; 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 (!(*this)->dup_proc_pipe (hProcess))
if (!DuplicateHandle (hMainProc, out, hProcess, &((*this)->wr_proc_pipe), 0,
TRUE, DUPLICATE_SAME_ACCESS))
{ {
system_printf ("Couldn't duplicate pipe topid %d(%p), %E", (*this)->pid, system_printf ("Couldn't duplicate pipe topid %d(%p), %E", (*this)->pid, hProcess);
hProcess);
return 0; return 0;
} }
CloseHandle (out); /* Don't need this end in this proces */
preserve (); /* Preserve the shared memory associated with the pinfo */ preserve (); /* Preserve the shared memory associated with the pinfo */
@ -808,26 +809,38 @@ pinfo::wait ()
return 1; 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 /* function to send a "signal" to the parent when something interesting happens
in the child. */ in the child. */
bool bool
pinfo::alert_parent (char sig) _pinfo::alert_parent (char sig)
{ {
DWORD nb = 0; DWORD nb = 0;
/* Send something to our parent. If the parent has gone away, /* Send something to our parent. If the parent has gone away,
close the pipe. */ close the pipe. */
if (myself->wr_proc_pipe == INVALID_HANDLE_VALUE if (wr_proc_pipe == INVALID_HANDLE_VALUE
|| !myself->wr_proc_pipe) || !myself->wr_proc_pipe)
/* no parent */; /* 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 else
{ {
HANDLE closeit = myself->wr_proc_pipe; sync_proc_pipe ();
myself->wr_proc_pipe = INVALID_HANDLE_VALUE; if (WriteFile (wr_proc_pipe, &sig, 1, &nb, NULL))
CloseHandle (closeit); /* 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; return (bool) nb;
} }

View File

@ -106,6 +106,9 @@ public:
bool alive (); bool alive ();
char *cmdline (size_t &); char *cmdline (size_t &);
void set_ctty (class tty_min *, int, class fhandler_tty_slave *); 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); friend void __stdcall set_myself (HANDLE);
@ -117,6 +120,7 @@ private:
sigset_t sig_mask; sigset_t sig_mask;
public: public:
HANDLE wr_proc_pipe; HANDLE wr_proc_pipe;
DWORD wr_proc_pipe_owner;
friend class pinfo; friend class pinfo;
}; };
@ -163,8 +167,6 @@ public:
operator _pinfo * () const {return procinfo;} operator _pinfo * () const {return procinfo;}
// operator bool () const {return (int) h;} // operator bool () const {return (int) h;}
void preserve () { destroy = false; } void preserve () { destroy = false; }
bool alert_parent (char);
bool parent_alive () { return alert_parent (__ALERT_ALIVE); }
#ifndef _SIGPROC_H #ifndef _SIGPROC_H
int remember () {system_printf ("remember is not here"); return 0;} int remember () {system_printf ("remember is not here"); return 0;}
#else #else
@ -178,6 +180,7 @@ public:
#endif #endif
HANDLE shared_handle () {return h;} HANDLE shared_handle () {return h;}
void set_acl(); void set_acl();
friend class _pinfo;
}; };
#define ISSTATE(p, f) (!!((p)->process_state & f)) #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) if (chtype != PROC_SPAWN)
subproc_ready = CreateEvent (&sec_all, FALSE, FALSE, NULL); subproc_ready = CreateEvent (&sec_all, FALSE, FALSE, NULL);
sigproc_printf ("subproc_ready %p", subproc_ready); 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 () child_info::~child_info ()

View File

@ -796,16 +796,28 @@ spawn_guts (const char * prog_arg, const char *const *argv,
sigproc_printf ("new process name %s", myself->progname); sigproc_printf ("new process name %s", myself->progname);
close_all_files (); close_all_files ();
/* If wr_proc_pipe doesn't exist then this process was not started by a cygwin /* 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" 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 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 is some minor special case code in proc_waiter and friends to accommodate
this). */ 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) if (!myself->wr_proc_pipe)
{ {
myself.remember (true); myself.remember (false);
wait_for_myself = true; 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 else
{ {
@ -849,14 +861,13 @@ ForceCloseHandle (pi.hThread);
sigproc_printf ("spawned windows pid %d", pi.dwProcessId); sigproc_printf ("spawned windows pid %d", pi.dwProcessId);
if (wait_for_myself) ciresrv.sync (myself, INFINITE);
waitpid (myself->pid, &res, 0);
else
ciresrv.sync (myself, INFINITE);
switch (mode) switch (mode)
{ {
case _P_OVERLAY: case _P_OVERLAY:
if (wait_for_myself)
waitpid (myself->pid, &res, 0);
myself->exit (res, 1); myself->exit (res, 1);
break; break;
case _P_WAIT: case _P_WAIT: