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

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

View File

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

View File

@ -29,7 +29,7 @@ enum
#define EXEC_MAGIC_SIZE sizeof(child_info)
#define CURR_CHILD_INFO_MAGIC 0x19c16fb6U
#define CURR_CHILD_INFO_MAGIC 0x83e9a7b7U
/* NOTE: Do not make gratuitous changes to the names or organization of the
below class. The layout is checksummed to determine compatibility between
@ -45,7 +45,6 @@ public:
HANDLE subproc_ready; // used for synchronization with parent
HANDLE user_h;
HANDLE parent;
HANDLE pppid_handle;
init_cygheap *cygheap;
void *cygheap_max;
DWORD cygheap_reserve_sz;
@ -83,7 +82,6 @@ class child_info_spawn: public child_info
{
public:
cygheap_exec_info *moreinfo;
HANDLE hexec_proc;
child_info_spawn (): moreinfo (NULL) {}
~child_info_spawn ()

View File

@ -289,6 +289,7 @@ struct init_cygheap
size_t sthreads;
int open_fhs;
pid_t pid; /* my pid */
HANDLE pid_handle; /* handle for my pid */
void close_ctty ();
};

View File

@ -11,7 +11,6 @@ details. */
#include <stdlib.h>
#include "exceptions.h"
#include "security.h"
#include "cygthread.h"
#include "sync.h"
#include "cygerrno.h"
#include "sigproc.h"
@ -33,6 +32,7 @@ DWORD WINAPI
cygthread::stub (VOID *arg)
{
cygthread *info = (cygthread *) arg;
_my_tls._ctinfo = info;
if (info->arg == cygself)
{
if (info->ev)
@ -69,7 +69,8 @@ cygthread::stub (VOID *arg)
info->func = NULL; // catch erroneous activation
#endif
info->__name = NULL;
SetEvent (info->ev);
if (info->inuse)
SetEvent (info->ev);
}
switch (WaitForSingleObject (info->thread_sync, INFINITE))
{
@ -88,6 +89,7 @@ DWORD WINAPI
cygthread::simplestub (VOID *arg)
{
cygthread *info = (cygthread *) arg;
_my_tls._ctinfo = info;
info->stack_ptr = &arg;
info->ev = info->h;
info->func (info->arg == cygself ? info : info->arg);

View File

@ -6,6 +6,9 @@ This software is a copyrighted work licensed under the terms of the
Cygwin license. Please consult the file "CYGWIN_LICENSE" for
details. */
#ifndef _CYGTHREAD_H
#define _CYGTHREAD_H
class cygthread
{
LONG inuse;
@ -25,6 +28,7 @@ class cygthread
static DWORD WINAPI simplestub (VOID *);
static DWORD main_thread_id;
static const char * name (DWORD = 0);
void release () { __name = NULL; inuse = false; }
cygthread (LPTHREAD_START_ROUTINE, LPVOID, const char *);
cygthread () {};
static void init ();
@ -43,3 +47,4 @@ class cygthread
};
#define cygself NULL
#endif /*_CYGTHREAD_H*/

View File

@ -19,7 +19,6 @@ details. */
#include "fhandler.h"
#include "dtable.h"
#include "cygheap.h"
#include "cygthread.h"
#include "pinfo.h"
#include "sigproc.h"

View File

@ -32,6 +32,8 @@ details. */
#define TLS_STACK_SIZE 256
#include "cygthread.h"
#pragma pack(push,4)
struct _local_storage
{
@ -131,6 +133,7 @@ struct _cygtls
char __dontuse[8 * ((sizeof(struct _reent) + 4) / 8)];
};
struct _local_storage locals;
class cygthread *_ctinfo;
waitq wq;
struct _cygtls *prev, *next;
__stack_t *stackptr;

View File

@ -29,11 +29,10 @@ details. */
#include "dtable.h"
#include "cygheap.h"
#include "child_info_magic.h"
#include "perthread.h"
#include "cygtls.h"
#include "shared_info.h"
#include "cygwin_version.h"
#include "dll_init.h"
#include "cygthread.h"
#include "sync.h"
#include "heap.h"
@ -44,16 +43,6 @@ details. */
HANDLE NO_COPY hMainProc = (HANDLE) -1;
HANDLE NO_COPY hMainThread;
#ifdef NEWVFORK
per_thread_vfork NO_COPY vfork_storage;
#endif
per_thread NO_COPY *threadstuff[] = {
#ifdef NEWVFORK
&vfork_storage,
#endif
NULL};
bool display_title;
bool strip_title_path;
bool allow_glob = true;
@ -656,8 +645,6 @@ dll_crt0_0 ()
memory_init ();
else
{
bool close_ppid_handle = false;
bool close_hexec_proc = false;
switch (child_proc_info->type)
{
case _PROC_FORK:
@ -665,16 +652,9 @@ dll_crt0_0 ()
cygheap_fixup_in_child (false);
memory_init ();
set_myself (NULL);
close_ppid_handle = !!child_proc_info->pppid_handle;
break;
case _PROC_SPAWN:
/* Have to delay closes until after cygheap is setup */
close_hexec_proc = !!spawn_info->hexec_proc;
close_ppid_handle = !!child_proc_info->pppid_handle;
goto around;
case _PROC_EXEC:
hexec_proc = spawn_info->hexec_proc;
around:
HANDLE h;
cygheap_fixup_in_child (true);
memory_init ();
@ -697,10 +677,6 @@ dll_crt0_0 ()
}
break;
}
if (close_hexec_proc)
CloseHandle (spawn_info->hexec_proc);
if (close_ppid_handle)
CloseHandle (child_proc_info->pppid_handle);
}
_cygtls::init ();
@ -1014,13 +990,10 @@ do_exit (int status)
if (exit_state < ES_SIGNAL)
{
exit_state = ES_SIGNAL;
if (!(n & EXIT_REPARENTING))
{
signal (SIGCHLD, SIG_IGN);
signal (SIGHUP, SIG_IGN);
signal (SIGINT, SIG_IGN);
signal (SIGQUIT, SIG_IGN);
}
signal (SIGCHLD, SIG_IGN);
signal (SIGHUP, SIG_IGN);
signal (SIGINT, SIG_IGN);
signal (SIGQUIT, SIG_IGN);
}
if (exit_state < ES_CLOSEALL)
@ -1112,7 +1085,7 @@ cygwin_exit (int n)
extern "C" void
_exit (int n)
{
do_exit ((DWORD) n & 0xffff);
do_exit (((DWORD) n & 0xff) << 8);
}
extern "C" void

View File

@ -11,7 +11,6 @@ details. */
#include "sync.h"
#include "sigproc.h"
#include "pinfo.h"
#include "perthread.h"
#include "perprocess.h"
#include "security.h"
#include "cygerrno.h"

View File

@ -140,7 +140,7 @@ dtable::stdio_init ()
Also, always set them even if we're to pick up our parent's fds
in case they're missed. */
if (myself->ppid_handle || ISSTATE (myself, PID_CYGPARENT))
if (myself->cygstarted || ISSTATE (myself, PID_CYGPARENT))
return;
HANDLE in = GetStdHandle (STD_INPUT_HANDLE);

View File

@ -20,12 +20,9 @@ details. */
#include "cygtls.h"
#include "sigproc.h"
#include "cygerrno.h"
#define NEED_VFORK
#include "perthread.h"
#include "shared_info.h"
#include "perprocess.h"
#include "security.h"
#include "cygthread.h"
#define CALL_HANDLER_RETRY 20
@ -159,7 +156,7 @@ open_stackdumpfile ()
CREATE_ALWAYS, 0, 0);
if (h != INVALID_HANDLE_VALUE)
{
if (!myself->ppid_handle)
if (!myself->cygstarted)
system_printf ("Dumping stack trace to %s", corefile);
else
debug_printf ("Dumping stack trace to %s", corefile);
@ -514,7 +511,7 @@ handle_exceptions (EXCEPTION_RECORD *e0, void *frame, CONTEXT *in0, void *)
|| (void *) global_sigs[si.si_signo].sa_handler == (void *) SIG_ERR)
{
/* Print the exception to the console */
if (!myself->ppid_handle)
if (!myself->cygstarted)
for (int i = 0; status_info[i].name; i++)
if (status_info[i].code == e.ExceptionCode)
{
@ -596,31 +593,15 @@ sig_handle_tty_stop (int sig)
_my_tls.incyg = 1;
/* Silently ignore attempts to suspend if there is no accommodating
cygwin parent to deal with this behavior. */
if (!myself->ppid_handle)
if (!myself->cygstarted)
{
myself->process_state &= ~PID_STOPPED;
return;
}
myself->stopsig = sig;
/* See if we have a living parent. If so, send it a special signal.
It will figure out exactly which pid has stopped by scanning
its list of subprocesses. */
if (my_parent_is_alive ())
{
pinfo parent (myself->ppid);
if (NOTSTATE (parent, PID_NOCLDSTOP))
{
siginfo_t si;
si.si_signo = SIGCHLD;
si.si_code = SI_KERNEL;
si.si_sigval.sival_int = CLD_STOPPED;
si.si_errno = si.si_pid = si.si_uid = si.si_errno = 0;
sig_send (parent, si);
}
}
sigproc_printf ("process %d stopped by signal %d, myself->ppid_handle %p",
myself->pid, sig, myself->ppid_handle);
myself.alert_parent (sig);
sigproc_printf ("process %d stopped by signal %d", myself->pid, sig);
HANDLE w4[2];
w4[0] = sigCONT;
w4[1] = signal_arrived;
@ -629,6 +610,7 @@ sig_handle_tty_stop (int sig)
case WAIT_OBJECT_0:
case WAIT_OBJECT_0 + 1:
reset_signal_arrived ();
myself.alert_parent (SIGCONT);
break;
default:
api_fatal ("WaitSingleObject failed, %E");
@ -807,7 +789,7 @@ ctrl_c_handler (DWORD type)
if (!cygwin_finished_initializing)
{
if (myself->ppid_handle) /* Was this process created by a cygwin process? */
if (myself->cygstarted) /* Was this process created by a cygwin process? */
return TRUE; /* Yes. Let the parent eventually handle CTRL-C issues. */
debug_printf ("exiting with status %p", STATUS_CONTROL_C_EXIT);
ExitProcess (STATUS_CONTROL_C_EXIT);
@ -982,7 +964,7 @@ sigpacket::process ()
bool special_case;
bool insigwait_mask;
insigwait_mask = masked = false;
if (special_case = (VFORKPID || ISSTATE (myself, PID_STOPPED)))
if (special_case = (/*VFORKPID || */ISSTATE (myself, PID_STOPPED)))
/* nothing to do */;
else if (tls && sigismember (&tls->sigwait_mask, si.si_signo))
insigwait_mask = true;
@ -1097,7 +1079,6 @@ static void
signal_exit (int rc)
{
EnterCriticalSection (&exit_lock);
rc = EXIT_SIGNAL | (rc << 8);
if (exit_already++)
myself->exit (rc);

View File

@ -25,7 +25,6 @@ details. */
#include "cygheap.h"
#include "wincap.h"
#include "heap.h"
#include "cygthread.h"
#include "pwdgrp.h"
#include "cygtls.h"
@ -72,7 +71,6 @@ fillout_pinfo (pid_t pid, int winpid)
ep.ctty = p->ctty;
ep.pid = p->pid;
ep.ppid = p->ppid;
ep.hProcess = p->hProcess;
ep.dwProcessId = p->dwProcessId;
ep.uid = p->uid;
ep.gid = p->gid;

View File

@ -28,7 +28,6 @@ details. */
#include "sigproc.h"
#include "pinfo.h"
#include "shared_info.h"
#include "cygthread.h"
#include "cygtls.h"
#define CONVERT_LIMIT 16384

View File

@ -771,7 +771,10 @@ fhandler_tty_slave::read (void *ptr, size_t& len)
rc = WaitForMultipleObjects (2, w4, FALSE, waiter);
if (rc == WAIT_TIMEOUT)
break;
{
termios_printf ("wait timed out, waiter %u", waiter);
break;
}
if (rc == WAIT_FAILED)
{

View File

@ -22,8 +22,7 @@ details. */
#include "pinfo.h"
#include "cygheap.h"
#include "child_info.h"
#define NEED_VFORK
#include "perthread.h"
#include "cygtls.h"
#include "perprocess.h"
#include "dll_init.h"
#include "sync.h"
@ -42,17 +41,6 @@ details. */
#define dll_bss_start &_bss_start__
#define dll_bss_end &_bss_end__
void
per_thread::set (void *s)
{
if (s == PER_THREAD_FORK_CLEAR)
{
tls = TlsAlloc ();
s = NULL;
}
TlsSetValue (get_tls (), s);
}
static void
stack_base (child_info_fork &ch)
{
@ -296,7 +284,6 @@ fork_child (HANDLE& hParent, dll *&first_dll, bool& load_dlls)
(void) ForceCloseHandle1 (fork_info->subproc_ready, subproc_ready);
(void) ForceCloseHandle1 (fork_info->forker_finished, forker_finished);
pinfo_fixup_after_fork ();
_my_tls.fixup_after_fork ();
sigproc_init ();
@ -305,13 +292,6 @@ fork_child (HANDLE& hParent, dll *&first_dll, bool& load_dlls)
api_fatal ("recreate_shm areas after fork failed");
#endif
/* Set thread local stuff to zero. Under Windows 95/98 this is sometimes
non-zero, for some reason.
FIXME: There is a memory leak here after a fork. */
for (per_thread **t = threadstuff; *t; t++)
if ((*t)->clear_on_fork ())
(*t)->set ();
pthread::atforkchild ();
fixup_timers_after_fork ();
cygbench ("fork-child");
@ -356,8 +336,6 @@ fork_parent (HANDLE& hParent, dll *&first_dll,
pthread::atforkprepare ();
subproc_init ();
int c_flags = GetPriorityClass (hMainProc) /*|
CREATE_NEW_PROCESS_GROUP*/;
STARTUPINFO si = {0, NULL, NULL, NULL, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, NULL, NULL, NULL, NULL};
@ -384,7 +362,7 @@ fork_parent (HANDLE& hParent, dll *&first_dll,
/* Create an inheritable handle to pass to the child process. This will
allow the child to duplicate handles from the parent to itself. */
hParent = NULL;
if (!DuplicateHandle (hMainProc, hMainProc, hMainProc, &hParent, 0, 1,
if (!DuplicateHandle (hMainProc, hMainProc, hMainProc, &hParent, 0, TRUE,
DUPLICATE_SAME_ACCESS))
{
system_printf ("couldn't create handle to myself for child, %E");
@ -501,8 +479,8 @@ fork_parent (HANDLE& hParent, dll *&first_dll,
ProtectHandle1 (pi.hProcess, childhProc);
/* Fill in fields in the child's process table entry. */
forked->hProcess = pi.hProcess;
forked->dwProcessId = pi.dwProcessId;
forked.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

View File

@ -232,7 +232,7 @@ struct external_pinfo
{
pid_t pid;
pid_t ppid;
HANDLE hProcess;
DWORD exitcode;
DWORD dwProcessId, dwSpawnedProcessId;
__uid16_t uid;
__gid16_t gid;

View File

@ -1,6 +1,6 @@
/* sys/wait.h
Copyright 1997, 1998, 2001 Red Hat, Inc.
Copyright 1997, 1998, 2001, 2002, 2003, 2004 Red Hat, Inc.
This file is part of Cygwin.
@ -36,6 +36,7 @@ extern "C" {
#define WEXITSTATUS(w) (((w) >> 8) & 0xff)
#define WTERMSIG(w) ((w) & 0x7f)
#define WSTOPSIG WEXITSTATUS
#define WCOREDUMP(w) (WIFSIGNALED(w) && (w & 0x80))
pid_t wait (int *);
pid_t waitpid (pid_t, int *, int);

View File

@ -12,7 +12,6 @@ details. */
#include <stdlib.h>
#include "thread.h"
#include "perprocess.h"
#include "cygthread.h"
#include "cygtls.h"
int NO_COPY dynamically_loaded;

View File

@ -1,86 +0,0 @@
/* perthread.h: Header file for cygwin thread-local storage.
Copyright 2000, 2001, 2002, 2003, 2004 Red Hat, Inc.
Written by Christopher Faylor <cgf@cygnus.com>
This file is part of Cygwin.
This software is a copyrighted work licensed under the terms of the
Cygwin license. Please consult the file "CYGWIN_LICENSE" for
details. */
#define PTMAGIC 0x77366377
#define PER_THREAD_FORK_CLEAR ((void *)UINT32_MAX)
class per_thread
{
DWORD tls;
int clear_on_fork_p;
public:
per_thread (int forkval = 1) {tls = TlsAlloc (); clear_on_fork_p = forkval;}
DWORD get_tls () {return tls;}
int clear_on_fork () {return clear_on_fork_p;}
virtual void *get () {return TlsGetValue (get_tls ());}
virtual size_t size () {return 0;}
virtual void set (void *s = NULL);
virtual void set (int n) {TlsSetValue (get_tls (), (void *)n);}
virtual void *create ()
{
void *s = calloc (1, size ());
set (s);
return s;
}
};
#ifdef NEED_VFORK
#include "cygtls.h"
#endif
#ifndef NEWVFORK
#define VFORKPID 0
#else
#if defined (NEED_VFORK)
class vfork_save
{
jmp_buf j;
int exitval;
public:
int pid;
DWORD frame[100];
_cygtls tls;
char **vfork_ebp;
char **vfork_esp;
int ctty;
pid_t sid;
pid_t pgid;
int open_fhs;
int is_active () { return pid < 0; }
void restore_pid (int val)
{
pid = val;
longjmp (j, 1);
}
void restore_exit (int val)
{
exitval = val;
longjmp (j, 1);
}
friend int vfork ();
};
class per_thread_vfork : public per_thread
{
public:
vfork_save *val () { return (vfork_save *) per_thread::get (); }
vfork_save *create () {return (vfork_save *) per_thread::create ();}
size_t size () {return sizeof (vfork_save);}
};
extern per_thread_vfork vfork_storage;
extern vfork_save *main_vfork;
#define VFORKPID main_vfork->pid
#endif
#endif /*NEWVFORK*/
extern per_thread *threadstuff[];

View File

@ -24,9 +24,9 @@ details. */
#include "perprocess.h"
#include "environ.h"
#include <assert.h>
#include <sys/wait.h>
#include <ntdef.h>
#include "ntdll.h"
#include "cygthread.h"
#include "shared_info.h"
#include "cygheap.h"
#include "fhandler.h"
@ -37,23 +37,6 @@ static char NO_COPY pinfo_dummy[sizeof (_pinfo)] = {0};
pinfo NO_COPY myself ((_pinfo *)&pinfo_dummy); // Avoid myself != NULL checks
HANDLE hexec_proc;
void __stdcall
pinfo_fixup_after_fork ()
{
if (hexec_proc)
CloseHandle (hexec_proc);
/* Keeps the cygpid from being reused. No rights required */
if (!DuplicateHandle (hMainProc, hMainProc, hMainProc, &hexec_proc, 0,
TRUE, 0))
{
system_printf ("couldn't save current process handle %p, %E", hMainProc);
hexec_proc = NULL;
}
VerifyHandle (hexec_proc);
}
/* Initialize the process table.
This is done once when the dll is first loaded. */
@ -70,7 +53,30 @@ set_myself (HANDLE h)
if (!strace.active)
strace.hello ();
debug_printf ("myself->dwProcessId %u", myself->dwProcessId);
InitializeCriticalSection (&myself->lock);
InitializeCriticalSection (&myself.lock);
myself->dwProcessId = GetCurrentProcessId ();
if (h)
{
/* here if execed */
static pinfo NO_COPY myself_identity;
myself_identity.init (cygwin_pid (myself->dwProcessId), PID_EXECED);
}
else if (myself->ppid)
{
/* here if forked/spawned */
pinfo parent (myself->ppid);
/* We've inherited the parent's wr_proc_pipe. We don't need it,
so close it. This could cause problems for the spawn case since there
is no guarantee that a parent will still be around by the time we get
here. If so, we would have a handle leak. FIXME? */
if (parent && parent->wr_proc_pipe)
CloseHandle (parent->wr_proc_pipe);
if (cygheap->pid_handle)
{
ForceCloseHandle (cygheap->pid_handle);
cygheap->pid_handle = NULL;
}
}
return;
}
@ -107,17 +113,27 @@ _pinfo::exit (UINT n, bool norecord)
exit_state = ES_FINAL;
cygthread::terminate ();
if (norecord)
sigproc_terminate ();
sigproc_terminate (); /* Just terminate signal and process stuff */
else
exitcode = n; /* We're really exiting. Record the UNIX exit code. */
if (this)
{
if (!norecord)
process_state = PID_EXITED;
/* FIXME: There is a potential race between an execed process and its
parent here. I hated to add a mutex just for this, though. */
struct rusage r;
fill_rusage (&r, hMainProc);
add_rusage (&rusage_self, &r);
if (!norecord)
{
process_state = PID_EXITED;
/* 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. */
if (wr_proc_pipe)
CloseHandle (wr_proc_pipe);
}
}
sigproc_printf ("Calling ExitProcess %d", n);
@ -259,6 +275,7 @@ pinfo::init (pid_t n, DWORD flag, HANDLE in_h)
procinfo->process_state |= PID_IN_USE | PID_EXECED;
procinfo->pid = myself->pid;
}
break;
}
destroy = 1;
@ -505,7 +522,7 @@ _pinfo::commune_send (DWORD code, ...)
__seterrno ();
goto err;
}
EnterCriticalSection (&myself->lock);
EnterCriticalSection (&myself.lock);
myself->tothem = tome;
myself->fromthem = fromme;
myself->hello_pid = pid;
@ -609,7 +626,7 @@ err:
out:
myself->hello_pid = 0;
LeaveCriticalSection (&myself->lock);
LeaveCriticalSection (&myself.lock);
return res;
}
@ -642,6 +659,196 @@ _pinfo::cmdline (size_t& n)
return s;
}
/* 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. */
static DWORD WINAPI
proc_waiter (void *arg)
{
extern HANDLE hExeced;
pinfo& vchild = *(pinfo *) arg;
siginfo_t si;
si.si_signo = SIGCHLD;
si.si_code = SI_KERNEL;
si.si_pid = vchild->pid;
si.si_errno = 0;
#if 0 // FIXME: This is tricky to get right
si.si_utime = pchildren[rc]->rusage_self.ru_utime;
si.si_stime = pchildren[rc].rusage_self.ru_stime;
#else
si.si_utime = 0;
si.si_stime = 0;
#endif
pid_t pid = vchild->pid;
for (;;)
{
DWORD nb;
char buf = '\0';
if (!ReadFile (vchild.rd_proc_pipe, &buf, 1, &nb, NULL)
&& GetLastError () != ERROR_BROKEN_PIPE)
{
system_printf ("error on read of child wait pipe %p, %E", vchild.rd_proc_pipe);
break;
}
si.si_uid = vchild->uid;
switch (buf)
{
case 0:
/* 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))
si.si_sigval.sival_int = CLD_DUMPED;
else
si.si_sigval.sival_int = CLD_KILLED;
si.si_status = vchild->exitcode;
vchild->process_state = PID_ZOMBIE;
break;
case SIGTTIN:
case SIGTTOU:
case SIGTSTP:
case SIGSTOP:
/* Child stopped. Signal myself. */
si.si_sigval.sival_int = CLD_STOPPED;
break;
case SIGCONT:
continue;
case __SIGREPARENT: /* 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;
}
/* Special case: If the "child process" that died is us, then we're
execing. Just call proc_subproc directly and then exit this loop.
We're done here. */
if (hExeced && vchild->pid == myself->pid)
{
/* execing. no signals available now. */
proc_subproc (PROC_CLEARWAIT, 0);
break;
}
/* Send a SIGCHLD to myself. We do this here, rather than in proc_subproc
to avoid the proc_subproc lock since the signal thread will eventually
be calling proc_subproc and could unnecessarily block. */
sig_send (myself_nowait, si);
/* If we're just stopped or got a continue signal, keep looping.
Otherwise, return this thread to the pool. */
if (buf != '\0')
sigproc_printf ("looping");
else
break;
}
sigproc_printf ("exiting wait thread for pid %d", pid);
_my_tls._ctinfo->release (); /* return the cygthread to the cygthread pool */
return 0;
}
/* 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))
{
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))
{
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 */
/* Fire up a new thread to track the subprocess */
cygthread *h = new cygthread (proc_waiter, this, "sig");
if (!h)
sigproc_printf ("tracking thread creation failed for pid %d", (*this)->pid);
else
{
h->zap_h ();
sigproc_printf ("created tracking thread for pid %d, winpid %p, rd_pipe %p",
(*this)->pid, (*this)->dwProcessId, rd_proc_pipe);
}
return 1;
}
/* function to send a "signal" to the parent when something interesting happens
in the child. */
void
pinfo::alert_parent (char sig)
{
DWORD nb;
/* Send something to our parent. If the parent has gone away,
close the pipe. */
if (myself->wr_proc_pipe
&& 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 = NULL;
CloseHandle (closeit);
}
}
void
pinfo::release ()
{

View File

@ -36,19 +36,12 @@ public:
constants below. */
DWORD process_state;
/* If hProcess is set, it's because it came from a
CreateProcess call. This means it's process relative
to the thing which created the process. That's ok because
we only use this handle from the parent. */
HANDLE hProcess;
DWORD exitcode; /* set when process exits */
#define PINFO_REDIR_SIZE ((char *) &myself.procinfo->hProcess - (char *) myself.procinfo)
#define PINFO_REDIR_SIZE ((char *) &myself.procinfo->exitcode - (char *) myself.procinfo)
/* Handle associated with initial Windows pid which started it all. */
HANDLE pid_handle;
/* Handle to the logical parent of this pid. */
HANDLE ppid_handle;
/* > 0 if started by a cygwin process */
DWORD cygstarted;
/* Parent process id. */
pid_t ppid;
@ -120,7 +113,9 @@ public:
HANDLE sendsig;
private:
sigset_t sig_mask;
CRITICAL_SECTION lock;
public:
HANDLE wr_proc_pipe;
friend class pinfo;
};
class pinfo
@ -129,12 +124,18 @@ class pinfo
_pinfo *procinfo;
bool destroy;
public:
HANDLE rd_proc_pipe;
HANDLE hProcess;
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) {}
pinfo (pid_t n) {init (n, 0);}
pinfo (pid_t n, DWORD flag) {init (n, flag);}
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);}
void release ();
int wait () __attribute__ ((regparm (1)));
~pinfo ()
{
if (destroy && procinfo)
@ -151,6 +152,8 @@ public:
_pinfo *operator * () const {return procinfo;}
operator _pinfo * () const {return procinfo;}
// operator bool () const {return (int) h;}
void preserve () { destroy = false; }
void alert_parent (char);
#ifndef _SIGPROC_H
int remember () {system_printf ("remember is not here"); return 0;}
#else
@ -210,9 +213,6 @@ extern pinfo myself;
#define _P_VFORK 0
#define _P_SYSTEM 512
extern void __stdcall pinfo_fixup_after_fork ();
extern HANDLE hexec_proc;
/* For mmaps across fork(). */
int __stdcall fixup_mmaps_after_fork (HANDLE parent);
/* for shm areas across fork (). */

View File

@ -36,9 +36,7 @@ details. */
#include "dtable.h"
#include "cygheap.h"
#include "sigproc.h"
#include "perthread.h"
#include "tty.h"
#include "cygthread.h"
#include "ntdll.h"
#include "cygtls.h"
#include <asm/byteorder.h>
@ -209,7 +207,7 @@ select_stuff::test_and_set (int i, fd_set *readfds, fd_set *writefds,
if (s->read_ready || s->write_ready || s->except_ready)
always_ready = true;
if (s->windows_handle || s->windows_handle || s->windows_handle)
if (s->windows_handle)
windows_used = true;
s->next = start.next;

View File

@ -342,7 +342,7 @@ abort (void)
raise (SIGABRT);
(void) _my_tls.call_signal_handler (); /* Call any signal handler */
do_exit (1); /* signal handler didn't exit. Goodbye. */
do_exit (SIGABRT); /* signal handler didn't exit. Goodbye. */
}
extern "C" int

View File

@ -28,10 +28,8 @@ details. */
#include "cygheap.h"
#include "child_info_magic.h"
#include "shared_info.h"
#include "cygthread.h"
#include "cygtls.h"
#include "sigproc.h"
#include "perthread.h"
#include "exceptions.h"
/*
@ -42,11 +40,9 @@ details. */
#define PSIZE 63 // Number of processes
#define wake_wait_subproc() SetEvent (events[0])
#define no_signals_available() (!hwait_sig || (myself->sendsig == INVALID_HANDLE_VALUE) || exit_state)
#define NZOMBIES 256
#define NPROCS 256
/*
* Global variables
@ -64,30 +60,15 @@ HANDLE NO_COPY signal_arrived; // Event signaled when a signal has
#define Static static NO_COPY
/* How long to wait for message/signals. Normally this is infinite.
On termination, however, these are set to zero as a flag to exit. */
Static DWORD proc_loop_wait = 1000; // Wait for subprocesses to exit
HANDLE NO_COPY sigCONT; // Used to "STOP" a process
Static cygthread *hwait_sig; // Handle of wait_sig thread
Static cygthread *hwait_subproc; // Handle of sig_subproc thread
Static HANDLE wait_sig_inited; // Control synchronization of
// message queue startup
/* Used by WaitForMultipleObjects. These are handles to child processes.
*/
Static HANDLE events[PSIZE + 1]; // All my children's handles++
#define hchildren (events + 1) // Where the children handles begin
Static int nchildren; // Number of active children
Static char cpchildren[PSIZE * sizeof (pinfo)]; // All my children info
Static int nzombies; // Number of deceased children
Static char czombies[(NZOMBIES + 1) * sizeof (pinfo)]; // All my deceased children info
#define pchildren ((pinfo *) cpchildren)
#define zombies ((pinfo *) czombies)
Static int nprocs; // Number of deceased children
Static char cprocs[(NPROCS + 1) * sizeof (pinfo)]; // All my deceased children info
#define procs ((pinfo *) cprocs)
Static waitq waitq_head = {0, 0, 0, 0, 0, 0, 0};// Start of queue for wait'ing threads
muto NO_COPY *sync_proc_subproc = NULL; // Control access to subproc stuff
@ -97,9 +78,8 @@ DWORD NO_COPY sigtid = 0; // ID of the signal thread
/* Function declarations */
static int __stdcall checkstate (waitq *) __attribute__ ((regparm (1)));
static __inline__ bool get_proc_lock (DWORD, DWORD);
static void __stdcall remove_zombie (int);
static int __stdcall stopped_or_terminated (waitq *, _pinfo *);
static DWORD WINAPI wait_subproc (VOID *);
static bool __stdcall remove_proc (int);
static bool __stdcall stopped_or_terminated (waitq *, _pinfo *);
static DWORD WINAPI wait_sig (VOID *arg);
/* wait_sig bookkeeping */
@ -152,33 +132,13 @@ bool __stdcall
my_parent_is_alive ()
{
bool res;
if (!myself->ppid_handle)
if (myself->cygstarted)
res = pid_exists (myself->ppid);
else
{
debug_printf ("No myself->ppid_handle");
debug_printf ("Not started by cygwin app");
res = false;
}
else
for (int i = 0; i < 2; i++)
switch (res = WaitForSingleObject (myself->ppid_handle, 0))
{
case WAIT_OBJECT_0:
debug_printf ("parent dead.");
res = false;
goto out;
case WAIT_TIMEOUT:
debug_printf ("parent still alive");
res = true;
goto out;
case WAIT_FAILED:
DWORD werr = GetLastError ();
if (werr == ERROR_INVALID_HANDLE && i == 0)
continue;
system_printf ("WFSO for myself->ppid_handle(%p) failed, error %d",
myself->ppid_handle, werr);
res = false;
goto out;
}
out:
return res;
}
@ -193,7 +153,7 @@ wait_for_sigthread ()
}
/* Get the sync_proc_subproc muto to control access to
* children, zombie arrays.
* children, proc arrays.
* Attempt to handle case where process is exiting as we try to grab
* the mutex.
*/
@ -260,16 +220,11 @@ proc_exists (_pinfo *p)
/* 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. */
int __stdcall
bool __stdcall
mychild (int pid)
{
for (int i = 0; i < nchildren; i++)
if (pchildren[i]->pid == pid)
return 1;
for (int i = 0; i < nzombies; i++)
if (zombies[i]->pid == pid)
return 1;
return 0;
pinfo p (pid);
return p && p->ppid == myself->pid;
}
/* Handle all subprocess requests
@ -283,7 +238,6 @@ proc_subproc (DWORD what, DWORD val)
_pinfo *child;
int clearing;
waitq *w;
int thiszombie;
#define wval ((waitq *) val)
@ -301,84 +255,32 @@ proc_subproc (DWORD what, DWORD val)
* (usually called from the main thread)
*/
case PROC_ADDCHILD:
if (nchildren >= PSIZE - 1)
/* Filled up process table? */
if (nprocs >= NPROCS)
{
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?
break;
}
pchildren[nchildren] = vchild;
hchildren[nchildren] = vchild->hProcess;
if (!DuplicateHandle (hMainProc, vchild->hProcess, hMainProc, &vchild->pid_handle,
0, 0, DUPLICATE_SAME_ACCESS))
system_printf ("Couldn't duplicate child handle for pid %d, %E", vchild->pid);
ProtectHandle1 (vchild->pid_handle, pid_handle);
if (!DuplicateHandle (hMainProc, hMainProc, vchild->hProcess, &vchild->ppid_handle,
SYNCHRONIZE | PROCESS_DUP_HANDLE, TRUE, 0))
system_printf ("Couldn't duplicate my handle<%p> for pid %d, %E", hMainProc, vchild->pid);
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);
sigproc_printf ("added pid %d to wait list, slot %d, winpid %p, handle %p",
vchild->pid, nchildren, vchild->dwProcessId,
vchild->hProcess);
nchildren++;
wake_wait_subproc ();
break;
/* A child process had terminated.
Possibly this is just due to an exec(). Cygwin implements an exec()
as a "handoff" from one windows process to another. If child->hProcess
is different from what is recorded in hchildren, then this is an exec().
Otherwise this is a normal child termination event.
(called from wait_subproc thread) */
case PROC_CHILDTERMINATED:
if (hchildren[val] != pchildren[val]->hProcess)
procs[nprocs] = vchild;
rc = procs[nprocs].wait ();
if (rc)
{
sigproc_printf ("pid %d[%d], reparented old hProcess %p, new %p",
pchildren[val]->pid, val, hchildren[val], pchildren[val]->hProcess);
HANDLE h = hchildren[val];
hchildren[val] = pchildren[val]->hProcess; /* Filled out by child */
ForceCloseHandle1 (h, childhProc);
ProtectHandle1 (pchildren[val]->hProcess, childhProc);
rc = 0;
goto out; // This was an exec()
sigproc_printf ("added pid %d to proc table, slot %d", vchild->pid,
nprocs);
nprocs++;
}
sigproc_printf ("pid %d[%d] terminated, handle %p, nchildren %d, nzombies %d",
pchildren[val]->pid, val, hchildren[val], nchildren, nzombies);
thiszombie = nzombies;
zombies[nzombies] = pchildren[val]; // Add to zombie array
zombies[nzombies++]->process_state = PID_ZOMBIE;// Walking dead
sigproc_printf ("zombifying [%d], pid %d, handle %p, nchildren %d",
val, pchildren[val]->pid, hchildren[val], nchildren);
if ((int) val < --nchildren)
{
hchildren[val] = hchildren[nchildren];
pchildren[val] = pchildren[nchildren];
}
/* See if we should care about the this terminated process. If we've
filled up our table or if we're ignoring SIGCHLD, then we immediately
remove the process and move on. Otherwise, this process becomes a zombie
which must be reaped by a wait() call. FIXME: This is a very inelegant
way to deal with this and could lead to process hangs. */
if (nzombies >= NZOMBIES)
{
sigproc_printf ("zombie table overflow %d", thiszombie);
remove_zombie (thiszombie);
}
/* Don't scan the wait queue yet. Caller will send SIGCHLD to this process.
This will cause an eventual scan of waiters. */
break;
/* Handle a wait4() operation. Allocates an event for the calling
@ -401,8 +303,8 @@ proc_subproc (DWORD what, DWORD val)
*/
if ((wval->ev = wval->thread_ev) == NULL)
{
wval->ev = wval->thread_ev = CreateEvent (&sec_none_nih, TRUE,
FALSE, NULL);
wval->ev = wval->thread_ev = CreateEvent (&sec_none_nih, TRUE, FALSE,
NULL);
ProtectHandle1 (wval->ev, wq_ev);
}
@ -459,9 +361,8 @@ proc_subproc (DWORD what, DWORD val)
}
if (global_sigs[SIGCHLD].sa_handler == (void *) SIG_IGN)
while (nzombies)
remove_zombie (0);
break;
for (int i = 0; i < nprocs; i += remove_proc (i))
continue;
}
out:
@ -492,54 +393,29 @@ _cygtls::remove_wq (DWORD wait)
* Called on process exit.
* Also called by spawn_guts to disassociate any subprocesses from this
* process. Subprocesses will then know to clean up after themselves and
* will not become zombies.
* will not become procs.
*/
void __stdcall
proc_terminate (void)
{
sigproc_printf ("nchildren %d, nzombies %d", nchildren, nzombies);
sigproc_printf ("nprocs %d", nprocs);
/* Signal processing is assumed to be blocked in this routine. */
if (hwait_subproc)
if (nprocs)
{
proc_loop_wait = 0; // Tell wait_subproc thread to exit
sync_proc_subproc->acquire (WPSP);
wake_wait_subproc (); // Wake wait_subproc loop
hwait_subproc = NULL;
(void) proc_subproc (PROC_CLEARWAIT, 1);
/* Clean out zombie processes from the pid list. */
/* Clean out proc processes from the pid list. */
int i;
for (i = 0; i < nzombies; i++)
for (i = 0; i < nprocs; i++)
{
if (zombies[i]->hProcess)
{
ForceCloseHandle1 (zombies[i]->hProcess, childhProc);
ForceCloseHandle1 (zombies[i]->pid_handle, pid_handle);
}
zombies[i]->ppid = 1;
zombies[i]->process_state = PID_EXITED; /* CGF FIXME - still needed? */
zombies[i].release (); // FIXME: this breaks older gccs for some reason
procs[i]->ppid = 1;
if (!proc_exists (procs[i]))
procs[i]->process_state = PID_EXITED; /* CGF FIXME - still needed? */
procs[i].release ();
}
/* Disassociate my subprocesses */
for (i = 0; i < nchildren; i++)
{
if (!pchildren[i]->hProcess)
sigproc_printf ("%d(%d) hProcess cleared already?", pchildren[i]->pid,
pchildren[i]->dwProcessId);
else
{
ForceCloseHandle1 (pchildren[i]->hProcess, childhProc);
sigproc_printf ("%d(%d) closed child handle", pchildren[i]->pid,
pchildren[i]->dwProcessId);
pchildren[i]->ppid = 1;
if (pchildren[i]->pgid == myself->pid)
pchildren[i]->process_state |= PID_ORPHANED;
}
pchildren[i].release ();
}
nchildren = nzombies = 0;
nprocs = 0;
sync_proc_subproc->release ();
}
sigproc_printf ("leaving");
@ -610,7 +486,7 @@ sigproc_init ()
ProtectHandle (wait_sig_inited);
/* sync_proc_subproc is used by proc_subproc. It serialises
* access to the children and zombie arrays.
* access to the children and proc arrays.
*/
new_muto (sync_proc_subproc);
@ -648,7 +524,7 @@ sigproc_terminate (void)
CloseHandle (sendsig);
}
}
proc_terminate (); // Terminate process handling thread
proc_terminate (); // clean up process stuff
return;
}
@ -833,25 +709,6 @@ out:
return rc;
}
/* Initialize the wait_subproc thread.
* Called from fork() or spawn() to initialize the handling of subprocesses.
*/
void __stdcall
subproc_init (void)
{
if (hwait_subproc)
return;
/* A "wakeup" handle which can be toggled to make wait_subproc reexamine
* the hchildren array.
*/
events[0] = CreateEvent (&sec_none_nih, FALSE, FALSE, NULL);
hwait_subproc = new cygthread (wait_subproc, NULL, "proc");
hwait_subproc->zap_h ();
ProtectHandle (events[0]);
sigproc_printf ("started wait_subproc thread");
}
/* Initialize some of the memory block passed to child processes
by fork/spawn/exec. */
@ -864,7 +721,6 @@ init_child_info (DWORD chtype, child_info *ch, HANDLE subproc_ready)
ch->magic = CHILD_INFO_MAGIC;
ch->type = chtype;
ch->subproc_ready = subproc_ready;
ch->pppid_handle = myself->ppid_handle;
ch->fhandler_union_cb = sizeof (fhandler_union);
ch->user_h = cygwin_user_h;
}
@ -877,132 +733,107 @@ checkstate (waitq *parent_w)
{
int potential_match = 0;
sigproc_printf ("nchildren %d, nzombies %d", nchildren, nzombies);
sigproc_printf ("nprocs %d", nprocs);
/* Check already dead processes first to see if they match the criteria
* given in w->next.
*/
for (int i = 0; i < nzombies; i++)
switch (stopped_or_terminated (parent_w, zombies[i]))
* given in w->next. */
int res;
for (int i = 0; i < nprocs; i++)
if ((res = stopped_or_terminated (parent_w, procs[i])))
{
case -1:
potential_match = -1;
break;
case 1:
remove_zombie (i);
remove_proc (i);
potential_match = 1;
goto out;
}
sigproc_printf ("checking alive children");
/* No dead terminated children matched. Check for stopped children. */
for (int i = 0; i < nchildren; i++)
switch (stopped_or_terminated (parent_w, pchildren[i]))
{
case -1:
potential_match = -1;
break;
case 1:
potential_match = 1;
goto out;
}
sigproc_printf ("no matching terminated children found");
potential_match = -!!nprocs;
out:
sigproc_printf ("returning %d", potential_match);
return potential_match;
}
/* Remove a zombie from zombies by swapping it with the last child in the list.
*/
static void __stdcall
remove_zombie (int ci)
/* Remove a proc from procs by swapping it with the last child in the list.
Also releases shared memory of exited processes. */
static bool __stdcall
remove_proc (int ci)
{
sigproc_printf ("removing %d, pid %d, nzombies %d", ci, zombies[ci]->pid,
nzombies);
if (proc_exists (procs[ci]))
return true;
if (zombies[ci])
sigproc_printf ("removing procs[%d], pid %d, nprocs %d", ci, procs[ci]->pid,
nprocs);
if (procs[ci] != myself)
{
ForceCloseHandle1 (zombies[ci]->hProcess, childhProc);
ForceCloseHandle1 (zombies[ci]->pid_handle, pid_handle);
zombies[ci].release ();
procs[ci].release ();
if (procs[ci].pid_handle)
ForceCloseHandle1 (procs[ci].pid_handle, childhProc);
if (procs[ci].hProcess)
ForceCloseHandle1 (procs[ci].hProcess, childhProc);
}
if (ci < --nzombies)
zombies[ci] = zombies[nzombies];
return;
if (ci < --nprocs)
procs[ci] = procs[nprocs];
return 0;
}
/* Check status of child process vs. waitq member.
*
* parent_w is the pointer to the parent of the waitq member in question.
* child is the subprocess being considered.
*
* Returns
* 1 if stopped or terminated child matches parent_w->next criteria
* -1 if a non-stopped/terminated child matches parent_w->next criteria
* 0 if child does not match parent_w->next criteria
*/
static int __stdcall
parent_w is the pointer to the parent of the waitq member in question.
child is the subprocess being considered.
Returns non-zero if waiting thread released. */
static bool __stdcall
stopped_or_terminated (waitq *parent_w, _pinfo *child)
{
int potential_match;
int might_match;
waitq *w = parent_w->next;
sigproc_printf ("considering pid %d", child->pid);
if (w->pid == -1)
potential_match = 1;
might_match = 1;
else if (w->pid == 0)
potential_match = child->pgid == myself->pgid;
might_match = child->pgid == myself->pgid;
else if (w->pid < 0)
potential_match = child->pgid == -w->pid;
might_match = child->pgid == -w->pid;
else
potential_match = (w->pid == child->pid);
might_match = (w->pid == child->pid);
if (!potential_match)
if (!might_match)
return 0;
bool terminated;
int terminated;
if ((terminated = child->process_state == PID_ZOMBIE) ||
((w->options & WUNTRACED) && child->stopsig))
if (!((terminated = (child->process_state == PID_ZOMBIE)) ||
((w->options & WUNTRACED) && child->stopsig)))
return 0;
parent_w->next = w->next; /* successful wait. remove from wait queue */
w->pid = child->pid;
if (!terminated)
{
parent_w->next = w->next; /* successful wait. remove from wait queue */
w->pid = child->pid;
sigproc_printf ("stopped child");
w->status = (child->stopsig << 8) | 0x7f;
child->stopsig = 0;
}
else /* Should only get here when child has been moved to the procs array */
{
w->status = child->exitcode;
if (!terminated)
add_rusage (&myself->rusage_children, &child->rusage_children);
add_rusage (&myself->rusage_children, &child->rusage_self);
if (w->rusage)
{
sigproc_printf ("stopped child");
w->status = (child->stopsig << 8) | 0x7f;
child->stopsig = 0;
add_rusage ((struct rusage *) w->rusage, &child->rusage_children);
add_rusage ((struct rusage *) w->rusage, &child->rusage_self);
}
else /* Should only get here when child has been moved to the zombies array */
{
DWORD status;
if (!GetExitCodeProcess (child->hProcess, &status))
status = 0xffff;
if (status & EXIT_SIGNAL)
w->status = (status >> 8) & 0xff; /* exited due to signal */
else
w->status = (status & 0xff) << 8; /* exited via "exit ()" */
add_rusage (&myself->rusage_children, &child->rusage_children);
add_rusage (&myself->rusage_children, &child->rusage_self);
if (w->rusage)
{
add_rusage ((struct rusage *) w->rusage, &child->rusage_children);
add_rusage ((struct rusage *) w->rusage, &child->rusage_self);
}
}
if (!SetEvent (w->ev)) /* wake up wait4 () immediately */
system_printf ("couldn't wake up wait event %p, %E", w->ev);
return 1;
}
return -potential_match;
if (!SetEvent (w->ev)) /* wake up wait4 () immediately */
system_printf ("couldn't wake up wait event %p, %E", w->ev);
return true;
}
static void
@ -1078,27 +909,10 @@ wait_sig (VOID *self)
signals. Prior to this, dwProcessId was set to the windows pid of
of the original windows process which spawned us unless this was a
"toplevel" process. */
myself->dwProcessId = GetCurrentProcessId ();
myself->process_state |= PID_ACTIVE;
myself->process_state &= ~PID_INITIALIZING;
sigproc_printf ("myself->dwProcessId %u", myself->dwProcessId);
/* If we've been execed, then there is still a stub left in the previous
windows process waiting to see if it's started a cygwin process or not.
Signalling subproc_ready indicates that we are a cygwin process. */
if (child_proc_info && child_proc_info->type == PROC_EXEC)
{
debug_printf ("subproc_ready %p", child_proc_info->subproc_ready);
if (!SetEvent (child_proc_info->subproc_ready))
system_printf ("SetEvent (subproc_ready) failed, %E");
ForceCloseHandle1 (child_proc_info->subproc_ready, subproc_ready);
/* Initialize an "indirect" pid block so that if someone looks up this
process via its Windows PID it will be redirected to the appropriate
Cygwin PID shared memory block. */
static pinfo NO_COPY myself_identity;
myself_identity.init (cygwin_pid (myself->dwProcessId), PID_EXECED);
}
SetEvent (wait_sig_inited);
sigtid = GetCurrentThreadId ();
@ -1215,85 +1029,3 @@ wait_sig (VOID *self)
sigproc_printf ("done");
ExitThread (0);
}
/* Wait for subprocesses to terminate. Executes in a separate thread. */
static DWORD WINAPI
wait_subproc (VOID *)
{
sigproc_printf ("starting");
int errloop = 0;
for (;;)
{
DWORD rc = WaitForMultipleObjects (nchildren + 1, events, FALSE,
proc_loop_wait);
if (!proc_loop_wait)
break;
if (rc == WAIT_TIMEOUT)
continue;
if (rc == WAIT_FAILED)
{
/* It's ok to get an ERROR_INVALID_HANDLE since another thread may have
closed a handle in the children[] array. So, we try looping a couple
of times to stabilize. FIXME - this is not foolproof. Probably, this
thread should be responsible for closing the children. */
if (!errloop++)
proc_subproc (PROC_NOTHING, 0); // Just synchronize and continue
if (errloop < 10)
continue;
system_printf ("wait failed. nchildren %d, wait %d, %E",
nchildren, proc_loop_wait);
for (int i = 0; i <= nchildren; i++)
if ((rc = WaitForSingleObject (events[i], 0)) == WAIT_OBJECT_0 ||
rc == WAIT_TIMEOUT)
continue;
else if (i == 0)
system_printf ("nchildren %d, event[%d] %p, %E", nchildren, i, events[i]);
else
{
system_printf ("nchildren %d, event[%d] %p, pchildren[%d] %p, events[0] %p, %E",
nchildren, i, events[i], i - 1, (_pinfo *) pchildren[i - 1], events[0]);
system_printf ("pid %d, dwProcessId %u, hProcess %p, progname '%s'",
pchildren[i - 1]->pid, pchildren[i - 1]->dwProcessId,
pchildren[i - 1]->hProcess, pchildren[i - 1]->progname);
}
break;
}
errloop = 0;
rc -= WAIT_OBJECT_0;
if (rc-- != 0)
{
siginfo_t si;
si.si_signo = SIGCHLD;
si.si_code = SI_KERNEL;
si.si_pid = pchildren[rc]->pid;
si.si_uid = pchildren[rc]->uid;
si.si_errno = 0;
GetExitCodeProcess (hchildren[rc], (DWORD *) &si.si_status);
#if 0 // FIXME: This is tricky to get right
si.si_utime = pchildren[rc]->rusage_self.ru_utime;
si.si_stime = pchildren[rc].rusage_self.ru_stime;
#else
si.si_utime = 0;
si.si_stime = 0;
#endif
rc = proc_subproc (PROC_CHILDTERMINATED, rc);
/* Send a SIGCHLD to myself. We do this here, rather than in proc_subproc
to avoid the proc_subproc lock since the signal thread will eventually
be calling proc_subproc and could unnecessarily block. */
if (rc)
sig_send (myself_nowait, si);
}
sigproc_printf ("looping");
}
ForceCloseHandle (events[0]);
events[0] = NULL;
sigproc_printf ("done");
ExitThread (0);
}

