* 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:
parent
c1ab3396dc
commit
8cb359d947
|
@ -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>
|
2004-11-22 Christopher Faylor <cgf@timesys.com>
|
||||||
|
|
||||||
* select.cc (select_stuff::test_and_set): Remove extraneous tests of
|
* select.cc (select_stuff::test_and_set): Remove extraneous tests of
|
||||||
|
|
|
@ -29,7 +29,7 @@ enum
|
||||||
|
|
||||||
#define EXEC_MAGIC_SIZE sizeof(child_info)
|
#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
|
/* 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
|
||||||
|
@ -45,7 +45,6 @@ public:
|
||||||
HANDLE subproc_ready; // used for synchronization with parent
|
HANDLE subproc_ready; // used for synchronization with parent
|
||||||
HANDLE user_h;
|
HANDLE user_h;
|
||||||
HANDLE parent;
|
HANDLE parent;
|
||||||
HANDLE pppid_handle;
|
|
||||||
init_cygheap *cygheap;
|
init_cygheap *cygheap;
|
||||||
void *cygheap_max;
|
void *cygheap_max;
|
||||||
DWORD cygheap_reserve_sz;
|
DWORD cygheap_reserve_sz;
|
||||||
|
@ -83,7 +82,6 @@ class child_info_spawn: public child_info
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
cygheap_exec_info *moreinfo;
|
cygheap_exec_info *moreinfo;
|
||||||
HANDLE hexec_proc;
|
|
||||||
|
|
||||||
child_info_spawn (): moreinfo (NULL) {}
|
child_info_spawn (): moreinfo (NULL) {}
|
||||||
~child_info_spawn ()
|
~child_info_spawn ()
|
||||||
|
|
|
@ -289,6 +289,7 @@ struct init_cygheap
|
||||||
size_t sthreads;
|
size_t sthreads;
|
||||||
int open_fhs;
|
int open_fhs;
|
||||||
pid_t pid; /* my pid */
|
pid_t pid; /* my pid */
|
||||||
|
HANDLE pid_handle; /* handle for my pid */
|
||||||
void close_ctty ();
|
void close_ctty ();
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -11,7 +11,6 @@ details. */
|
||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
#include "exceptions.h"
|
#include "exceptions.h"
|
||||||
#include "security.h"
|
#include "security.h"
|
||||||
#include "cygthread.h"
|
|
||||||
#include "sync.h"
|
#include "sync.h"
|
||||||
#include "cygerrno.h"
|
#include "cygerrno.h"
|
||||||
#include "sigproc.h"
|
#include "sigproc.h"
|
||||||
|
@ -33,6 +32,7 @@ DWORD WINAPI
|
||||||
cygthread::stub (VOID *arg)
|
cygthread::stub (VOID *arg)
|
||||||
{
|
{
|
||||||
cygthread *info = (cygthread *) arg;
|
cygthread *info = (cygthread *) arg;
|
||||||
|
_my_tls._ctinfo = info;
|
||||||
if (info->arg == cygself)
|
if (info->arg == cygself)
|
||||||
{
|
{
|
||||||
if (info->ev)
|
if (info->ev)
|
||||||
|
@ -69,7 +69,8 @@ cygthread::stub (VOID *arg)
|
||||||
info->func = NULL; // catch erroneous activation
|
info->func = NULL; // catch erroneous activation
|
||||||
#endif
|
#endif
|
||||||
info->__name = NULL;
|
info->__name = NULL;
|
||||||
SetEvent (info->ev);
|
if (info->inuse)
|
||||||
|
SetEvent (info->ev);
|
||||||
}
|
}
|
||||||
switch (WaitForSingleObject (info->thread_sync, INFINITE))
|
switch (WaitForSingleObject (info->thread_sync, INFINITE))
|
||||||
{
|
{
|
||||||
|
@ -88,6 +89,7 @@ DWORD WINAPI
|
||||||
cygthread::simplestub (VOID *arg)
|
cygthread::simplestub (VOID *arg)
|
||||||
{
|
{
|
||||||
cygthread *info = (cygthread *) arg;
|
cygthread *info = (cygthread *) arg;
|
||||||
|
_my_tls._ctinfo = info;
|
||||||
info->stack_ptr = &arg;
|
info->stack_ptr = &arg;
|
||||||
info->ev = info->h;
|
info->ev = info->h;
|
||||||
info->func (info->arg == cygself ? info : info->arg);
|
info->func (info->arg == cygself ? info : info->arg);
|
||||||
|
|
|
@ -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
|
Cygwin license. Please consult the file "CYGWIN_LICENSE" for
|
||||||
details. */
|
details. */
|
||||||
|
|
||||||
|
#ifndef _CYGTHREAD_H
|
||||||
|
#define _CYGTHREAD_H
|
||||||
|
|
||||||
class cygthread
|
class cygthread
|
||||||
{
|
{
|
||||||
LONG inuse;
|
LONG inuse;
|
||||||
|
@ -25,6 +28,7 @@ class cygthread
|
||||||
static DWORD WINAPI simplestub (VOID *);
|
static DWORD WINAPI simplestub (VOID *);
|
||||||
static DWORD main_thread_id;
|
static DWORD main_thread_id;
|
||||||
static const char * name (DWORD = 0);
|
static const char * name (DWORD = 0);
|
||||||
|
void release () { __name = NULL; inuse = false; }
|
||||||
cygthread (LPTHREAD_START_ROUTINE, LPVOID, const char *);
|
cygthread (LPTHREAD_START_ROUTINE, LPVOID, const char *);
|
||||||
cygthread () {};
|
cygthread () {};
|
||||||
static void init ();
|
static void init ();
|
||||||
|
@ -43,3 +47,4 @@ class cygthread
|
||||||
};
|
};
|
||||||
|
|
||||||
#define cygself NULL
|
#define cygself NULL
|
||||||
|
#endif /*_CYGTHREAD_H*/
|
||||||
|
|
|
@ -19,7 +19,6 @@ details. */
|
||||||
#include "fhandler.h"
|
#include "fhandler.h"
|
||||||
#include "dtable.h"
|
#include "dtable.h"
|
||||||
#include "cygheap.h"
|
#include "cygheap.h"
|
||||||
#include "cygthread.h"
|
|
||||||
#include "pinfo.h"
|
#include "pinfo.h"
|
||||||
#include "sigproc.h"
|
#include "sigproc.h"
|
||||||
|
|
||||||
|
|
|
@ -32,6 +32,8 @@ details. */
|
||||||
|
|
||||||
#define TLS_STACK_SIZE 256
|
#define TLS_STACK_SIZE 256
|
||||||
|
|
||||||
|
#include "cygthread.h"
|
||||||
|
|
||||||
#pragma pack(push,4)
|
#pragma pack(push,4)
|
||||||
struct _local_storage
|
struct _local_storage
|
||||||
{
|
{
|
||||||
|
@ -131,6 +133,7 @@ struct _cygtls
|
||||||
char __dontuse[8 * ((sizeof(struct _reent) + 4) / 8)];
|
char __dontuse[8 * ((sizeof(struct _reent) + 4) / 8)];
|
||||||
};
|
};
|
||||||
struct _local_storage locals;
|
struct _local_storage locals;
|
||||||
|
class cygthread *_ctinfo;
|
||||||
waitq wq;
|
waitq wq;
|
||||||
struct _cygtls *prev, *next;
|
struct _cygtls *prev, *next;
|
||||||
__stack_t *stackptr;
|
__stack_t *stackptr;
|
||||||
|
|
|
@ -29,11 +29,10 @@ details. */
|
||||||
#include "dtable.h"
|
#include "dtable.h"
|
||||||
#include "cygheap.h"
|
#include "cygheap.h"
|
||||||
#include "child_info_magic.h"
|
#include "child_info_magic.h"
|
||||||
#include "perthread.h"
|
#include "cygtls.h"
|
||||||
#include "shared_info.h"
|
#include "shared_info.h"
|
||||||
#include "cygwin_version.h"
|
#include "cygwin_version.h"
|
||||||
#include "dll_init.h"
|
#include "dll_init.h"
|
||||||
#include "cygthread.h"
|
|
||||||
#include "sync.h"
|
#include "sync.h"
|
||||||
#include "heap.h"
|
#include "heap.h"
|
||||||
|
|
||||||
|
@ -44,16 +43,6 @@ details. */
|
||||||
HANDLE NO_COPY hMainProc = (HANDLE) -1;
|
HANDLE NO_COPY hMainProc = (HANDLE) -1;
|
||||||
HANDLE NO_COPY hMainThread;
|
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 display_title;
|
||||||
bool strip_title_path;
|
bool strip_title_path;
|
||||||
bool allow_glob = true;
|
bool allow_glob = true;
|
||||||
|
@ -656,8 +645,6 @@ dll_crt0_0 ()
|
||||||
memory_init ();
|
memory_init ();
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
bool close_ppid_handle = false;
|
|
||||||
bool close_hexec_proc = false;
|
|
||||||
switch (child_proc_info->type)
|
switch (child_proc_info->type)
|
||||||
{
|
{
|
||||||
case _PROC_FORK:
|
case _PROC_FORK:
|
||||||
|
@ -665,16 +652,9 @@ dll_crt0_0 ()
|
||||||
cygheap_fixup_in_child (false);
|
cygheap_fixup_in_child (false);
|
||||||
memory_init ();
|
memory_init ();
|
||||||
set_myself (NULL);
|
set_myself (NULL);
|
||||||
close_ppid_handle = !!child_proc_info->pppid_handle;
|
|
||||||
break;
|
break;
|
||||||
case _PROC_SPAWN:
|
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:
|
case _PROC_EXEC:
|
||||||
hexec_proc = spawn_info->hexec_proc;
|
|
||||||
around:
|
|
||||||
HANDLE h;
|
HANDLE h;
|
||||||
cygheap_fixup_in_child (true);
|
cygheap_fixup_in_child (true);
|
||||||
memory_init ();
|
memory_init ();
|
||||||
|
@ -697,10 +677,6 @@ dll_crt0_0 ()
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
if (close_hexec_proc)
|
|
||||||
CloseHandle (spawn_info->hexec_proc);
|
|
||||||
if (close_ppid_handle)
|
|
||||||
CloseHandle (child_proc_info->pppid_handle);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
_cygtls::init ();
|
_cygtls::init ();
|
||||||
|
@ -1014,13 +990,10 @@ do_exit (int status)
|
||||||
if (exit_state < ES_SIGNAL)
|
if (exit_state < ES_SIGNAL)
|
||||||
{
|
{
|
||||||
exit_state = ES_SIGNAL;
|
exit_state = ES_SIGNAL;
|
||||||
if (!(n & EXIT_REPARENTING))
|
signal (SIGCHLD, SIG_IGN);
|
||||||
{
|
signal (SIGHUP, SIG_IGN);
|
||||||
signal (SIGCHLD, SIG_IGN);
|
signal (SIGINT, SIG_IGN);
|
||||||
signal (SIGHUP, SIG_IGN);
|
signal (SIGQUIT, SIG_IGN);
|
||||||
signal (SIGINT, SIG_IGN);
|
|
||||||
signal (SIGQUIT, SIG_IGN);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (exit_state < ES_CLOSEALL)
|
if (exit_state < ES_CLOSEALL)
|
||||||
|
@ -1112,7 +1085,7 @@ cygwin_exit (int n)
|
||||||
extern "C" void
|
extern "C" void
|
||||||
_exit (int n)
|
_exit (int n)
|
||||||
{
|
{
|
||||||
do_exit ((DWORD) n & 0xffff);
|
do_exit (((DWORD) n & 0xff) << 8);
|
||||||
}
|
}
|
||||||
|
|
||||||
extern "C" void
|
extern "C" void
|
||||||
|
|
|
@ -11,7 +11,6 @@ details. */
|
||||||
#include "sync.h"
|
#include "sync.h"
|
||||||
#include "sigproc.h"
|
#include "sigproc.h"
|
||||||
#include "pinfo.h"
|
#include "pinfo.h"
|
||||||
#include "perthread.h"
|
|
||||||
#include "perprocess.h"
|
#include "perprocess.h"
|
||||||
#include "security.h"
|
#include "security.h"
|
||||||
#include "cygerrno.h"
|
#include "cygerrno.h"
|
||||||
|
|
|
@ -140,7 +140,7 @@ dtable::stdio_init ()
|
||||||
Also, always set them even if we're to pick up our parent's fds
|
Also, always set them even if we're to pick up our parent's fds
|
||||||
in case they're missed. */
|
in case they're missed. */
|
||||||
|
|
||||||
if (myself->ppid_handle || ISSTATE (myself, PID_CYGPARENT))
|
if (myself->cygstarted || ISSTATE (myself, PID_CYGPARENT))
|
||||||
return;
|
return;
|
||||||
|
|
||||||
HANDLE in = GetStdHandle (STD_INPUT_HANDLE);
|
HANDLE in = GetStdHandle (STD_INPUT_HANDLE);
|
||||||
|
|
|
@ -20,12 +20,9 @@ details. */
|
||||||
#include "cygtls.h"
|
#include "cygtls.h"
|
||||||
#include "sigproc.h"
|
#include "sigproc.h"
|
||||||
#include "cygerrno.h"
|
#include "cygerrno.h"
|
||||||
#define NEED_VFORK
|
|
||||||
#include "perthread.h"
|
|
||||||
#include "shared_info.h"
|
#include "shared_info.h"
|
||||||
#include "perprocess.h"
|
#include "perprocess.h"
|
||||||
#include "security.h"
|
#include "security.h"
|
||||||
#include "cygthread.h"
|
|
||||||
|
|
||||||
#define CALL_HANDLER_RETRY 20
|
#define CALL_HANDLER_RETRY 20
|
||||||
|
|
||||||
|
@ -159,7 +156,7 @@ open_stackdumpfile ()
|
||||||
CREATE_ALWAYS, 0, 0);
|
CREATE_ALWAYS, 0, 0);
|
||||||
if (h != INVALID_HANDLE_VALUE)
|
if (h != INVALID_HANDLE_VALUE)
|
||||||
{
|
{
|
||||||
if (!myself->ppid_handle)
|
if (!myself->cygstarted)
|
||||||
system_printf ("Dumping stack trace to %s", corefile);
|
system_printf ("Dumping stack trace to %s", corefile);
|
||||||
else
|
else
|
||||||
debug_printf ("Dumping stack trace to %s", corefile);
|
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)
|
|| (void *) global_sigs[si.si_signo].sa_handler == (void *) SIG_ERR)
|
||||||
{
|
{
|
||||||
/* Print the exception to the console */
|
/* Print the exception to the console */
|
||||||
if (!myself->ppid_handle)
|
if (!myself->cygstarted)
|
||||||
for (int i = 0; status_info[i].name; i++)
|
for (int i = 0; status_info[i].name; i++)
|
||||||
if (status_info[i].code == e.ExceptionCode)
|
if (status_info[i].code == e.ExceptionCode)
|
||||||
{
|
{
|
||||||
|
@ -596,31 +593,15 @@ sig_handle_tty_stop (int sig)
|
||||||
_my_tls.incyg = 1;
|
_my_tls.incyg = 1;
|
||||||
/* Silently ignore attempts to suspend if there is no accommodating
|
/* Silently ignore attempts to suspend if there is no accommodating
|
||||||
cygwin parent to deal with this behavior. */
|
cygwin parent to deal with this behavior. */
|
||||||
if (!myself->ppid_handle)
|
if (!myself->cygstarted)
|
||||||
{
|
{
|
||||||
myself->process_state &= ~PID_STOPPED;
|
myself->process_state &= ~PID_STOPPED;
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
myself->stopsig = sig;
|
myself->stopsig = sig;
|
||||||
/* See if we have a living parent. If so, send it a special signal.
|
myself.alert_parent (sig);
|
||||||
It will figure out exactly which pid has stopped by scanning
|
sigproc_printf ("process %d stopped by signal %d", myself->pid, sig);
|
||||||
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);
|
|
||||||
HANDLE w4[2];
|
HANDLE w4[2];
|
||||||
w4[0] = sigCONT;
|
w4[0] = sigCONT;
|
||||||
w4[1] = signal_arrived;
|
w4[1] = signal_arrived;
|
||||||
|
@ -629,6 +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);
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
api_fatal ("WaitSingleObject failed, %E");
|
api_fatal ("WaitSingleObject failed, %E");
|
||||||
|
@ -807,7 +789,7 @@ ctrl_c_handler (DWORD type)
|
||||||
|
|
||||||
if (!cygwin_finished_initializing)
|
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. */
|
return TRUE; /* Yes. Let the parent eventually handle CTRL-C issues. */
|
||||||
debug_printf ("exiting with status %p", STATUS_CONTROL_C_EXIT);
|
debug_printf ("exiting with status %p", STATUS_CONTROL_C_EXIT);
|
||||||
ExitProcess (STATUS_CONTROL_C_EXIT);
|
ExitProcess (STATUS_CONTROL_C_EXIT);
|
||||||
|
@ -982,7 +964,7 @@ sigpacket::process ()
|
||||||
bool special_case;
|
bool special_case;
|
||||||
bool insigwait_mask;
|
bool insigwait_mask;
|
||||||
insigwait_mask = masked = false;
|
insigwait_mask = masked = false;
|
||||||
if (special_case = (VFORKPID || ISSTATE (myself, PID_STOPPED)))
|
if (special_case = (/*VFORKPID || */ISSTATE (myself, PID_STOPPED)))
|
||||||
/* nothing to do */;
|
/* nothing to do */;
|
||||||
else if (tls && sigismember (&tls->sigwait_mask, si.si_signo))
|
else if (tls && sigismember (&tls->sigwait_mask, si.si_signo))
|
||||||
insigwait_mask = true;
|
insigwait_mask = true;
|
||||||
|
@ -1097,7 +1079,6 @@ static void
|
||||||
signal_exit (int rc)
|
signal_exit (int rc)
|
||||||
{
|
{
|
||||||
EnterCriticalSection (&exit_lock);
|
EnterCriticalSection (&exit_lock);
|
||||||
rc = EXIT_SIGNAL | (rc << 8);
|
|
||||||
if (exit_already++)
|
if (exit_already++)
|
||||||
myself->exit (rc);
|
myself->exit (rc);
|
||||||
|
|
||||||
|
|
|
@ -25,7 +25,6 @@ details. */
|
||||||
#include "cygheap.h"
|
#include "cygheap.h"
|
||||||
#include "wincap.h"
|
#include "wincap.h"
|
||||||
#include "heap.h"
|
#include "heap.h"
|
||||||
#include "cygthread.h"
|
|
||||||
#include "pwdgrp.h"
|
#include "pwdgrp.h"
|
||||||
#include "cygtls.h"
|
#include "cygtls.h"
|
||||||
|
|
||||||
|
@ -72,7 +71,6 @@ fillout_pinfo (pid_t pid, int winpid)
|
||||||
ep.ctty = p->ctty;
|
ep.ctty = p->ctty;
|
||||||
ep.pid = p->pid;
|
ep.pid = p->pid;
|
||||||
ep.ppid = p->ppid;
|
ep.ppid = p->ppid;
|
||||||
ep.hProcess = p->hProcess;
|
|
||||||
ep.dwProcessId = p->dwProcessId;
|
ep.dwProcessId = p->dwProcessId;
|
||||||
ep.uid = p->uid;
|
ep.uid = p->uid;
|
||||||
ep.gid = p->gid;
|
ep.gid = p->gid;
|
||||||
|
|
|
@ -28,7 +28,6 @@ details. */
|
||||||
#include "sigproc.h"
|
#include "sigproc.h"
|
||||||
#include "pinfo.h"
|
#include "pinfo.h"
|
||||||
#include "shared_info.h"
|
#include "shared_info.h"
|
||||||
#include "cygthread.h"
|
|
||||||
#include "cygtls.h"
|
#include "cygtls.h"
|
||||||
|
|
||||||
#define CONVERT_LIMIT 16384
|
#define CONVERT_LIMIT 16384
|
||||||
|
|
|
@ -771,7 +771,10 @@ fhandler_tty_slave::read (void *ptr, size_t& len)
|
||||||
rc = WaitForMultipleObjects (2, w4, FALSE, waiter);
|
rc = WaitForMultipleObjects (2, w4, FALSE, waiter);
|
||||||
|
|
||||||
if (rc == WAIT_TIMEOUT)
|
if (rc == WAIT_TIMEOUT)
|
||||||
break;
|
{
|
||||||
|
termios_printf ("wait timed out, waiter %u", waiter);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
if (rc == WAIT_FAILED)
|
if (rc == WAIT_FAILED)
|
||||||
{
|
{
|
||||||
|
|
|
@ -22,8 +22,7 @@ details. */
|
||||||
#include "pinfo.h"
|
#include "pinfo.h"
|
||||||
#include "cygheap.h"
|
#include "cygheap.h"
|
||||||
#include "child_info.h"
|
#include "child_info.h"
|
||||||
#define NEED_VFORK
|
#include "cygtls.h"
|
||||||
#include "perthread.h"
|
|
||||||
#include "perprocess.h"
|
#include "perprocess.h"
|
||||||
#include "dll_init.h"
|
#include "dll_init.h"
|
||||||
#include "sync.h"
|
#include "sync.h"
|
||||||
|
@ -42,17 +41,6 @@ details. */
|
||||||
#define dll_bss_start &_bss_start__
|
#define dll_bss_start &_bss_start__
|
||||||
#define dll_bss_end &_bss_end__
|
#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
|
static void
|
||||||
stack_base (child_info_fork &ch)
|
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->subproc_ready, subproc_ready);
|
||||||
(void) ForceCloseHandle1 (fork_info->forker_finished, forker_finished);
|
(void) ForceCloseHandle1 (fork_info->forker_finished, forker_finished);
|
||||||
|
|
||||||
pinfo_fixup_after_fork ();
|
|
||||||
_my_tls.fixup_after_fork ();
|
_my_tls.fixup_after_fork ();
|
||||||
sigproc_init ();
|
sigproc_init ();
|
||||||
|
|
||||||
|
@ -305,13 +292,6 @@ fork_child (HANDLE& hParent, dll *&first_dll, bool& load_dlls)
|
||||||
api_fatal ("recreate_shm areas after fork failed");
|
api_fatal ("recreate_shm areas after fork failed");
|
||||||
#endif
|
#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 ();
|
pthread::atforkchild ();
|
||||||
fixup_timers_after_fork ();
|
fixup_timers_after_fork ();
|
||||||
cygbench ("fork-child");
|
cygbench ("fork-child");
|
||||||
|
@ -356,8 +336,6 @@ fork_parent (HANDLE& hParent, dll *&first_dll,
|
||||||
|
|
||||||
pthread::atforkprepare ();
|
pthread::atforkprepare ();
|
||||||
|
|
||||||
subproc_init ();
|
|
||||||
|
|
||||||
int c_flags = GetPriorityClass (hMainProc) /*|
|
int c_flags = GetPriorityClass (hMainProc) /*|
|
||||||
CREATE_NEW_PROCESS_GROUP*/;
|
CREATE_NEW_PROCESS_GROUP*/;
|
||||||
STARTUPINFO si = {0, NULL, NULL, NULL, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, NULL, NULL, NULL, NULL};
|
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
|
/* Create an inheritable handle to pass to the child process. This will
|
||||||
allow the child to duplicate handles from the parent to itself. */
|
allow the child to duplicate handles from the parent to itself. */
|
||||||
hParent = NULL;
|
hParent = NULL;
|
||||||
if (!DuplicateHandle (hMainProc, hMainProc, hMainProc, &hParent, 0, 1,
|
if (!DuplicateHandle (hMainProc, hMainProc, hMainProc, &hParent, 0, TRUE,
|
||||||
DUPLICATE_SAME_ACCESS))
|
DUPLICATE_SAME_ACCESS))
|
||||||
{
|
{
|
||||||
system_printf ("couldn't create handle to myself for child, %E");
|
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);
|
ProtectHandle1 (pi.hProcess, childhProc);
|
||||||
|
|
||||||
/* Fill in fields in the child's process table entry. */
|
/* Fill in fields in the child's process table entry. */
|
||||||
forked->hProcess = pi.hProcess;
|
|
||||||
forked->dwProcessId = pi.dwProcessId;
|
forked->dwProcessId = pi.dwProcessId;
|
||||||
|
forked.hProcess = pi.hProcess;
|
||||||
|
|
||||||
/* Hopefully, this will succeed. The alternative to doing things this
|
/* Hopefully, this will succeed. The alternative to doing things this
|
||||||
way is to reserve space prior to calling CreateProcess and then fill
|
way is to reserve space prior to calling CreateProcess and then fill
|
||||||
|
|
|
@ -232,7 +232,7 @@ struct external_pinfo
|
||||||
{
|
{
|
||||||
pid_t pid;
|
pid_t pid;
|
||||||
pid_t ppid;
|
pid_t ppid;
|
||||||
HANDLE hProcess;
|
DWORD exitcode;
|
||||||
DWORD dwProcessId, dwSpawnedProcessId;
|
DWORD dwProcessId, dwSpawnedProcessId;
|
||||||
__uid16_t uid;
|
__uid16_t uid;
|
||||||
__gid16_t gid;
|
__gid16_t gid;
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
/* sys/wait.h
|
/* 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.
|
This file is part of Cygwin.
|
||||||
|
|
||||||
|
@ -36,6 +36,7 @@ extern "C" {
|
||||||
#define WEXITSTATUS(w) (((w) >> 8) & 0xff)
|
#define WEXITSTATUS(w) (((w) >> 8) & 0xff)
|
||||||
#define WTERMSIG(w) ((w) & 0x7f)
|
#define WTERMSIG(w) ((w) & 0x7f)
|
||||||
#define WSTOPSIG WEXITSTATUS
|
#define WSTOPSIG WEXITSTATUS
|
||||||
|
#define WCOREDUMP(w) (WIFSIGNALED(w) && (w & 0x80))
|
||||||
|
|
||||||
pid_t wait (int *);
|
pid_t wait (int *);
|
||||||
pid_t waitpid (pid_t, int *, int);
|
pid_t waitpid (pid_t, int *, int);
|
||||||
|
|
|
@ -12,7 +12,6 @@ details. */
|
||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
#include "thread.h"
|
#include "thread.h"
|
||||||
#include "perprocess.h"
|
#include "perprocess.h"
|
||||||
#include "cygthread.h"
|
|
||||||
#include "cygtls.h"
|
#include "cygtls.h"
|
||||||
|
|
||||||
int NO_COPY dynamically_loaded;
|
int NO_COPY dynamically_loaded;
|
||||||
|
|
|
@ -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[];
|
|
|
@ -24,9 +24,9 @@ details. */
|
||||||
#include "perprocess.h"
|
#include "perprocess.h"
|
||||||
#include "environ.h"
|
#include "environ.h"
|
||||||
#include <assert.h>
|
#include <assert.h>
|
||||||
|
#include <sys/wait.h>
|
||||||
#include <ntdef.h>
|
#include <ntdef.h>
|
||||||
#include "ntdll.h"
|
#include "ntdll.h"
|
||||||
#include "cygthread.h"
|
|
||||||
#include "shared_info.h"
|
#include "shared_info.h"
|
||||||
#include "cygheap.h"
|
#include "cygheap.h"
|
||||||
#include "fhandler.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
|
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.
|
/* Initialize the process table.
|
||||||
This is done once when the dll is first loaded. */
|
This is done once when the dll is first loaded. */
|
||||||
|
|
||||||
|
@ -70,7 +53,30 @@ set_myself (HANDLE h)
|
||||||
if (!strace.active)
|
if (!strace.active)
|
||||||
strace.hello ();
|
strace.hello ();
|
||||||
debug_printf ("myself->dwProcessId %u", myself->dwProcessId);
|
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;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -107,17 +113,27 @@ _pinfo::exit (UINT n, bool norecord)
|
||||||
exit_state = ES_FINAL;
|
exit_state = ES_FINAL;
|
||||||
cygthread::terminate ();
|
cygthread::terminate ();
|
||||||
if (norecord)
|
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 (this)
|
||||||
{
|
{
|
||||||
if (!norecord)
|
|
||||||
process_state = PID_EXITED;
|
|
||||||
|
|
||||||
/* FIXME: There is a potential race between an execed process and its
|
/* FIXME: There is a potential race between an execed process and its
|
||||||
parent here. I hated to add a mutex just for this, though. */
|
parent here. I hated to add a mutex just for this, though. */
|
||||||
struct rusage r;
|
struct rusage r;
|
||||||
fill_rusage (&r, hMainProc);
|
fill_rusage (&r, hMainProc);
|
||||||
add_rusage (&rusage_self, &r);
|
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);
|
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->process_state |= PID_IN_USE | PID_EXECED;
|
||||||
procinfo->pid = myself->pid;
|
procinfo->pid = myself->pid;
|
||||||
}
|
}
|
||||||
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
destroy = 1;
|
destroy = 1;
|
||||||
|
@ -505,7 +522,7 @@ _pinfo::commune_send (DWORD code, ...)
|
||||||
__seterrno ();
|
__seterrno ();
|
||||||
goto err;
|
goto err;
|
||||||
}
|
}
|
||||||
EnterCriticalSection (&myself->lock);
|
EnterCriticalSection (&myself.lock);
|
||||||
myself->tothem = tome;
|
myself->tothem = tome;
|
||||||
myself->fromthem = fromme;
|
myself->fromthem = fromme;
|
||||||
myself->hello_pid = pid;
|
myself->hello_pid = pid;
|
||||||
|
@ -609,7 +626,7 @@ err:
|
||||||
|
|
||||||
out:
|
out:
|
||||||
myself->hello_pid = 0;
|
myself->hello_pid = 0;
|
||||||
LeaveCriticalSection (&myself->lock);
|
LeaveCriticalSection (&myself.lock);
|
||||||
return res;
|
return res;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -642,6 +659,196 @@ _pinfo::cmdline (size_t& n)
|
||||||
return s;
|
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
|
void
|
||||||
pinfo::release ()
|
pinfo::release ()
|
||||||
{
|
{
|
||||||
|
|
|
@ -36,19 +36,12 @@ public:
|
||||||
constants below. */
|
constants below. */
|
||||||
DWORD process_state;
|
DWORD process_state;
|
||||||
|
|
||||||
/* If hProcess is set, it's because it came from a
|
DWORD exitcode; /* set when process exits */
|
||||||
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;
|
|
||||||
|
|
||||||
#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. */
|
/* > 0 if started by a cygwin process */
|
||||||
HANDLE pid_handle;
|
DWORD cygstarted;
|
||||||
|
|
||||||
/* Handle to the logical parent of this pid. */
|
|
||||||
HANDLE ppid_handle;
|
|
||||||
|
|
||||||
/* Parent process id. */
|
/* Parent process id. */
|
||||||
pid_t ppid;
|
pid_t ppid;
|
||||||
|
@ -120,7 +113,9 @@ public:
|
||||||
HANDLE sendsig;
|
HANDLE sendsig;
|
||||||
private:
|
private:
|
||||||
sigset_t sig_mask;
|
sigset_t sig_mask;
|
||||||
CRITICAL_SECTION lock;
|
public:
|
||||||
|
HANDLE wr_proc_pipe;
|
||||||
|
friend class pinfo;
|
||||||
};
|
};
|
||||||
|
|
||||||
class pinfo
|
class pinfo
|
||||||
|
@ -129,12 +124,18 @@ class pinfo
|
||||||
_pinfo *procinfo;
|
_pinfo *procinfo;
|
||||||
bool destroy;
|
bool destroy;
|
||||||
public:
|
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)));
|
void init (pid_t, DWORD, HANDLE = NULL) __attribute__ ((regparm(3)));
|
||||||
pinfo () {}
|
pinfo () {}
|
||||||
pinfo (_pinfo *x): procinfo (x) {}
|
pinfo (_pinfo *x): procinfo (x), hProcess (NULL), pid_handle (NULL) {}
|
||||||
pinfo (pid_t n) {init (n, 0);}
|
pinfo (pid_t n) : rd_proc_pipe (NULL), hProcess (NULL), pid_handle (NULL) {init (n, 0);}
|
||||||
pinfo (pid_t n, DWORD flag) {init (n, flag);}
|
pinfo (pid_t n, DWORD flag) : rd_proc_pipe (NULL), hProcess (NULL), pid_handle (NULL) {init (n, flag);}
|
||||||
void release ();
|
void release ();
|
||||||
|
int wait () __attribute__ ((regparm (1)));
|
||||||
~pinfo ()
|
~pinfo ()
|
||||||
{
|
{
|
||||||
if (destroy && procinfo)
|
if (destroy && procinfo)
|
||||||
|
@ -151,6 +152,8 @@ public:
|
||||||
_pinfo *operator * () const {return procinfo;}
|
_pinfo *operator * () const {return procinfo;}
|
||||||
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 alert_parent (char);
|
||||||
#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
|
||||||
|
@ -210,9 +213,6 @@ extern pinfo myself;
|
||||||
#define _P_VFORK 0
|
#define _P_VFORK 0
|
||||||
#define _P_SYSTEM 512
|
#define _P_SYSTEM 512
|
||||||
|
|
||||||
extern void __stdcall pinfo_fixup_after_fork ();
|
|
||||||
extern HANDLE hexec_proc;
|
|
||||||
|
|
||||||
/* For mmaps across fork(). */
|
/* For mmaps across fork(). */
|
||||||
int __stdcall fixup_mmaps_after_fork (HANDLE parent);
|
int __stdcall fixup_mmaps_after_fork (HANDLE parent);
|
||||||
/* for shm areas across fork (). */
|
/* for shm areas across fork (). */
|
||||||
|
|
|
@ -36,9 +36,7 @@ details. */
|
||||||
#include "dtable.h"
|
#include "dtable.h"
|
||||||
#include "cygheap.h"
|
#include "cygheap.h"
|
||||||
#include "sigproc.h"
|
#include "sigproc.h"
|
||||||
#include "perthread.h"
|
|
||||||
#include "tty.h"
|
#include "tty.h"
|
||||||
#include "cygthread.h"
|
|
||||||
#include "ntdll.h"
|
#include "ntdll.h"
|
||||||
#include "cygtls.h"
|
#include "cygtls.h"
|
||||||
#include <asm/byteorder.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)
|
if (s->read_ready || s->write_ready || s->except_ready)
|
||||||
always_ready = true;
|
always_ready = true;
|
||||||
|
|
||||||
if (s->windows_handle || s->windows_handle || s->windows_handle)
|
if (s->windows_handle)
|
||||||
windows_used = true;
|
windows_used = true;
|
||||||
|
|
||||||
s->next = start.next;
|
s->next = start.next;
|
||||||
|
|
|
@ -342,7 +342,7 @@ abort (void)
|
||||||
|
|
||||||
raise (SIGABRT);
|
raise (SIGABRT);
|
||||||
(void) _my_tls.call_signal_handler (); /* Call any signal handler */
|
(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
|
extern "C" int
|
||||||
|
|
|
@ -28,10 +28,8 @@ details. */
|
||||||
#include "cygheap.h"
|
#include "cygheap.h"
|
||||||
#include "child_info_magic.h"
|
#include "child_info_magic.h"
|
||||||
#include "shared_info.h"
|
#include "shared_info.h"
|
||||||
#include "cygthread.h"
|
|
||||||
#include "cygtls.h"
|
#include "cygtls.h"
|
||||||
#include "sigproc.h"
|
#include "sigproc.h"
|
||||||
#include "perthread.h"
|
|
||||||
#include "exceptions.h"
|
#include "exceptions.h"
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
@ -42,11 +40,9 @@ details. */
|
||||||
|
|
||||||
#define PSIZE 63 // Number of processes
|
#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 no_signals_available() (!hwait_sig || (myself->sendsig == INVALID_HANDLE_VALUE) || exit_state)
|
||||||
|
|
||||||
#define NZOMBIES 256
|
#define NPROCS 256
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Global variables
|
* Global variables
|
||||||
|
@ -64,30 +60,15 @@ HANDLE NO_COPY signal_arrived; // Event signaled when a signal has
|
||||||
|
|
||||||
#define Static static NO_COPY
|
#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
|
HANDLE NO_COPY sigCONT; // Used to "STOP" a process
|
||||||
Static cygthread *hwait_sig; // Handle of wait_sig thread
|
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
|
Static HANDLE wait_sig_inited; // Control synchronization of
|
||||||
// message queue startup
|
// message queue startup
|
||||||
|
|
||||||
/* Used by WaitForMultipleObjects. These are handles to child processes.
|
Static int nprocs; // Number of deceased children
|
||||||
*/
|
Static char cprocs[(NPROCS + 1) * sizeof (pinfo)]; // All my deceased children info
|
||||||
Static HANDLE events[PSIZE + 1]; // All my children's handles++
|
#define procs ((pinfo *) cprocs)
|
||||||
#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 waitq waitq_head = {0, 0, 0, 0, 0, 0, 0};// Start of queue for wait'ing threads
|
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
|
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 */
|
/* Function declarations */
|
||||||
static int __stdcall checkstate (waitq *) __attribute__ ((regparm (1)));
|
static int __stdcall checkstate (waitq *) __attribute__ ((regparm (1)));
|
||||||
static __inline__ bool get_proc_lock (DWORD, DWORD);
|
static __inline__ bool get_proc_lock (DWORD, DWORD);
|
||||||
static void __stdcall remove_zombie (int);
|
static bool __stdcall remove_proc (int);
|
||||||
static int __stdcall stopped_or_terminated (waitq *, _pinfo *);
|
static bool __stdcall stopped_or_terminated (waitq *, _pinfo *);
|
||||||
static DWORD WINAPI wait_subproc (VOID *);
|
|
||||||
static DWORD WINAPI wait_sig (VOID *arg);
|
static DWORD WINAPI wait_sig (VOID *arg);
|
||||||
|
|
||||||
/* wait_sig bookkeeping */
|
/* wait_sig bookkeeping */
|
||||||
|
@ -152,33 +132,13 @@ bool __stdcall
|
||||||
my_parent_is_alive ()
|
my_parent_is_alive ()
|
||||||
{
|
{
|
||||||
bool res;
|
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;
|
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;
|
return res;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -193,7 +153,7 @@ wait_for_sigthread ()
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Get the sync_proc_subproc muto to control access to
|
/* 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
|
* Attempt to handle case where process is exiting as we try to grab
|
||||||
* the mutex.
|
* the mutex.
|
||||||
*/
|
*/
|
||||||
|
@ -260,16 +220,11 @@ proc_exists (_pinfo *p)
|
||||||
/* Return 1 if this is one of our children, zero otherwise.
|
/* Return 1 if this is one of our children, zero otherwise.
|
||||||
FIXME: This really should be integrated with the rest of the proc_subproc
|
FIXME: This really should be integrated with the rest of the proc_subproc
|
||||||
testing. Scanning these lists twice is inefficient. */
|
testing. Scanning these lists twice is inefficient. */
|
||||||
int __stdcall
|
bool __stdcall
|
||||||
mychild (int pid)
|
mychild (int pid)
|
||||||
{
|
{
|
||||||
for (int i = 0; i < nchildren; i++)
|
pinfo p (pid);
|
||||||
if (pchildren[i]->pid == pid)
|
return p && p->ppid == myself->pid;
|
||||||
return 1;
|
|
||||||
for (int i = 0; i < nzombies; i++)
|
|
||||||
if (zombies[i]->pid == pid)
|
|
||||||
return 1;
|
|
||||||
return 0;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Handle all subprocess requests
|
/* Handle all subprocess requests
|
||||||
|
@ -283,7 +238,6 @@ proc_subproc (DWORD what, DWORD val)
|
||||||
_pinfo *child;
|
_pinfo *child;
|
||||||
int clearing;
|
int clearing;
|
||||||
waitq *w;
|
waitq *w;
|
||||||
int thiszombie;
|
|
||||||
|
|
||||||
#define wval ((waitq *) val)
|
#define wval ((waitq *) val)
|
||||||
|
|
||||||
|
@ -301,84 +255,32 @@ proc_subproc (DWORD what, DWORD val)
|
||||||
* (usually called from the main thread)
|
* (usually called from the main thread)
|
||||||
*/
|
*/
|
||||||
case PROC_ADDCHILD:
|
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;
|
rc = 0;
|
||||||
|
set_errno (EMFILE); // FIXMENOW - what's the right errno?
|
||||||
break;
|
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->ppid = myself->pid;
|
||||||
vchild->uid = myself->uid;
|
vchild->uid = myself->uid;
|
||||||
vchild->gid = myself->gid;
|
vchild->gid = myself->gid;
|
||||||
vchild->pgid = myself->pgid;
|
vchild->pgid = myself->pgid;
|
||||||
vchild->sid = myself->sid;
|
vchild->sid = myself->sid;
|
||||||
vchild->ctty = myself->ctty;
|
vchild->ctty = myself->ctty;
|
||||||
|
vchild->cygstarted = true;
|
||||||
vchild->process_state |= PID_INITIALIZING | (myself->process_state & PID_USETTY);
|
vchild->process_state |= PID_INITIALIZING | (myself->process_state & PID_USETTY);
|
||||||
|
procs[nprocs] = vchild;
|
||||||
sigproc_printf ("added pid %d to wait list, slot %d, winpid %p, handle %p",
|
rc = procs[nprocs].wait ();
|
||||||
vchild->pid, nchildren, vchild->dwProcessId,
|
if (rc)
|
||||||
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)
|
|
||||||
{
|
{
|
||||||
sigproc_printf ("pid %d[%d], reparented old hProcess %p, new %p",
|
sigproc_printf ("added pid %d to proc table, slot %d", vchild->pid,
|
||||||
pchildren[val]->pid, val, hchildren[val], pchildren[val]->hProcess);
|
nprocs);
|
||||||
HANDLE h = hchildren[val];
|
nprocs++;
|
||||||
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 ("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;
|
break;
|
||||||
|
|
||||||
/* Handle a wait4() operation. Allocates an event for the calling
|
/* 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)
|
if ((wval->ev = wval->thread_ev) == NULL)
|
||||||
{
|
{
|
||||||
wval->ev = wval->thread_ev = CreateEvent (&sec_none_nih, TRUE,
|
wval->ev = wval->thread_ev = CreateEvent (&sec_none_nih, TRUE, FALSE,
|
||||||
FALSE, NULL);
|
NULL);
|
||||||
ProtectHandle1 (wval->ev, wq_ev);
|
ProtectHandle1 (wval->ev, wq_ev);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -459,9 +361,8 @@ proc_subproc (DWORD what, DWORD val)
|
||||||
}
|
}
|
||||||
|
|
||||||
if (global_sigs[SIGCHLD].sa_handler == (void *) SIG_IGN)
|
if (global_sigs[SIGCHLD].sa_handler == (void *) SIG_IGN)
|
||||||
while (nzombies)
|
for (int i = 0; i < nprocs; i += remove_proc (i))
|
||||||
remove_zombie (0);
|
continue;
|
||||||
break;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
out:
|
out:
|
||||||
|
@ -492,54 +393,29 @@ _cygtls::remove_wq (DWORD wait)
|
||||||
* Called on process exit.
|
* Called on process exit.
|
||||||
* Also called by spawn_guts to disassociate any subprocesses from this
|
* Also called by spawn_guts to disassociate any subprocesses from this
|
||||||
* process. Subprocesses will then know to clean up after themselves and
|
* process. Subprocesses will then know to clean up after themselves and
|
||||||
* will not become zombies.
|
* will not become procs.
|
||||||
*/
|
*/
|
||||||
void __stdcall
|
void __stdcall
|
||||||
proc_terminate (void)
|
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. */
|
/* 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);
|
sync_proc_subproc->acquire (WPSP);
|
||||||
wake_wait_subproc (); // Wake wait_subproc loop
|
|
||||||
hwait_subproc = NULL;
|
|
||||||
|
|
||||||
(void) proc_subproc (PROC_CLEARWAIT, 1);
|
(void) proc_subproc (PROC_CLEARWAIT, 1);
|
||||||
|
|
||||||
/* Clean out zombie processes from the pid list. */
|
/* Clean out proc processes from the pid list. */
|
||||||
int i;
|
int i;
|
||||||
for (i = 0; i < nzombies; i++)
|
for (i = 0; i < nprocs; i++)
|
||||||
{
|
{
|
||||||
if (zombies[i]->hProcess)
|
procs[i]->ppid = 1;
|
||||||
{
|
if (!proc_exists (procs[i]))
|
||||||
ForceCloseHandle1 (zombies[i]->hProcess, childhProc);
|
procs[i]->process_state = PID_EXITED; /* CGF FIXME - still needed? */
|
||||||
ForceCloseHandle1 (zombies[i]->pid_handle, pid_handle);
|
procs[i].release ();
|
||||||
}
|
|
||||||
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
|
|
||||||
}
|
}
|
||||||
|
nprocs = 0;
|
||||||
/* 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;
|
|
||||||
sync_proc_subproc->release ();
|
sync_proc_subproc->release ();
|
||||||
}
|
}
|
||||||
sigproc_printf ("leaving");
|
sigproc_printf ("leaving");
|
||||||
|
@ -610,7 +486,7 @@ sigproc_init ()
|
||||||
ProtectHandle (wait_sig_inited);
|
ProtectHandle (wait_sig_inited);
|
||||||
|
|
||||||
/* sync_proc_subproc is used by proc_subproc. It serialises
|
/* 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);
|
new_muto (sync_proc_subproc);
|
||||||
|
|
||||||
|
@ -648,7 +524,7 @@ sigproc_terminate (void)
|
||||||
CloseHandle (sendsig);
|
CloseHandle (sendsig);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
proc_terminate (); // Terminate process handling thread
|
proc_terminate (); // clean up process stuff
|
||||||
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
@ -833,25 +709,6 @@ out:
|
||||||
return rc;
|
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
|
/* Initialize some of the memory block passed to child processes
|
||||||
by fork/spawn/exec. */
|
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->magic = CHILD_INFO_MAGIC;
|
||||||
ch->type = chtype;
|
ch->type = chtype;
|
||||||
ch->subproc_ready = subproc_ready;
|
ch->subproc_ready = subproc_ready;
|
||||||
ch->pppid_handle = myself->ppid_handle;
|
|
||||||
ch->fhandler_union_cb = sizeof (fhandler_union);
|
ch->fhandler_union_cb = sizeof (fhandler_union);
|
||||||
ch->user_h = cygwin_user_h;
|
ch->user_h = cygwin_user_h;
|
||||||
}
|
}
|
||||||
|
@ -877,132 +733,107 @@ checkstate (waitq *parent_w)
|
||||||
{
|
{
|
||||||
int potential_match = 0;
|
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
|
/* Check already dead processes first to see if they match the criteria
|
||||||
* given in w->next.
|
* given in w->next. */
|
||||||
*/
|
int res;
|
||||||
for (int i = 0; i < nzombies; i++)
|
for (int i = 0; i < nprocs; i++)
|
||||||
switch (stopped_or_terminated (parent_w, zombies[i]))
|
if ((res = stopped_or_terminated (parent_w, procs[i])))
|
||||||
{
|
{
|
||||||
case -1:
|
remove_proc (i);
|
||||||
potential_match = -1;
|
|
||||||
break;
|
|
||||||
case 1:
|
|
||||||
remove_zombie (i);
|
|
||||||
potential_match = 1;
|
potential_match = 1;
|
||||||
goto out;
|
goto out;
|
||||||
}
|
}
|
||||||
|
|
||||||
sigproc_printf ("checking alive children");
|
sigproc_printf ("no matching terminated children found");
|
||||||
|
potential_match = -!!nprocs;
|
||||||
/* 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;
|
|
||||||
}
|
|
||||||
|
|
||||||
out:
|
out:
|
||||||
sigproc_printf ("returning %d", potential_match);
|
sigproc_printf ("returning %d", potential_match);
|
||||||
return potential_match;
|
return potential_match;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Remove a zombie from zombies by swapping it with the last child in the list.
|
/* Remove a proc from procs by swapping it with the last child in the list.
|
||||||
*/
|
Also releases shared memory of exited processes. */
|
||||||
static void __stdcall
|
static bool __stdcall
|
||||||
remove_zombie (int ci)
|
remove_proc (int ci)
|
||||||
{
|
{
|
||||||
sigproc_printf ("removing %d, pid %d, nzombies %d", ci, zombies[ci]->pid,
|
if (proc_exists (procs[ci]))
|
||||||
nzombies);
|
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);
|
procs[ci].release ();
|
||||||
ForceCloseHandle1 (zombies[ci]->pid_handle, pid_handle);
|
if (procs[ci].pid_handle)
|
||||||
zombies[ci].release ();
|
ForceCloseHandle1 (procs[ci].pid_handle, childhProc);
|
||||||
|
if (procs[ci].hProcess)
|
||||||
|
ForceCloseHandle1 (procs[ci].hProcess, childhProc);
|
||||||
}
|
}
|
||||||
|
if (ci < --nprocs)
|
||||||
if (ci < --nzombies)
|
procs[ci] = procs[nprocs];
|
||||||
zombies[ci] = zombies[nzombies];
|
return 0;
|
||||||
|
|
||||||
return;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Check status of child process vs. waitq member.
|
/* Check status of child process vs. waitq member.
|
||||||
*
|
|
||||||
* parent_w is the pointer to the parent of the waitq member in question.
|
parent_w is the pointer to the parent of the waitq member in question.
|
||||||
* child is the subprocess being considered.
|
child is the subprocess being considered.
|
||||||
*
|
|
||||||
* Returns
|
Returns non-zero if waiting thread released. */
|
||||||
* 1 if stopped or terminated child matches parent_w->next criteria
|
static bool __stdcall
|
||||||
* -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
|
|
||||||
stopped_or_terminated (waitq *parent_w, _pinfo *child)
|
stopped_or_terminated (waitq *parent_w, _pinfo *child)
|
||||||
{
|
{
|
||||||
int potential_match;
|
int might_match;
|
||||||
waitq *w = parent_w->next;
|
waitq *w = parent_w->next;
|
||||||
|
|
||||||
sigproc_printf ("considering pid %d", child->pid);
|
sigproc_printf ("considering pid %d", child->pid);
|
||||||
if (w->pid == -1)
|
if (w->pid == -1)
|
||||||
potential_match = 1;
|
might_match = 1;
|
||||||
else if (w->pid == 0)
|
else if (w->pid == 0)
|
||||||
potential_match = child->pgid == myself->pgid;
|
might_match = child->pgid == myself->pgid;
|
||||||
else if (w->pid < 0)
|
else if (w->pid < 0)
|
||||||
potential_match = child->pgid == -w->pid;
|
might_match = child->pgid == -w->pid;
|
||||||
else
|
else
|
||||||
potential_match = (w->pid == child->pid);
|
might_match = (w->pid == child->pid);
|
||||||
|
|
||||||
if (!potential_match)
|
if (!might_match)
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
bool terminated;
|
int terminated;
|
||||||
|
|
||||||
if ((terminated = child->process_state == PID_ZOMBIE) ||
|
if (!((terminated = (child->process_state == PID_ZOMBIE)) ||
|
||||||
((w->options & WUNTRACED) && child->stopsig))
|
((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 */
|
sigproc_printf ("stopped child");
|
||||||
w->pid = child->pid;
|
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");
|
add_rusage ((struct rusage *) w->rusage, &child->rusage_children);
|
||||||
w->status = (child->stopsig << 8) | 0x7f;
|
add_rusage ((struct rusage *) w->rusage, &child->rusage_self);
|
||||||
child->stopsig = 0;
|
|
||||||
}
|
}
|
||||||
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
|
static void
|
||||||
|
@ -1078,27 +909,10 @@ wait_sig (VOID *self)
|
||||||
signals. Prior to this, dwProcessId was set to the windows pid of
|
signals. Prior to this, dwProcessId was set to the windows pid of
|
||||||
of the original windows process which spawned us unless this was a
|
of the original windows process which spawned us unless this was a
|
||||||
"toplevel" process. */
|
"toplevel" process. */
|
||||||
myself->dwProcessId = GetCurrentProcessId ();
|
|
||||||
myself->process_state |= PID_ACTIVE;
|
myself->process_state |= PID_ACTIVE;
|
||||||
myself->process_state &= ~PID_INITIALIZING;
|
myself->process_state &= ~PID_INITIALIZING;
|
||||||
|
|
||||||
sigproc_printf ("myself->dwProcessId %u", myself->dwProcessId);
|
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);
|
SetEvent (wait_sig_inited);
|
||||||
sigtid = GetCurrentThreadId ();
|
sigtid = GetCurrentThreadId ();
|
||||||
|
|
||||||
|
@ -1215,85 +1029,3 @@ wait_sig (VOID *self)
|
||||||
sigproc_printf ("done");
|
sigproc_printf ("done");
|
||||||
ExitThread (0);
|
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);
|
|
||||||
}
|
|
||||||
|
|
|
@ -12,10 +12,6 @@ details. */
|
||||||
#define _SIGPROC_H
|
#define _SIGPROC_H
|
||||||
#include <signal.h>
|
#include <signal.h>
|
||||||
|
|
||||||
#define EXIT_SIGNAL 0x010000
|
|
||||||
#define EXIT_REPARENTING 0x020000
|
|
||||||
#define EXIT_NOCLOSEALL 0x040000
|
|
||||||
|
|
||||||
#ifdef NSIG
|
#ifdef NSIG
|
||||||
enum
|
enum
|
||||||
{
|
{
|
||||||
|
@ -26,7 +22,8 @@ enum
|
||||||
__SIGDELETE = -(NSIG + 5),
|
__SIGDELETE = -(NSIG + 5),
|
||||||
__SIGFLUSHFAST = -(NSIG + 6),
|
__SIGFLUSHFAST = -(NSIG + 6),
|
||||||
__SIGHOLD = -(NSIG + 7),
|
__SIGHOLD = -(NSIG + 7),
|
||||||
__SIGNOHOLD = -(NSIG + 8)
|
__SIGNOHOLD = -(NSIG + 8),
|
||||||
|
__SIGREPARENT = (NSIG + 2)
|
||||||
};
|
};
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
@ -77,7 +74,6 @@ int __stdcall proc_subproc (DWORD, DWORD) __attribute__ ((regparm (2)));
|
||||||
class _pinfo;
|
class _pinfo;
|
||||||
void __stdcall proc_terminate ();
|
void __stdcall proc_terminate ();
|
||||||
void __stdcall sigproc_init ();
|
void __stdcall sigproc_init ();
|
||||||
void __stdcall subproc_init ();
|
|
||||||
void __stdcall sigproc_terminate ();
|
void __stdcall sigproc_terminate ();
|
||||||
bool __stdcall proc_exists (_pinfo *) __attribute__ ((regparm(1)));
|
bool __stdcall proc_exists (_pinfo *) __attribute__ ((regparm(1)));
|
||||||
bool __stdcall pid_exists (pid_t) __attribute__ ((regparm(1)));
|
bool __stdcall pid_exists (pid_t) __attribute__ ((regparm(1)));
|
||||||
|
|
|
@ -29,8 +29,6 @@ details. */
|
||||||
#include "child_info.h"
|
#include "child_info.h"
|
||||||
#include "shared_info.h"
|
#include "shared_info.h"
|
||||||
#include "pinfo.h"
|
#include "pinfo.h"
|
||||||
#define NEED_VFORK
|
|
||||||
#include "perthread.h"
|
|
||||||
#include "registry.h"
|
#include "registry.h"
|
||||||
#include "environ.h"
|
#include "environ.h"
|
||||||
#include "cygthread.h"
|
#include "cygthread.h"
|
||||||
|
@ -384,16 +382,7 @@ spawn_guts (const char * prog_arg, const char *const *argv,
|
||||||
else
|
else
|
||||||
chtype = PROC_EXEC;
|
chtype = PROC_EXEC;
|
||||||
|
|
||||||
HANDLE subproc_ready;
|
init_child_info (chtype, &ciresrv, NULL);
|
||||||
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);
|
|
||||||
|
|
||||||
ciresrv.moreinfo = (cygheap_exec_info *) ccalloc (HEAP_1_EXEC, 1, sizeof (cygheap_exec_info));
|
ciresrv.moreinfo = (cygheap_exec_info *) ccalloc (HEAP_1_EXEC, 1, sizeof (cygheap_exec_info));
|
||||||
ciresrv.moreinfo->old_title = NULL;
|
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->argc = newargv.argc;
|
||||||
ciresrv.moreinfo->argv = newargv;
|
ciresrv.moreinfo->argv = newargv;
|
||||||
ciresrv.hexec_proc = hexec_proc;
|
|
||||||
|
|
||||||
if (mode != _P_OVERLAY ||
|
if (mode != _P_OVERLAY ||
|
||||||
!DuplicateHandle (hMainProc, myself.shared_handle (), hMainProc,
|
!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 ())
|
if (mode == _P_DETACH || !set_console_state_for_spawn ())
|
||||||
flags |= DETACHED_PROCESS;
|
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
|
HANDLE saved_sendsig;
|
||||||
parent after CreateProcess and before copying the datastructures
|
if (mode != _P_OVERLAY)
|
||||||
to the child. So we have to start the child in suspend state,
|
saved_sendsig = NULL;
|
||||||
unfortunately, to avoid a race condition. */
|
else
|
||||||
if (cygheap->fdtab.need_fixup_before ())
|
{
|
||||||
flags |= CREATE_SUSPENDED;
|
/* 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;
|
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
|
/* Restore impersonation. In case of _P_OVERLAY this isn't
|
||||||
allowed since it would overwrite child data. */
|
allowed since it would overwrite child data. */
|
||||||
if (mode != _P_OVERLAY || !rc)
|
if (mode != _P_OVERLAY || !rc)
|
||||||
cygheap->user.reimpersonate ();
|
cygheap->user.reimpersonate ();
|
||||||
|
|
||||||
MALLOC_CHECK;
|
MALLOC_CHECK;
|
||||||
if (envblock)
|
if (envblock)
|
||||||
|
@ -732,12 +736,9 @@ spawn_guts (const char * prog_arg, const char *const *argv,
|
||||||
{
|
{
|
||||||
__seterrno ();
|
__seterrno ();
|
||||||
syscall_printf ("CreateProcess failed, %E");
|
syscall_printf ("CreateProcess failed, %E");
|
||||||
#if 0 // someday
|
/* If this was a failed exec, restore the saved sendsig. */
|
||||||
if (mode == _P_OVERLAY)
|
if (saved_sendsig)
|
||||||
myself->dwProcessId = GetCurrentProcessId ();
|
myself->sendsig = saved_sendsig;
|
||||||
#endif
|
|
||||||
if (subproc_ready)
|
|
||||||
ForceCloseHandle (subproc_ready);
|
|
||||||
cygheap_setup_for_child_cleanup (newheap, &ciresrv, 0);
|
cygheap_setup_for_child_cleanup (newheap, &ciresrv, 0);
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
@ -765,11 +766,6 @@ spawn_guts (const char * prog_arg, const char *const *argv,
|
||||||
{
|
{
|
||||||
cygheap->fdtab.fixup_before_exec (pi.dwProcessId);
|
cygheap->fdtab.fixup_before_exec (pi.dwProcessId);
|
||||||
cygheap_setup_for_child_cleanup (newheap, &ciresrv, 1);
|
cygheap_setup_for_child_cleanup (newheap, &ciresrv, 1);
|
||||||
if (mode == _P_OVERLAY)
|
|
||||||
{
|
|
||||||
ResumeThread (pi.hThread);
|
|
||||||
cygthread::terminate ();
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (mode != _P_OVERLAY)
|
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. */
|
/* Name the handle similarly to proc_subproc. */
|
||||||
ProtectHandle1 (pi.hProcess, childhProc);
|
ProtectHandle1 (pi.hProcess, childhProc);
|
||||||
|
|
||||||
|
int wait_for_myself = false;
|
||||||
|
DWORD exec_cygstarted;
|
||||||
if (mode == _P_OVERLAY)
|
if (mode == _P_OVERLAY)
|
||||||
{
|
{
|
||||||
/* These are both duplicated in the child code. We do this here,
|
/* Store the old exec_cygstarted since this is used as a crude semaphore for
|
||||||
primarily for strace. */
|
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;
|
strace.execing = 1;
|
||||||
hExeced = pi.hProcess;
|
hExeced = pi.hProcess;
|
||||||
dwExeced = pi.dwProcessId;
|
|
||||||
strcpy (myself->progname, real_path);
|
strcpy (myself->progname, real_path);
|
||||||
close_all_files ();
|
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
|
else
|
||||||
{
|
{
|
||||||
|
exec_cygstarted = 0;
|
||||||
myself->set_has_pgid_children ();
|
myself->set_has_pgid_children ();
|
||||||
ProtectHandle (pi.hThread);
|
ProtectHandle (pi.hThread);
|
||||||
pinfo child (cygpid, PID_IN_USE);
|
pinfo child (cygpid, PID_IN_USE);
|
||||||
|
@ -808,7 +822,7 @@ spawn_guts (const char * prog_arg, const char *const *argv,
|
||||||
goto out;
|
goto out;
|
||||||
}
|
}
|
||||||
child->dwProcessId = pi.dwProcessId;
|
child->dwProcessId = pi.dwProcessId;
|
||||||
child->hProcess = pi.hProcess;
|
child.hProcess = pi.hProcess;
|
||||||
if (!child.remember ())
|
if (!child.remember ())
|
||||||
{
|
{
|
||||||
syscall_printf ("process table full");
|
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. */
|
However, we should try to find another way to do this eventually. */
|
||||||
(void) DuplicateHandle (hMainProc, child.shared_handle (), pi.hProcess,
|
(void) DuplicateHandle (hMainProc, child.shared_handle (), pi.hProcess,
|
||||||
NULL, 0, 0, DUPLICATE_SAME_ACCESS);
|
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.hThread);
|
||||||
|
// ForceCloseHandle (pi.hProcess); // handled by proc_subproc and friends
|
||||||
|
|
||||||
sigproc_printf ("spawned windows pid %d", pi.dwProcessId);
|
sigproc_printf ("spawned windows pid %d", pi.dwProcessId);
|
||||||
|
|
||||||
bool exited;
|
if (wait_for_myself)
|
||||||
|
waitpid (myself->pid, &res, 0);
|
||||||
res = 0;
|
else
|
||||||
exited = false;
|
|
||||||
MALLOC_CHECK;
|
|
||||||
if (mode == _P_OVERLAY)
|
|
||||||
{
|
{
|
||||||
int nwait = 3;
|
/* Loop, waiting for parent to notice pid change, if exec_cygstarted.
|
||||||
HANDLE waitbuf[3] = {pi.hProcess, signal_arrived, subproc_ready};
|
In theory this wait should be a no-op. */
|
||||||
for (int i = 0; i < 100; i++)
|
if (exec_cygstarted)
|
||||||
{
|
while (myself->cygstarted == exec_cygstarted)
|
||||||
switch (WaitForMultipleObjects (nwait, waitbuf, FALSE, INFINITE))
|
low_priority_sleep (0);
|
||||||
{
|
res = 42;
|
||||||
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);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
MALLOC_CHECK;
|
|
||||||
|
|
||||||
switch (mode)
|
switch (mode)
|
||||||
{
|
{
|
||||||
case _P_OVERLAY:
|
case _P_OVERLAY:
|
||||||
ForceCloseHandle1 (pi.hProcess, childhProc);
|
|
||||||
myself->exit (res, 1);
|
myself->exit (res, 1);
|
||||||
break;
|
break;
|
||||||
case _P_WAIT:
|
case _P_WAIT:
|
||||||
|
@ -986,7 +930,6 @@ spawnve (int mode, const char *path, const char *const *argv,
|
||||||
case _P_WAIT:
|
case _P_WAIT:
|
||||||
case _P_DETACH:
|
case _P_DETACH:
|
||||||
case _P_SYSTEM:
|
case _P_SYSTEM:
|
||||||
subproc_init ();
|
|
||||||
ret = spawn_guts (path, argv, envp, mode);
|
ret = spawn_guts (path, argv, envp, mode);
|
||||||
#ifdef NEWVFORK
|
#ifdef NEWVFORK
|
||||||
if (vf)
|
if (vf)
|
||||||
|
|
|
@ -56,8 +56,6 @@ details. */
|
||||||
#include "pinfo.h"
|
#include "pinfo.h"
|
||||||
#include "shared_info.h"
|
#include "shared_info.h"
|
||||||
#include "cygheap.h"
|
#include "cygheap.h"
|
||||||
#define NEED_VFORK
|
|
||||||
#include "perthread.h"
|
|
||||||
#include "pwdgrp.h"
|
#include "pwdgrp.h"
|
||||||
#include "cpuid.h"
|
#include "cpuid.h"
|
||||||
#include "registry.h"
|
#include "registry.h"
|
||||||
|
|
|
@ -16,7 +16,6 @@ details. */
|
||||||
#include "hires.h"
|
#include "hires.h"
|
||||||
#include "thread.h"
|
#include "thread.h"
|
||||||
#include "cygtls.h"
|
#include "cygtls.h"
|
||||||
#include "cygthread.h"
|
|
||||||
#include "sigproc.h"
|
#include "sigproc.h"
|
||||||
#include "sync.h"
|
#include "sync.h"
|
||||||
|
|
||||||
|
|
|
@ -23,7 +23,6 @@ details. */
|
||||||
#include "pinfo.h"
|
#include "pinfo.h"
|
||||||
#include "hires.h"
|
#include "hires.h"
|
||||||
#include "cygtls.h"
|
#include "cygtls.h"
|
||||||
#include "cygthread.h"
|
|
||||||
#include "sigproc.h"
|
#include "sigproc.h"
|
||||||
#include "sync.h"
|
#include "sync.h"
|
||||||
|
|
||||||
|
|
|
@ -1,113 +1,117 @@
|
||||||
//;# autogenerated: Do not edit.
|
//;# autogenerated: Do not edit.
|
||||||
|
|
||||||
//; $tls::sizeof__cygtls = 3932;
|
//; $tls::sizeof__cygtls = 3936;
|
||||||
//; $tls::func = -3932;
|
//; $tls::func = -3936;
|
||||||
//; $tls::pfunc = 0;
|
//; $tls::pfunc = 0;
|
||||||
//; $tls::saved_errno = -3928;
|
//; $tls::saved_errno = -3932;
|
||||||
//; $tls::psaved_errno = 4;
|
//; $tls::psaved_errno = 4;
|
||||||
//; $tls::sa_flags = -3924;
|
//; $tls::sa_flags = -3928;
|
||||||
//; $tls::psa_flags = 8;
|
//; $tls::psa_flags = 8;
|
||||||
//; $tls::oldmask = -3920;
|
//; $tls::oldmask = -3924;
|
||||||
//; $tls::poldmask = 12;
|
//; $tls::poldmask = 12;
|
||||||
//; $tls::deltamask = -3916;
|
//; $tls::deltamask = -3920;
|
||||||
//; $tls::pdeltamask = 16;
|
//; $tls::pdeltamask = 16;
|
||||||
//; $tls::event = -3912;
|
//; $tls::event = -3916;
|
||||||
//; $tls::pevent = 20;
|
//; $tls::pevent = 20;
|
||||||
//; $tls::errno_addr = -3908;
|
//; $tls::errno_addr = -3912;
|
||||||
//; $tls::perrno_addr = 24;
|
//; $tls::perrno_addr = 24;
|
||||||
//; $tls::initialized = -3904;
|
//; $tls::initialized = -3908;
|
||||||
//; $tls::pinitialized = 28;
|
//; $tls::pinitialized = 28;
|
||||||
//; $tls::sigmask = -3900;
|
//; $tls::sigmask = -3904;
|
||||||
//; $tls::psigmask = 32;
|
//; $tls::psigmask = 32;
|
||||||
//; $tls::sigwait_mask = -3896;
|
//; $tls::sigwait_mask = -3900;
|
||||||
//; $tls::psigwait_mask = 36;
|
//; $tls::psigwait_mask = 36;
|
||||||
//; $tls::sigwait_info = -3892;
|
//; $tls::sigwait_info = -3896;
|
||||||
//; $tls::psigwait_info = 40;
|
//; $tls::psigwait_info = 40;
|
||||||
//; $tls::threadkill = -3888;
|
//; $tls::threadkill = -3892;
|
||||||
//; $tls::pthreadkill = 44;
|
//; $tls::pthreadkill = 44;
|
||||||
//; $tls::infodata = -3884;
|
//; $tls::infodata = -3888;
|
||||||
//; $tls::pinfodata = 48;
|
//; $tls::pinfodata = 48;
|
||||||
//; $tls::tid = -3736;
|
//; $tls::tid = -3740;
|
||||||
//; $tls::ptid = 196;
|
//; $tls::ptid = 196;
|
||||||
//; $tls::local_clib = -3732;
|
//; $tls::local_clib = -3736;
|
||||||
//; $tls::plocal_clib = 200;
|
//; $tls::plocal_clib = 200;
|
||||||
//; $tls::__dontuse = -3732;
|
//; $tls::__dontuse = -3736;
|
||||||
//; $tls::p__dontuse = 200;
|
//; $tls::p__dontuse = 200;
|
||||||
//; $tls::locals = -2668;
|
//; $tls::locals = -2672;
|
||||||
//; $tls::plocals = 1264;
|
//; $tls::plocals = 1264;
|
||||||
|
//; $tls::_ctinfo = -1084;
|
||||||
|
//; $tls::p_ctinfo = 2852;
|
||||||
//; $tls::wq = -1080;
|
//; $tls::wq = -1080;
|
||||||
//; $tls::pwq = 2852;
|
//; $tls::pwq = 2856;
|
||||||
//; $tls::prev = -1052;
|
//; $tls::prev = -1052;
|
||||||
//; $tls::pprev = 2880;
|
//; $tls::pprev = 2884;
|
||||||
//; $tls::next = -1048;
|
//; $tls::next = -1048;
|
||||||
//; $tls::pnext = 2884;
|
//; $tls::pnext = 2888;
|
||||||
//; $tls::stackptr = -1044;
|
//; $tls::stackptr = -1044;
|
||||||
//; $tls::pstackptr = 2888;
|
//; $tls::pstackptr = 2892;
|
||||||
//; $tls::sig = -1040;
|
//; $tls::sig = -1040;
|
||||||
//; $tls::psig = 2892;
|
//; $tls::psig = 2896;
|
||||||
//; $tls::incyg = -1036;
|
//; $tls::incyg = -1036;
|
||||||
//; $tls::pincyg = 2896;
|
//; $tls::pincyg = 2900;
|
||||||
//; $tls::spinning = -1032;
|
//; $tls::spinning = -1032;
|
||||||
//; $tls::pspinning = 2900;
|
//; $tls::pspinning = 2904;
|
||||||
//; $tls::stacklock = -1028;
|
//; $tls::stacklock = -1028;
|
||||||
//; $tls::pstacklock = 2904;
|
//; $tls::pstacklock = 2908;
|
||||||
//; $tls::stack = -1024;
|
//; $tls::stack = -1024;
|
||||||
//; $tls::pstack = 2908;
|
//; $tls::pstack = 2912;
|
||||||
//; $tls::padding = 0;
|
//; $tls::padding = 0;
|
||||||
//; $tls::ppadding = 3932;
|
//; $tls::ppadding = 3936;
|
||||||
//; __DATA__
|
//; __DATA__
|
||||||
|
|
||||||
#define tls_func (-3932)
|
#define tls_func (-3936)
|
||||||
#define tls_pfunc (0)
|
#define tls_pfunc (0)
|
||||||
#define tls_saved_errno (-3928)
|
#define tls_saved_errno (-3932)
|
||||||
#define tls_psaved_errno (4)
|
#define tls_psaved_errno (4)
|
||||||
#define tls_sa_flags (-3924)
|
#define tls_sa_flags (-3928)
|
||||||
#define tls_psa_flags (8)
|
#define tls_psa_flags (8)
|
||||||
#define tls_oldmask (-3920)
|
#define tls_oldmask (-3924)
|
||||||
#define tls_poldmask (12)
|
#define tls_poldmask (12)
|
||||||
#define tls_deltamask (-3916)
|
#define tls_deltamask (-3920)
|
||||||
#define tls_pdeltamask (16)
|
#define tls_pdeltamask (16)
|
||||||
#define tls_event (-3912)
|
#define tls_event (-3916)
|
||||||
#define tls_pevent (20)
|
#define tls_pevent (20)
|
||||||
#define tls_errno_addr (-3908)
|
#define tls_errno_addr (-3912)
|
||||||
#define tls_perrno_addr (24)
|
#define tls_perrno_addr (24)
|
||||||
#define tls_initialized (-3904)
|
#define tls_initialized (-3908)
|
||||||
#define tls_pinitialized (28)
|
#define tls_pinitialized (28)
|
||||||
#define tls_sigmask (-3900)
|
#define tls_sigmask (-3904)
|
||||||
#define tls_psigmask (32)
|
#define tls_psigmask (32)
|
||||||
#define tls_sigwait_mask (-3896)
|
#define tls_sigwait_mask (-3900)
|
||||||
#define tls_psigwait_mask (36)
|
#define tls_psigwait_mask (36)
|
||||||
#define tls_sigwait_info (-3892)
|
#define tls_sigwait_info (-3896)
|
||||||
#define tls_psigwait_info (40)
|
#define tls_psigwait_info (40)
|
||||||
#define tls_threadkill (-3888)
|
#define tls_threadkill (-3892)
|
||||||
#define tls_pthreadkill (44)
|
#define tls_pthreadkill (44)
|
||||||
#define tls_infodata (-3884)
|
#define tls_infodata (-3888)
|
||||||
#define tls_pinfodata (48)
|
#define tls_pinfodata (48)
|
||||||
#define tls_tid (-3736)
|
#define tls_tid (-3740)
|
||||||
#define tls_ptid (196)
|
#define tls_ptid (196)
|
||||||
#define tls_local_clib (-3732)
|
#define tls_local_clib (-3736)
|
||||||
#define tls_plocal_clib (200)
|
#define tls_plocal_clib (200)
|
||||||
#define tls___dontuse (-3732)
|
#define tls___dontuse (-3736)
|
||||||
#define tls_p__dontuse (200)
|
#define tls_p__dontuse (200)
|
||||||
#define tls_locals (-2668)
|
#define tls_locals (-2672)
|
||||||
#define tls_plocals (1264)
|
#define tls_plocals (1264)
|
||||||
|
#define tls__ctinfo (-1084)
|
||||||
|
#define tls_p_ctinfo (2852)
|
||||||
#define tls_wq (-1080)
|
#define tls_wq (-1080)
|
||||||
#define tls_pwq (2852)
|
#define tls_pwq (2856)
|
||||||
#define tls_prev (-1052)
|
#define tls_prev (-1052)
|
||||||
#define tls_pprev (2880)
|
#define tls_pprev (2884)
|
||||||
#define tls_next (-1048)
|
#define tls_next (-1048)
|
||||||
#define tls_pnext (2884)
|
#define tls_pnext (2888)
|
||||||
#define tls_stackptr (-1044)
|
#define tls_stackptr (-1044)
|
||||||
#define tls_pstackptr (2888)
|
#define tls_pstackptr (2892)
|
||||||
#define tls_sig (-1040)
|
#define tls_sig (-1040)
|
||||||
#define tls_psig (2892)
|
#define tls_psig (2896)
|
||||||
#define tls_incyg (-1036)
|
#define tls_incyg (-1036)
|
||||||
#define tls_pincyg (2896)
|
#define tls_pincyg (2900)
|
||||||
#define tls_spinning (-1032)
|
#define tls_spinning (-1032)
|
||||||
#define tls_pspinning (2900)
|
#define tls_pspinning (2904)
|
||||||
#define tls_stacklock (-1028)
|
#define tls_stacklock (-1028)
|
||||||
#define tls_pstacklock (2904)
|
#define tls_pstacklock (2908)
|
||||||
#define tls_stack (-1024)
|
#define tls_stack (-1024)
|
||||||
#define tls_pstack (2908)
|
#define tls_pstack (2912)
|
||||||
#define tls_padding (0)
|
#define tls_padding (0)
|
||||||
#define tls_ppadding (3932)
|
#define tls_ppadding (3936)
|
||||||
|
|
|
@ -57,7 +57,7 @@ ttyslot (void)
|
||||||
void __stdcall
|
void __stdcall
|
||||||
tty_init (void)
|
tty_init (void)
|
||||||
{
|
{
|
||||||
if (!myself->ppid_handle && NOTSTATE (myself, PID_CYGPARENT))
|
if (!myself->cygstarted && NOTSTATE (myself, PID_CYGPARENT))
|
||||||
cygheap->fdtab.get_debugger_info ();
|
cygheap->fdtab.get_debugger_info ();
|
||||||
|
|
||||||
if (NOTSTATE (myself, PID_USETTY))
|
if (NOTSTATE (myself, PID_USETTY))
|
||||||
|
|
|
@ -13,7 +13,6 @@ details. */
|
||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
#include "cygerrno.h"
|
#include "cygerrno.h"
|
||||||
#include "sigproc.h"
|
#include "sigproc.h"
|
||||||
#include "perthread.h"
|
|
||||||
#include "thread.h"
|
#include "thread.h"
|
||||||
#include "cygtls.h"
|
#include "cygtls.h"
|
||||||
|
|
||||||
|
|
|
@ -23,7 +23,6 @@ details. */
|
||||||
#include "cygerrno.h"
|
#include "cygerrno.h"
|
||||||
#include "perprocess.h"
|
#include "perprocess.h"
|
||||||
#include "security.h"
|
#include "security.h"
|
||||||
#include "cygthread.h"
|
|
||||||
#include "thread.h"
|
#include "thread.h"
|
||||||
#include "cygtls.h"
|
#include "cygtls.h"
|
||||||
#include "sync.h"
|
#include "sync.h"
|
||||||
|
|
Loading…
Reference in New Issue