View File

@ -12,10 +12,6 @@ details. */
#define _SIGPROC_H
#include <signal.h>
#define EXIT_SIGNAL 0x010000
#define EXIT_REPARENTING 0x020000
#define EXIT_NOCLOSEALL 0x040000
#ifdef NSIG
enum
{
@ -26,7 +22,8 @@ enum
__SIGDELETE = -(NSIG + 5),
__SIGFLUSHFAST = -(NSIG + 6),
__SIGHOLD = -(NSIG + 7),
__SIGNOHOLD = -(NSIG + 8)
__SIGNOHOLD = -(NSIG + 8),
__SIGREPARENT = (NSIG + 2)
};
#endif
@ -77,7 +74,6 @@ int __stdcall proc_subproc (DWORD, DWORD) __attribute__ ((regparm (2)));
class _pinfo;
void __stdcall proc_terminate ();
void __stdcall sigproc_init ();
void __stdcall subproc_init ();
void __stdcall sigproc_terminate ();
bool __stdcall proc_exists (_pinfo *) __attribute__ ((regparm(1)));
bool __stdcall pid_exists (pid_t) __attribute__ ((regparm(1)));

View File

@ -29,8 +29,6 @@ details. */
#include "child_info.h"
#include "shared_info.h"
#include "pinfo.h"
#define NEED_VFORK
#include "perthread.h"
#include "registry.h"
#include "environ.h"
#include "cygthread.h"
@ -384,16 +382,7 @@ spawn_guts (const char * prog_arg, const char *const *argv,
else
chtype = PROC_EXEC;
HANDLE subproc_ready;
if (chtype != PROC_EXEC)
subproc_ready = NULL;
else
{
subproc_ready = CreateEvent (&sec_all, TRUE, FALSE, NULL);
ProtectHandleINH (subproc_ready);
}
init_child_info (chtype, &ciresrv, subproc_ready);
init_child_info (chtype, &ciresrv, NULL);
ciresrv.moreinfo = (cygheap_exec_info *) ccalloc (HEAP_1_EXEC, 1, sizeof (cygheap_exec_info));
ciresrv.moreinfo->old_title = NULL;
@ -603,7 +592,6 @@ spawn_guts (const char * prog_arg, const char *const *argv,
ciresrv.moreinfo->argc = newargv.argc;
ciresrv.moreinfo->argv = newargv;
ciresrv.hexec_proc = hexec_proc;
if (mode != _P_OVERLAY ||
!DuplicateHandle (hMainProc, myself.shared_handle (), hMainProc,
@ -627,19 +615,35 @@ spawn_guts (const char * prog_arg, const char *const *argv,
if (mode == _P_DETACH || !set_console_state_for_spawn ())
flags |= DETACHED_PROCESS;
if (mode != _P_OVERLAY)
flags |= CREATE_SUSPENDED;
#if 0 //someday
else
myself->dwProcessId = 0;
#endif
/* Some file types (currently only sockets) need extra effort in the
parent after CreateProcess and before copying the datastructures
to the child. So we have to start the child in suspend state,
unfortunately, to avoid a race condition. */
if (cygheap->fdtab.need_fixup_before ())
flags |= CREATE_SUSPENDED;
HANDLE saved_sendsig;
if (mode != _P_OVERLAY)
saved_sendsig = NULL;
else
{
/* Reset sendsig so that any process which wants to send a signal
to this pid will wait for the new process to become active.
Save the old value in case the exec fails. */
saved_sendsig = myself->sendsig;
myself->sendsig = INVALID_HANDLE_VALUE;
/* Save a copy of a handle to the current process around the first time we
exec so that the pid will not be reused. Why did I stop cygwin from
generating its own pids again? */
if (cygheap->pid_handle)
/* already done previously */;
else if (DuplicateHandle (hMainProc, hMainProc, hMainProc, &cygheap->pid_handle,
PROCESS_QUERY_INFORMATION, TRUE, 0))
ProtectHandle (cygheap->pid_handle);
else
system_printf ("duplicate to pid_handle failed, %E");
}
/* Start the process in a suspended state. Needed so that any potential parent will
be able to take notice of the new "execed" process. This is only really needed
to handle exec'ed windows processes since cygwin processes are smart enough that
the parent doesn't have to bother but what are you gonna do? Cygwin lives in
a windows world. */
flags |= CREATE_SUSPENDED;
const char *runpath = null_app_name ? NULL : (const char *) real_path;
@ -718,7 +722,7 @@ spawn_guts (const char * prog_arg, const char *const *argv,
/* Restore impersonation. In case of _P_OVERLAY this isn't
allowed since it would overwrite child data. */
if (mode != _P_OVERLAY || !rc)
cygheap->user.reimpersonate ();
cygheap->user.reimpersonate ();
MALLOC_CHECK;
if (envblock)
@ -732,12 +736,9 @@ spawn_guts (const char * prog_arg, const char *const *argv,
{
__seterrno ();
syscall_printf ("CreateProcess failed, %E");
#if 0 // someday
if (mode == _P_OVERLAY)
myself->dwProcessId = GetCurrentProcessId ();
#endif
if (subproc_ready)
ForceCloseHandle (subproc_ready);
/* If this was a failed exec, restore the saved sendsig. */
if (saved_sendsig)
myself->sendsig = saved_sendsig;
cygheap_setup_for_child_cleanup (newheap, &ciresrv, 0);
return -1;
}
@ -765,11 +766,6 @@ spawn_guts (const char * prog_arg, const char *const *argv,
{
cygheap->fdtab.fixup_before_exec (pi.dwProcessId);
cygheap_setup_for_child_cleanup (newheap, &ciresrv, 1);
if (mode == _P_OVERLAY)
{
ResumeThread (pi.hThread);
cygthread::terminate ();
}
}
if (mode != _P_OVERLAY)
@ -784,18 +780,36 @@ spawn_guts (const char * prog_arg, const char *const *argv,
/* Name the handle similarly to proc_subproc. */
ProtectHandle1 (pi.hProcess, childhProc);
int wait_for_myself = false;
DWORD exec_cygstarted;
if (mode == _P_OVERLAY)
{
/* These are both duplicated in the child code. We do this here,
primarily for strace. */
/* Store the old exec_cygstarted since this is used as a crude semaphore for
detecting when the parent has noticed the change in windows pid for this
cygwin pid. */
exec_cygstarted = myself->cygstarted;
myself->dwProcessId = dwExeced = pi.dwProcessId; /* Reparenting needs this */
myself.alert_parent (__SIGREPARENT);
CloseHandle (saved_sendsig);
strace.execing = 1;
hExeced = pi.hProcess;
dwExeced = pi.dwProcessId;
strcpy (myself->progname, real_path);
close_all_files ();
/* If wr_proc_pipe doesn't exist then this process was not started by a cygwin
process. So, we need to wait around until the process we've just "execed"
dies. Use our own wait facility to wait for our own pid to exit (there
is some minor special case code in proc_waiter and friends to accommodeate
this). */
if (!myself->wr_proc_pipe)
{
myself.hProcess = pi.hProcess;
myself.remember ();
wait_for_myself = true;
}
}
else
{
exec_cygstarted = 0;
myself->set_has_pgid_children ();
ProtectHandle (pi.hThread);
pinfo child (cygpid, PID_IN_USE);
@ -808,7 +822,7 @@ spawn_guts (const char * prog_arg, const char *const *argv,
goto out;
}
child->dwProcessId = pi.dwProcessId;
child->hProcess = pi.hProcess;
child.hProcess = pi.hProcess;
if (!child.remember ())
{
syscall_printf ("process table full");
@ -825,101 +839,31 @@ spawn_guts (const char * prog_arg, const char *const *argv,
However, we should try to find another way to do this eventually. */
(void) DuplicateHandle (hMainProc, child.shared_handle (), pi.hProcess,
NULL, 0, 0, DUPLICATE_SAME_ACCESS);
/* Start the child running */
ResumeThread (pi.hThread);
}
/* Start the child running */
if (flags & CREATE_SUSPENDED)
ResumeThread (pi.hThread);
ForceCloseHandle (pi.hThread);
// ForceCloseHandle (pi.hProcess); // handled by proc_subproc and friends
sigproc_printf ("spawned windows pid %d", pi.dwProcessId);
bool exited;
res = 0;
exited = false;
MALLOC_CHECK;
if (mode == _P_OVERLAY)
if (wait_for_myself)
waitpid (myself->pid, &res, 0);
else
{
int nwait = 3;
HANDLE waitbuf[3] = {pi.hProcess, signal_arrived, subproc_ready};
for (int i = 0; i < 100; i++)
{
switch (WaitForMultipleObjects (nwait, waitbuf, FALSE, INFINITE))
{
case WAIT_OBJECT_0:
sigproc_printf ("subprocess exited");
DWORD exitcode;
if (!GetExitCodeProcess (pi.hProcess, &exitcode))
exitcode = 1;
res |= exitcode;
exited = true;
break;
case WAIT_OBJECT_0 + 1:
sigproc_printf ("signal arrived");
reset_signal_arrived ();
continue;
case WAIT_OBJECT_0 + 2:
if (my_parent_is_alive ())
res |= EXIT_REPARENTING;
else if (!myself->ppid_handle)
{
nwait = 2;
sigproc_terminate ();
continue;
}
break;
case WAIT_FAILED:
system_printf ("wait failed: nwait %d, pid %d, winpid %d, %E",
nwait, myself->pid, myself->dwProcessId);
system_printf ("waitbuf[0] %p %d", waitbuf[0],
WaitForSingleObject (waitbuf[0], 0));
system_printf ("waitbuf[1] %p %d", waitbuf[1],
WaitForSingleObject (waitbuf[1], 0));
system_printf ("waitbuf[w] %p %d", waitbuf[2],
WaitForSingleObject (waitbuf[2], 0));
set_errno (ECHILD);
try_to_debug ();
return -1;
}
break;
}
ForceCloseHandle (subproc_ready);
sigproc_printf ("res %p", res);
if (res & EXIT_REPARENTING)
{
/* Try to reparent child process.
* Make handles to child available to parent process and exit with
* EXIT_REPARENTING status. Wait() syscall in parent will then wait
* for newly created child.
*/
HANDLE oldh = myself->hProcess;
HANDLE h = myself->ppid_handle;
sigproc_printf ("parent handle %p", h);
int rc = DuplicateHandle (hMainProc, pi.hProcess, h, &myself->hProcess,
0, FALSE, DUPLICATE_SAME_ACCESS);
sigproc_printf ("%d = DuplicateHandle, oldh %p, newh %p",
rc, oldh, myself->hProcess);
VerifyHandle (myself->hProcess);
if (!rc && my_parent_is_alive ())
{
system_printf ("Reparent failed, parent handle %p, %E", h);
system_printf ("my dwProcessId %d, myself->dwProcessId %d",
GetCurrentProcessId (), myself->dwProcessId);
system_printf ("old hProcess %p, hProcess %p", oldh, myself->hProcess);
}
}
/* Loop, waiting for parent to notice pid change, if exec_cygstarted.
In theory this wait should be a no-op. */
if (exec_cygstarted)
while (myself->cygstarted == exec_cygstarted)
low_priority_sleep (0);
res = 42;
}
MALLOC_CHECK;
switch (mode)
{
case _P_OVERLAY:
ForceCloseHandle1 (pi.hProcess, childhProc);
myself->exit (res, 1);
break;
case _P_WAIT:
@ -986,7 +930,6 @@ spawnve (int mode, const char *path, const char *const *argv,
case _P_WAIT:
case _P_DETACH:
case _P_SYSTEM:
subproc_init ();
ret = spawn_guts (path, argv, envp, mode);
#ifdef NEWVFORK
if (vf)

View File

@ -56,8 +56,6 @@ details. */
#include "pinfo.h"
#include "shared_info.h"
#include "cygheap.h"
#define NEED_VFORK
#include "perthread.h"
#include "pwdgrp.h"
#include "cpuid.h"
#include "registry.h"

View File

@ -16,7 +16,6 @@ details. */
#include "hires.h"
#include "thread.h"
#include "cygtls.h"
#include "cygthread.h"
#include "sigproc.h"
#include "sync.h"

View File

@ -23,7 +23,6 @@ details. */
#include "pinfo.h"
#include "hires.h"
#include "cygtls.h"
#include "cygthread.h"
#include "sigproc.h"
#include "sync.h"

View File

@ -1,113 +1,117 @@
//;# autogenerated: Do not edit.
//; $tls::sizeof__cygtls = 3932;
//; $tls::func = -3932;
//; $tls::sizeof__cygtls = 3936;
//; $tls::func = -3936;
//; $tls::pfunc = 0;
//; $tls::saved_errno = -3928;
//; $tls::saved_errno = -3932;
//; $tls::psaved_errno = 4;
//; $tls::sa_flags = -3924;
//; $tls::sa_flags = -3928;
//; $tls::psa_flags = 8;
//; $tls::oldmask = -3920;
//; $tls::oldmask = -3924;
//; $tls::poldmask = 12;
//; $tls::deltamask = -3916;
//; $tls::deltamask = -3920;
//; $tls::pdeltamask = 16;
//; $tls::event = -3912;
//; $tls::event = -3916;
//; $tls::pevent = 20;
//; $tls::errno_addr = -3908;
//; $tls::errno_addr = -3912;
//; $tls::perrno_addr = 24;
//; $tls::initialized = -3904;
//; $tls::initialized = -3908;
//; $tls::pinitialized = 28;
//; $tls::sigmask = -3900;
//; $tls::sigmask = -3904;
//; $tls::psigmask = 32;
//; $tls::sigwait_mask = -3896;
//; $tls::sigwait_mask = -3900;
//; $tls::psigwait_mask = 36;
//; $tls::sigwait_info = -3892;
//; $tls::sigwait_info = -3896;
//; $tls::psigwait_info = 40;
//; $tls::threadkill = -3888;
//; $tls::threadkill = -3892;
//; $tls::pthreadkill = 44;
//; $tls::infodata = -3884;
//; $tls::infodata = -3888;
//; $tls::pinfodata = 48;
//; $tls::tid = -3736;
//; $tls::tid = -3740;
//; $tls::ptid = 196;
//; $tls::local_clib = -3732;
//; $tls::local_clib = -3736;
//; $tls::plocal_clib = 200;
//; $tls::__dontuse = -3732;
//; $tls::__dontuse = -3736;
//; $tls::p__dontuse = 200;
//; $tls::locals = -2668;
//; $tls::locals = -2672;
//; $tls::plocals = 1264;
//; $tls::_ctinfo = -1084;
//; $tls::p_ctinfo = 2852;
//; $tls::wq = -1080;
//; $tls::pwq = 2852;
//; $tls::pwq = 2856;
//; $tls::prev = -1052;
//; $tls::pprev = 2880;
//; $tls::pprev = 2884;
//; $tls::next = -1048;
//; $tls::pnext = 2884;
//; $tls::pnext = 2888;
//; $tls::stackptr = -1044;
//; $tls::pstackptr = 2888;
//; $tls::pstackptr = 2892;
//; $tls::sig = -1040;
//; $tls::psig = 2892;
//; $tls::psig = 2896;
//; $tls::incyg = -1036;
//; $tls::pincyg = 2896;
//; $tls::pincyg = 2900;
//; $tls::spinning = -1032;
//; $tls::pspinning = 2900;
//; $tls::pspinning = 2904;
//; $tls::stacklock = -1028;
//; $tls::pstacklock = 2904;
//; $tls::pstacklock = 2908;
//; $tls::stack = -1024;
//; $tls::pstack = 2908;
//; $tls::pstack = 2912;
//; $tls::padding = 0;
//; $tls::ppadding = 3932;
//; $tls::ppadding = 3936;
//; __DATA__
#define tls_func (-3932)
#define tls_func (-3936)
#define tls_pfunc (0)
#define tls_saved_errno (-3928)
#define tls_saved_errno (-3932)
#define tls_psaved_errno (4)
#define tls_sa_flags (-3924)
#define tls_sa_flags (-3928)
#define tls_psa_flags (8)
#define tls_oldmask (-3920)
#define tls_oldmask (-3924)
#define tls_poldmask (12)
#define tls_deltamask (-3916)
#define tls_deltamask (-3920)
#define tls_pdeltamask (16)
#define tls_event (-3912)
#define tls_event (-3916)
#define tls_pevent (20)
#define tls_errno_addr (-3908)
#define tls_errno_addr (-3912)
#define tls_perrno_addr (24)
#define tls_initialized (-3904)
#define tls_initialized (-3908)
#define tls_pinitialized (28)
#define tls_sigmask (-3900)
#define tls_sigmask (-3904)
#define tls_psigmask (32)
#define tls_sigwait_mask (-3896)
#define tls_sigwait_mask (-3900)
#define tls_psigwait_mask (36)
#define tls_sigwait_info (-3892)
#define tls_sigwait_info (-3896)
#define tls_psigwait_info (40)
#define tls_threadkill (-3888)
#define tls_threadkill (-3892)
#define tls_pthreadkill (44)
#define tls_infodata (-3884)
#define tls_infodata (-3888)
#define tls_pinfodata (48)
#define tls_tid (-3736)
#define tls_tid (-3740)
#define tls_ptid (196)
#define tls_local_clib (-3732)
#define tls_local_clib (-3736)
#define tls_plocal_clib (200)
#define tls___dontuse (-3732)
#define tls___dontuse (-3736)
#define tls_p__dontuse (200)
#define tls_locals (-2668)
#define tls_locals (-2672)
#define tls_plocals (1264)
#define tls__ctinfo (-1084)
#define tls_p_ctinfo (2852)
#define tls_wq (-1080)
#define tls_pwq (2852)
#define tls_pwq (2856)
#define tls_prev (-1052)
#define tls_pprev (2880)
#define tls_pprev (2884)
#define tls_next (-1048)
#define tls_pnext (2884)
#define tls_pnext (2888)
#define tls_stackptr (-1044)
#define tls_pstackptr (2888)
#define tls_pstackptr (2892)
#define tls_sig (-1040)
#define tls_psig (2892)
#define tls_psig (2896)
#define tls_incyg (-1036)
#define tls_pincyg (2896)
#define tls_pincyg (2900)
#define tls_spinning (-1032)
#define tls_pspinning (2900)
#define tls_pspinning (2904)
#define tls_stacklock (-1028)
#define tls_pstacklock (2904)
#define tls_pstacklock (2908)
#define tls_stack (-1024)
#define tls_pstack (2908)
#define tls_pstack (2912)
#define tls_padding (0)
#define tls_ppadding (3932)
#define tls_ppadding (3936)

View File

@ -57,7 +57,7 @@ ttyslot (void)
void __stdcall
tty_init (void)
{
if (!myself->ppid_handle && NOTSTATE (myself, PID_CYGPARENT))
if (!myself->cygstarted && NOTSTATE (myself, PID_CYGPARENT))
cygheap->fdtab.get_debugger_info ();
if (NOTSTATE (myself, PID_USETTY))

View File

@ -13,7 +13,6 @@ details. */
#include <stdlib.h>
#include "cygerrno.h"
#include "sigproc.h"
#include "perthread.h"
#include "thread.h"
#include "cygtls.h"

View File

@ -23,7 +23,6 @@ details. */
#include "cygerrno.h"
#include "perprocess.h"
#include "security.h"
#include "cygthread.h"
#include "thread.h"
#include "cygtls.h"
#include "sync.h"