diff options
Diffstat (limited to 'winsup/cygwin')
33 files changed, 655 insertions, 797 deletions
diff --git a/winsup/cygwin/ChangeLog b/winsup/cygwin/ChangeLog index 8d999c2..600ca06 100644 --- a/winsup/cygwin/ChangeLog +++ b/winsup/cygwin/ChangeLog @@ -1,3 +1,134 @@ +2004-11-25 Christopher Faylor <cgf@timesys.com> + + * child_info.h (child_info_spawn::hexec_proc): Eliminate. + * dcrt0.cc (dll_crt0_0): Remove hexec_proc stuff. + * fork.cc (fork_child): Remove call to pinfo_fixup_after_fork. + * pinfo.cc (set_myself): Close and zero pid_handle if set. + (pinfo_fixup_after_fork): Delete. + (proc_waiter): Don't close vchild.hProcess here. Do that when we are + remove the vchild from procs. Save hProcess as pid_handle only on + first reparent operation. + (pinfo::wait): Don't set pid_handle here. + (pinfo::alert_parent): Always try to send signal. If unsuccessful then + close and zero wr_proc_pipe. + * pinfo.h (pinfo::pinfo): Make sure that appropriate parts of the class + are zeroed on construction. + (pinfo::alert_parent): Take char argument. + (pinfo_fixup_after_fork): Delete declaration. + (hexec_proc): Ditto. + * sigproc.cc (remove_proc): Close pid_handle and hProcess if + appropriate. + * spawn.cc (spawn_guts): Set cygheap->pid_handle on first exec. + +2004-11-25 Christopher Faylor <cgf@timesys.com> + + * cygheap.h (init_cygheap::pid_handle): New element. + * pinfo.cc (set_myself): Clear previously existing cygheap->pid_handle + when a new process has been started. + (pinfo::wait): Make sure that a handle to the newly forked/spawned + process is kept around so that the pid will not be reused. + * pinfo.h (_pinfo::pid_handle): Move. + (pinfo::pid_handle): to here. + * spawn.cc (spawn_guts): Create a pid_handle in cygheap prior to + spawning to ensure that the pid does not get reused during the lifetime + of the "cygwin pid". + +2004-11-25 Christopher Faylor <cgf@timesys.com> + + * pinfo.h (pinfo::alert_parent): New function. + * exceptions.cc (sig_handle_tty_stop): Use alert_parent to send + "signals" to parent. + * fork.cc (fork_parent): Don't close pi.hProcess. Let the waiter + thread do that. + * pinfo.cc (proc_waiter): Detect case where process exits without + setting the exit code and use value from GetExitCodeProcess. + Reluctantly implement __SIGREPARENT. + (pinfo::alert_parent): Define. + * sigproc.h (__SIGREPARENT): New enum. + * spawn.cc (spawn_guts): Send reparent signal to parent on exec. + Always create process in suspended state to avoid races. + +2004-11-25 Christopher Faylor <cgf@timesys.com> + + Remove cygthread.h in favor of cygtls.h throughout since cygtls now + includes cygthread.h. Eliminate ppid_handle usage throughout. + * child_info.h: Regenerate magic number + (child_info): Remove pppid_handle. + * cygthread.h (cygthread::release): New method. Frees thread without + waiting. + * cygthread.cc (cygthread::stub): Set _ctinfo in _mytls to point to + information for executing thread. Don't call SetEvent if thread is no + longer in use. + (cygthread::simplestub): Ditto. + * cygtls.h (_cygtls::_ctinfo): New element contains pointer to + information about executing cygthread, if any. + * dcrt0.cc: Remove last vestiges of per_thread stuff. + (dll_crt0_0): Ditto. Remove accommodation for ppid_handle. + (do_exit): Remove obsolete reparenting test. + (_exit): Exit with a more SUSv3-like exit value. + * dtable.cc (dtable::stdio_init): Check for myself->cygstarted rather + than myself->ppid_handle to see if we were started by a cygwin process. + * exceptions.cc (open_stackdumpfile): Ditto. + (handle_exceptions): Ditto. + (ctrl_c_handler): Ditto. + (sig_handle_tty_stop): Ditto. Let parent send signal to itself on + STOP. + (sigpacket::process): Comment out vfork test. + (signal_exit): Use more SUSv3-like exit value on signal. + * external.cc (fillout_pinfo): Don't set hProcess. + * fork.cc: Remove VFORK cruft. + (per_thread::set): Delete. + (fork_child): Remove perthread stuff. + (fork_parent): Remove obsolete subproc_init. Accommodate new method + for tracking subprocesses. + * pinfo.cc (set_myself): Accommodate new pinfo/_pinfo layout. Set some + things here that used to be set in wait_sig. + (_pinfo::exit): Set exitcode here. Close process pipe. + (_pinfo::commune_send): Accommodeate new pinfo/_pinfo layout. + (proc_waiter): New function. Waits, in a thread for subprocess to go + away. + (pinfo::wait): New function. Initialization for proc_waiter. + * pinfo.h (_pinfo::exitcode): New element. + (_pinfo::cygstarted): Ditto. + (_pinfo::wr_proc_pipe): Ditto. + (_pinfo::ppid_handle): Delete. + (_pinfo::hProcess): Delete. + (_pinfo::lock): Delete. + (pinfo::hProcess): New element. + (pinfo::lock): Ditto. + (pinfo::wait): Declare new function. + (pinfo::preserve): Define new function. + * sigproc.cc: Remove old stuff from wait_subproc thread based method. + (zombies): Remove. + (procs): New. + (my_parent_is_alive): Just check that the parent pid exists. + (mychild): Just use pinfo methods to determine if child is mine. + (proc_subproc): Revamp PROC_ADDCHILD to use pinfo::wait. Remove + PROC_CHILDTERMINATED logic. Use different method to remove processes + from list when SIGCHLD == SIG_IGN. + (proc_terminate): Gut. + (subproc_init): Delete. + (init_child_info): Remove setting of pppid_handle. + (checkstate): Revamp to only scan procs array. + (remove_proc): Rename from remove_zombie. Don't close hProcess or + pid_handle. Don't release memory if it's myself. + (stopped_or_terminated): Change logic to handle new consolidated + proc/zombie array. + (wait_subproc): Delete. + * sigproc.h: Remove obsolete EXIT_* defines. + (subproc_init): Remove declaration. + * spawn.cc (spawn_guts): Remove reparenting stuff. Use standard wait + logic to wait for child if started from a non-cygwin process. + * tlsoffsets.h: Regenerate. + * tty.cc (tty_init): Check for myself->cygstarted rather than + myself->ppid_handle to see if we were started by a cygwin process. + * include/sys/signal.h (external_pinfo::exitcode): Replace hProcess. + * include/sys/wait.h (WCOREDUMP): Define. + + * fhandler_tty.cc (fhandler_tty_slave::read): Add debugging output for + timeout case. + * signal.cc (abort): Flag that we are exiting with the ABORT signal. + 2004-11-22 Christopher Faylor <cgf@timesys.com> * select.cc (select_stuff::test_and_set): Remove extraneous tests of diff --git a/winsup/cygwin/child_info.h b/winsup/cygwin/child_info.h index 3088bea..7cbcb6f 100644 --- a/winsup/cygwin/child_info.h +++ b/winsup/cygwin/child_info.h @@ -29,7 +29,7 @@ enum #define EXEC_MAGIC_SIZE sizeof(child_info) -#define CURR_CHILD_INFO_MAGIC 0x19c16fb6U +#define CURR_CHILD_INFO_MAGIC 0x83e9a7b7U /* NOTE: Do not make gratuitous changes to the names or organization of the below class. The layout is checksummed to determine compatibility between @@ -45,7 +45,6 @@ public: HANDLE subproc_ready; // used for synchronization with parent HANDLE user_h; HANDLE parent; - HANDLE pppid_handle; init_cygheap *cygheap; void *cygheap_max; DWORD cygheap_reserve_sz; @@ -83,7 +82,6 @@ class child_info_spawn: public child_info { public: cygheap_exec_info *moreinfo; - HANDLE hexec_proc; child_info_spawn (): moreinfo (NULL) {} ~child_info_spawn () diff --git a/winsup/cygwin/cygheap.h b/winsup/cygwin/cygheap.h index 9e86519..323ab0a 100644 --- a/winsup/cygwin/cygheap.h +++ b/winsup/cygwin/cygheap.h @@ -289,6 +289,7 @@ struct init_cygheap size_t sthreads; int open_fhs; pid_t pid; /* my pid */ + HANDLE pid_handle; /* handle for my pid */ void close_ctty (); }; diff --git a/winsup/cygwin/cygthread.cc b/winsup/cygwin/cygthread.cc index 7ad860b..1f071b8 100644 --- a/winsup/cygwin/cygthread.cc +++ b/winsup/cygwin/cygthread.cc @@ -11,7 +11,6 @@ details. */ #include <stdlib.h> #include "exceptions.h" #include "security.h" -#include "cygthread.h" #include "sync.h" #include "cygerrno.h" #include "sigproc.h" @@ -33,6 +32,7 @@ DWORD WINAPI cygthread::stub (VOID *arg) { cygthread *info = (cygthread *) arg; + _my_tls._ctinfo = info; if (info->arg == cygself) { if (info->ev) @@ -69,7 +69,8 @@ cygthread::stub (VOID *arg) info->func = NULL; // catch erroneous activation #endif info->__name = NULL; - SetEvent (info->ev); + if (info->inuse) + SetEvent (info->ev); } switch (WaitForSingleObject (info->thread_sync, INFINITE)) { @@ -88,6 +89,7 @@ DWORD WINAPI cygthread::simplestub (VOID *arg) { cygthread *info = (cygthread *) arg; + _my_tls._ctinfo = info; info->stack_ptr = &arg; info->ev = info->h; info->func (info->arg == cygself ? info : info->arg); diff --git a/winsup/cygwin/cygthread.h b/winsup/cygwin/cygthread.h index ff174c9..dfeef90 100644 --- a/winsup/cygwin/cygthread.h +++ b/winsup/cygwin/cygthread.h @@ -6,6 +6,9 @@ This software is a copyrighted work licensed under the terms of the Cygwin license. Please consult the file "CYGWIN_LICENSE" for details. */ +#ifndef _CYGTHREAD_H +#define _CYGTHREAD_H + class cygthread { LONG inuse; @@ -25,6 +28,7 @@ class cygthread static DWORD WINAPI simplestub (VOID *); static DWORD main_thread_id; static const char * name (DWORD = 0); + void release () { __name = NULL; inuse = false; } cygthread (LPTHREAD_START_ROUTINE, LPVOID, const char *); cygthread () {}; static void init (); @@ -43,3 +47,4 @@ class cygthread }; #define cygself NULL +#endif /*_CYGTHREAD_H*/ diff --git a/winsup/cygwin/cygtls.cc b/winsup/cygwin/cygtls.cc index 6be3881..22db636 100644 --- a/winsup/cygwin/cygtls.cc +++ b/winsup/cygwin/cygtls.cc @@ -19,7 +19,6 @@ details. */ #include "fhandler.h" #include "dtable.h" #include "cygheap.h" -#include "cygthread.h" #include "pinfo.h" #include "sigproc.h" diff --git a/winsup/cygwin/cygtls.h b/winsup/cygwin/cygtls.h index 016bf8c..deff108 100644 --- a/winsup/cygwin/cygtls.h +++ b/winsup/cygwin/cygtls.h @@ -32,6 +32,8 @@ details. */ #define TLS_STACK_SIZE 256 +#include "cygthread.h" + #pragma pack(push,4) struct _local_storage { @@ -131,6 +133,7 @@ struct _cygtls char __dontuse[8 * ((sizeof(struct _reent) + 4) / 8)]; }; struct _local_storage locals; + class cygthread *_ctinfo; waitq wq; struct _cygtls *prev, *next; __stack_t *stackptr; diff --git a/winsup/cygwin/dcrt0.cc b/winsup/cygwin/dcrt0.cc index 47cd8b1..51b197e 100644 --- a/winsup/cygwin/dcrt0.cc +++ b/winsup/cygwin/dcrt0.cc @@ -29,11 +29,10 @@ details. */ #include "dtable.h" #include "cygheap.h" #include "child_info_magic.h" -#include "perthread.h" +#include "cygtls.h" #include "shared_info.h" #include "cygwin_version.h" #include "dll_init.h" -#include "cygthread.h" #include "sync.h" #include "heap.h" @@ -44,16 +43,6 @@ details. */ HANDLE NO_COPY hMainProc = (HANDLE) -1; HANDLE NO_COPY hMainThread; -#ifdef NEWVFORK -per_thread_vfork NO_COPY vfork_storage; -#endif - -per_thread NO_COPY *threadstuff[] = { -#ifdef NEWVFORK - &vfork_storage, -#endif - NULL}; - bool display_title; bool strip_title_path; bool allow_glob = true; @@ -656,8 +645,6 @@ dll_crt0_0 () memory_init (); else { - bool close_ppid_handle = false; - bool close_hexec_proc = false; switch (child_proc_info->type) { case _PROC_FORK: @@ -665,16 +652,9 @@ dll_crt0_0 () cygheap_fixup_in_child (false); memory_init (); set_myself (NULL); - close_ppid_handle = !!child_proc_info->pppid_handle; break; case _PROC_SPAWN: - /* Have to delay closes until after cygheap is setup */ - close_hexec_proc = !!spawn_info->hexec_proc; - close_ppid_handle = !!child_proc_info->pppid_handle; - goto around; case _PROC_EXEC: - hexec_proc = spawn_info->hexec_proc; - around: HANDLE h; cygheap_fixup_in_child (true); memory_init (); @@ -697,10 +677,6 @@ dll_crt0_0 () } break; } - if (close_hexec_proc) - CloseHandle (spawn_info->hexec_proc); - if (close_ppid_handle) - CloseHandle (child_proc_info->pppid_handle); } _cygtls::init (); @@ -1014,13 +990,10 @@ do_exit (int status) if (exit_state < ES_SIGNAL) { exit_state = ES_SIGNAL; - if (!(n & EXIT_REPARENTING)) - { - signal (SIGCHLD, SIG_IGN); - signal (SIGHUP, SIG_IGN); - signal (SIGINT, SIG_IGN); - signal (SIGQUIT, SIG_IGN); - } + signal (SIGCHLD, SIG_IGN); + signal (SIGHUP, SIG_IGN); + signal (SIGINT, SIG_IGN); + signal (SIGQUIT, SIG_IGN); } if (exit_state < ES_CLOSEALL) @@ -1112,7 +1085,7 @@ cygwin_exit (int n) extern "C" void _exit (int n) { - do_exit ((DWORD) n & 0xffff); + do_exit (((DWORD) n & 0xff) << 8); } extern "C" void diff --git a/winsup/cygwin/debug.cc b/winsup/cygwin/debug.cc index db5da1a..7411a5d 100644 --- a/winsup/cygwin/debug.cc +++ b/winsup/cygwin/debug.cc @@ -11,7 +11,6 @@ details. */ #include "sync.h" #include "sigproc.h" #include "pinfo.h" -#include "perthread.h" #include "perprocess.h" #include "security.h" #include "cygerrno.h" diff --git a/winsup/cygwin/dtable.cc b/winsup/cygwin/dtable.cc index cc72a2a..81c84a9 100644 --- a/winsup/cygwin/dtable.cc +++ b/winsup/cygwin/dtable.cc @@ -140,7 +140,7 @@ dtable::stdio_init () Also, always set them even if we're to pick up our parent's fds in case they're missed. */ - if (myself->ppid_handle || ISSTATE (myself, PID_CYGPARENT)) + if (myself->cygstarted || ISSTATE (myself, PID_CYGPARENT)) return; HANDLE in = GetStdHandle (STD_INPUT_HANDLE); diff --git a/winsup/cygwin/exceptions.cc b/winsup/cygwin/exceptions.cc index 510f534..bc28cc8 100644 --- a/winsup/cygwin/exceptions.cc +++ b/winsup/cygwin/exceptions.cc @@ -20,12 +20,9 @@ details. */ #include "cygtls.h" #include "sigproc.h" #include "cygerrno.h" -#define NEED_VFORK -#include "perthread.h" #include "shared_info.h" #include "perprocess.h" #include "security.h" -#include "cygthread.h" #define CALL_HANDLER_RETRY 20 @@ -159,7 +156,7 @@ open_stackdumpfile () CREATE_ALWAYS, 0, 0); if (h != INVALID_HANDLE_VALUE) { - if (!myself->ppid_handle) + if (!myself->cygstarted) system_printf ("Dumping stack trace to %s", corefile); else debug_printf ("Dumping stack trace to %s", corefile); @@ -514,7 +511,7 @@ handle_exceptions (EXCEPTION_RECORD *e0, void *frame, CONTEXT *in0, void *) || (void *) global_sigs[si.si_signo].sa_handler == (void *) SIG_ERR) { /* Print the exception to the console */ - if (!myself->ppid_handle) + if (!myself->cygstarted) for (int i = 0; status_info[i].name; i++) if (status_info[i].code == e.ExceptionCode) { @@ -596,31 +593,15 @@ sig_handle_tty_stop (int sig) _my_tls.incyg = 1; /* Silently ignore attempts to suspend if there is no accommodating cygwin parent to deal with this behavior. */ - if (!myself->ppid_handle) + if (!myself->cygstarted) { myself->process_state &= ~PID_STOPPED; return; } myself->stopsig = sig; - /* See if we have a living parent. If so, send it a special signal. - It will figure out exactly which pid has stopped by scanning - its list of subprocesses. */ - if (my_parent_is_alive ()) - { - pinfo parent (myself->ppid); - if (NOTSTATE (parent, PID_NOCLDSTOP)) - { - siginfo_t si; - si.si_signo = SIGCHLD; - si.si_code = SI_KERNEL; - si.si_sigval.sival_int = CLD_STOPPED; - si.si_errno = si.si_pid = si.si_uid = si.si_errno = 0; - sig_send (parent, si); - } - } - sigproc_printf ("process %d stopped by signal %d, myself->ppid_handle %p", - myself->pid, sig, myself->ppid_handle); + myself.alert_parent (sig); + sigproc_printf ("process %d stopped by signal %d", myself->pid, sig); HANDLE w4[2]; w4[0] = sigCONT; w4[1] = signal_arrived; @@ -629,6 +610,7 @@ sig_handle_tty_stop (int sig) case WAIT_OBJECT_0: case WAIT_OBJECT_0 + 1: reset_signal_arrived (); + myself.alert_parent (SIGCONT); break; default: api_fatal ("WaitSingleObject failed, %E"); @@ -807,7 +789,7 @@ ctrl_c_handler (DWORD type) if (!cygwin_finished_initializing) { - if (myself->ppid_handle) /* Was this process created by a cygwin process? */ + if (myself->cygstarted) /* Was this process created by a cygwin process? */ return TRUE; /* Yes. Let the parent eventually handle CTRL-C issues. */ debug_printf ("exiting with status %p", STATUS_CONTROL_C_EXIT); ExitProcess (STATUS_CONTROL_C_EXIT); @@ -982,7 +964,7 @@ sigpacket::process () bool special_case; bool insigwait_mask; insigwait_mask = masked = false; - if (special_case = (VFORKPID || ISSTATE (myself, PID_STOPPED))) + if (special_case = (/*VFORKPID || */ISSTATE (myself, PID_STOPPED))) /* nothing to do */; else if (tls && sigismember (&tls->sigwait_mask, si.si_signo)) insigwait_mask = true; @@ -1097,7 +1079,6 @@ static void signal_exit (int rc) { EnterCriticalSection (&exit_lock); - rc = EXIT_SIGNAL | (rc << 8); if (exit_already++) myself->exit (rc); diff --git a/winsup/cygwin/external.cc b/winsup/cygwin/external.cc index c0cad36..56ef0c6 100644 --- a/winsup/cygwin/external.cc +++ b/winsup/cygwin/external.cc @@ -25,7 +25,6 @@ details. */ #include "cygheap.h" #include "wincap.h" #include "heap.h" -#include "cygthread.h" #include "pwdgrp.h" #include "cygtls.h" @@ -72,7 +71,6 @@ fillout_pinfo (pid_t pid, int winpid) ep.ctty = p->ctty; ep.pid = p->pid; ep.ppid = p->ppid; - ep.hProcess = p->hProcess; ep.dwProcessId = p->dwProcessId; ep.uid = p->uid; ep.gid = p->gid; diff --git a/winsup/cygwin/fhandler_console.cc b/winsup/cygwin/fhandler_console.cc index 81f495f..76b7911 100644 --- a/winsup/cygwin/fhandler_console.cc +++ b/winsup/cygwin/fhandler_console.cc @@ -28,7 +28,6 @@ details. */ #include "sigproc.h" #include "pinfo.h" #include "shared_info.h" -#include "cygthread.h" #include "cygtls.h" #define CONVERT_LIMIT 16384 diff --git a/winsup/cygwin/fhandler_tty.cc b/winsup/cygwin/fhandler_tty.cc index c64aac7..642f5ca 100644 --- a/winsup/cygwin/fhandler_tty.cc +++ b/winsup/cygwin/fhandler_tty.cc @@ -771,7 +771,10 @@ fhandler_tty_slave::read (void *ptr, size_t& len) rc = WaitForMultipleObjects (2, w4, FALSE, waiter); if (rc == WAIT_TIMEOUT) - break; + { + termios_printf ("wait timed out, waiter %u", waiter); + break; + } if (rc == WAIT_FAILED) { diff --git a/winsup/cygwin/fork.cc b/winsup/cygwin/fork.cc index 187fcdc..1dc1e7b 100644 --- a/winsup/cygwin/fork.cc +++ b/winsup/cygwin/fork.cc @@ -22,8 +22,7 @@ details. */ #include "pinfo.h" #include "cygheap.h" #include "child_info.h" -#define NEED_VFORK -#include "perthread.h" +#include "cygtls.h" #include "perprocess.h" #include "dll_init.h" #include "sync.h" @@ -42,17 +41,6 @@ details. */ #define dll_bss_start &_bss_start__ #define dll_bss_end &_bss_end__ -void -per_thread::set (void *s) -{ - if (s == PER_THREAD_FORK_CLEAR) - { - tls = TlsAlloc (); - s = NULL; - } - TlsSetValue (get_tls (), s); -} - static void stack_base (child_info_fork &ch) { @@ -296,7 +284,6 @@ fork_child (HANDLE& hParent, dll *&first_dll, bool& load_dlls) (void) ForceCloseHandle1 (fork_info->subproc_ready, subproc_ready); (void) ForceCloseHandle1 (fork_info->forker_finished, forker_finished); - pinfo_fixup_after_fork (); _my_tls.fixup_after_fork (); sigproc_init (); @@ -305,13 +292,6 @@ fork_child (HANDLE& hParent, dll *&first_dll, bool& load_dlls) api_fatal ("recreate_shm areas after fork failed"); #endif - /* Set thread local stuff to zero. Under Windows 95/98 this is sometimes - non-zero, for some reason. - FIXME: There is a memory leak here after a fork. */ - for (per_thread **t = threadstuff; *t; t++) - if ((*t)->clear_on_fork ()) - (*t)->set (); - pthread::atforkchild (); fixup_timers_after_fork (); cygbench ("fork-child"); @@ -356,8 +336,6 @@ fork_parent (HANDLE& hParent, dll *&first_dll, pthread::atforkprepare (); - subproc_init (); - int c_flags = GetPriorityClass (hMainProc) /*| CREATE_NEW_PROCESS_GROUP*/; STARTUPINFO si = {0, NULL, NULL, NULL, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, NULL, NULL, NULL, NULL}; @@ -384,7 +362,7 @@ fork_parent (HANDLE& hParent, dll *&first_dll, /* Create an inheritable handle to pass to the child process. This will allow the child to duplicate handles from the parent to itself. */ hParent = NULL; - if (!DuplicateHandle (hMainProc, hMainProc, hMainProc, &hParent, 0, 1, + if (!DuplicateHandle (hMainProc, hMainProc, hMainProc, &hParent, 0, TRUE, DUPLICATE_SAME_ACCESS)) { system_printf ("couldn't create handle to myself for child, %E"); @@ -501,8 +479,8 @@ fork_parent (HANDLE& hParent, dll *&first_dll, ProtectHandle1 (pi.hProcess, childhProc); /* Fill in fields in the child's process table entry. */ - forked->hProcess = pi.hProcess; forked->dwProcessId = pi.dwProcessId; + forked.hProcess = pi.hProcess; /* Hopefully, this will succeed. The alternative to doing things this way is to reserve space prior to calling CreateProcess and then fill diff --git a/winsup/cygwin/include/sys/cygwin.h b/winsup/cygwin/include/sys/cygwin.h index 2b42462..b8c9973 100644 --- a/winsup/cygwin/include/sys/cygwin.h +++ b/winsup/cygwin/include/sys/cygwin.h @@ -232,7 +232,7 @@ struct external_pinfo { pid_t pid; pid_t ppid; - HANDLE hProcess; + DWORD exitcode; DWORD dwProcessId, dwSpawnedProcessId; __uid16_t uid; __gid16_t gid; diff --git a/winsup/cygwin/include/sys/wait.h b/winsup/cygwin/include/sys/wait.h index 9dd8bf7..d070838 100644 --- a/winsup/cygwin/include/sys/wait.h +++ b/winsup/cygwin/include/sys/wait.h @@ -1,6 +1,6 @@ /* sys/wait.h - Copyright 1997, 1998, 2001 Red Hat, Inc. + Copyright 1997, 1998, 2001, 2002, 2003, 2004 Red Hat, Inc. This file is part of Cygwin. @@ -36,6 +36,7 @@ extern "C" { #define WEXITSTATUS(w) (((w) >> 8) & 0xff) #define WTERMSIG(w) ((w) & 0x7f) #define WSTOPSIG WEXITSTATUS +#define WCOREDUMP(w) (WIFSIGNALED(w) && (w & 0x80)) pid_t wait (int *); pid_t waitpid (pid_t, int *, int); diff --git a/winsup/cygwin/init.cc b/winsup/cygwin/init.cc index cc86870..7ba0dc3 100644 --- a/winsup/cygwin/init.cc +++ b/winsup/cygwin/init.cc @@ -12,7 +12,6 @@ details. */ #include <stdlib.h> #include "thread.h" #include "perprocess.h" -#include "cygthread.h" #include "cygtls.h" int NO_COPY dynamically_loaded; diff --git a/winsup/cygwin/perthread.h b/winsup/cygwin/perthread.h deleted file mode 100644 index e10a624..0000000 --- a/winsup/cygwin/perthread.h +++ /dev/null @@ -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[]; diff --git a/winsup/cygwin/pinfo.cc b/winsup/cygwin/pinfo.cc index 829db2a..8a42daa 100644 --- a/winsup/cygwin/pinfo.cc +++ b/winsup/cygwin/pinfo.cc @@ -24,9 +24,9 @@ details. */ #include "perprocess.h" #include "environ.h" #include <assert.h> +#include <sys/wait.h> #include <ntdef.h> #include "ntdll.h" -#include "cygthread.h" #include "shared_info.h" #include "cygheap.h" #include "fhandler.h" @@ -37,23 +37,6 @@ static char NO_COPY pinfo_dummy[sizeof (_pinfo)] = {0}; pinfo NO_COPY myself ((_pinfo *)&pinfo_dummy); // Avoid myself != NULL checks -HANDLE hexec_proc; - -void __stdcall -pinfo_fixup_after_fork () -{ - if (hexec_proc) - CloseHandle (hexec_proc); - /* Keeps the cygpid from being reused. No rights required */ - if (!DuplicateHandle (hMainProc, hMainProc, hMainProc, &hexec_proc, 0, - TRUE, 0)) - { - system_printf ("couldn't save current process handle %p, %E", hMainProc); - hexec_proc = NULL; - } - VerifyHandle (hexec_proc); -} - /* Initialize the process table. This is done once when the dll is first loaded. */ @@ -70,7 +53,30 @@ set_myself (HANDLE h) if (!strace.active) strace.hello (); debug_printf ("myself->dwProcessId %u", myself->dwProcessId); - InitializeCriticalSection (&myself->lock); + InitializeCriticalSection (&myself.lock); + myself->dwProcessId = GetCurrentProcessId (); + if (h) + { + /* here if execed */ + static pinfo NO_COPY myself_identity; + myself_identity.init (cygwin_pid (myself->dwProcessId), PID_EXECED); + } + else if (myself->ppid) + { + /* here if forked/spawned */ + pinfo parent (myself->ppid); + /* We've inherited the parent's wr_proc_pipe. We don't need it, + so close it. This could cause problems for the spawn case since there + is no guarantee that a parent will still be around by the time we get + here. If so, we would have a handle leak. FIXME? */ + if (parent && parent->wr_proc_pipe) + CloseHandle (parent->wr_proc_pipe); + if (cygheap->pid_handle) + { + ForceCloseHandle (cygheap->pid_handle); + cygheap->pid_handle = NULL; + } + } return; } @@ -107,17 +113,27 @@ _pinfo::exit (UINT n, bool norecord) exit_state = ES_FINAL; cygthread::terminate (); if (norecord) - sigproc_terminate (); + sigproc_terminate (); /* Just terminate signal and process stuff */ + else + exitcode = n; /* We're really exiting. Record the UNIX exit code. */ + if (this) { - if (!norecord) - process_state = PID_EXITED; - /* FIXME: There is a potential race between an execed process and its parent here. I hated to add a mutex just for this, though. */ struct rusage r; fill_rusage (&r, hMainProc); add_rusage (&rusage_self, &r); + + if (!norecord) + { + process_state = PID_EXITED; + /* We could just let this happen automatically when the process + exits but this should gain us a microsecond or so by notifying + the parent early. */ + if (wr_proc_pipe) + CloseHandle (wr_proc_pipe); + } } sigproc_printf ("Calling ExitProcess %d", n); @@ -259,6 +275,7 @@ pinfo::init (pid_t n, DWORD flag, HANDLE in_h) procinfo->process_state |= PID_IN_USE | PID_EXECED; procinfo->pid = myself->pid; } + break; } destroy = 1; @@ -505,7 +522,7 @@ _pinfo::commune_send (DWORD code, ...) __seterrno (); goto err; } - EnterCriticalSection (&myself->lock); + EnterCriticalSection (&myself.lock); myself->tothem = tome; myself->fromthem = fromme; myself->hello_pid = pid; @@ -609,7 +626,7 @@ err: out: myself->hello_pid = 0; - LeaveCriticalSection (&myself->lock); + LeaveCriticalSection (&myself.lock); return res; } @@ -642,6 +659,196 @@ _pinfo::cmdline (size_t& n) return s; } +/* This is the workhorse which waits for the write end of the pipe + created during new process creation. If the pipe is closed, it is + assumed that the cygwin pid has exited. Otherwise, various "signals" + can be sent to the parent to inform the parent to perform a certain + action. + + This code was originally written to eliminate the need for "reparenting" + but, unfortunately, reparenting is still needed in order to get the + exit code of an execed windows process. Otherwise, the exit code of + a cygwin process comes from the exitcode field in _pinfo. */ +static DWORD WINAPI +proc_waiter (void *arg) +{ + extern HANDLE hExeced; + pinfo& vchild = *(pinfo *) arg; + + siginfo_t si; + si.si_signo = SIGCHLD; + si.si_code = SI_KERNEL; + si.si_pid = vchild->pid; + si.si_errno = 0; +#if 0 // FIXME: This is tricky to get right + si.si_utime = pchildren[rc]->rusage_self.ru_utime; + si.si_stime = pchildren[rc].rusage_self.ru_stime; +#else + si.si_utime = 0; + si.si_stime = 0; +#endif + pid_t pid = vchild->pid; + + for (;;) + { + DWORD nb; + char buf = '\0'; + if (!ReadFile (vchild.rd_proc_pipe, &buf, 1, &nb, NULL) + && GetLastError () != ERROR_BROKEN_PIPE) + { + system_printf ("error on read of child wait pipe %p, %E", vchild.rd_proc_pipe); + break; + } + + si.si_uid = vchild->uid; + + switch (buf) + { + case 0: + /* Child exited. Do some cleanup and signal myself. */ + CloseHandle (vchild.rd_proc_pipe); + vchild.rd_proc_pipe = NULL; + + if (vchild->process_state != PID_EXITED && vchild.hProcess) + { + DWORD exit_code; + if (GetExitCodeProcess (vchild.hProcess, &exit_code)) + vchild->exitcode = (exit_code & 0xff) << 8; + } + if (WIFEXITED (vchild->exitcode)) + si.si_sigval.sival_int = CLD_EXITED; + else if (WCOREDUMP (vchild->exitcode)) + si.si_sigval.sival_int = CLD_DUMPED; + else + si.si_sigval.sival_int = CLD_KILLED; + si.si_status = vchild->exitcode; + vchild->process_state = PID_ZOMBIE; + break; + case SIGTTIN: + case SIGTTOU: + case SIGTSTP: + case SIGSTOP: + /* Child stopped. Signal myself. */ + si.si_sigval.sival_int = CLD_STOPPED; + break; + case SIGCONT: + continue; + case __SIGREPARENT: /* sigh */ + /* spawn_guts has signalled us that it has just started a new + subprocess which will take over this cygwin pid. */ + + /* We need to keep a handle to the original windows process which + represents the cygwin process around to make sure that the + windows pid is not reused before we are through with it. + So, detect the first time that a subprocess calls exec + and save the current hprocess in the pid_handle field. + On subsequent execs just close the handle. */ + if (!vchild.hProcess) + /* something went wrong. oh well. */; + else if (vchild.pid_handle) + ForceCloseHandle1 (vchild.hProcess, childhProc); + else + vchild.pid_handle = vchild.hProcess; + vchild.hProcess = OpenProcess (PROCESS_QUERY_INFORMATION, FALSE, + vchild->dwProcessId); + vchild->cygstarted++; + if (vchild.hProcess) + ProtectHandle1 (vchild.hProcess, childhProc); + continue; + default: + system_printf ("unknown value %d on proc pipe", buf); + continue; + } + + /* Special case: If the "child process" that died is us, then we're + execing. Just call proc_subproc directly and then exit this loop. + We're done here. */ + if (hExeced && vchild->pid == myself->pid) + { + /* execing. no signals available now. */ + proc_subproc (PROC_CLEARWAIT, 0); + break; + } + + /* Send a SIGCHLD to myself. We do this here, rather than in proc_subproc + to avoid the proc_subproc lock since the signal thread will eventually + be calling proc_subproc and could unnecessarily block. */ + sig_send (myself_nowait, si); + + /* If we're just stopped or got a continue signal, keep looping. + Otherwise, return this thread to the pool. */ + if (buf != '\0') + sigproc_printf ("looping"); + else + break; + } + + sigproc_printf ("exiting wait thread for pid %d", pid); + _my_tls._ctinfo->release (); /* return the cygthread to the cygthread pool */ + return 0; +} + +/* function to set up the process pipe and kick off proc_waiter */ +int +pinfo::wait () +{ + HANDLE out; + /* FIXME: execed processes should be able to wait for pids that were started + by the process which execed them. */ + if (!CreatePipe (&rd_proc_pipe, &out, &sec_none_nih, 16)) + { + system_printf ("Couldn't create pipe tracker for pid %d, %E", + (*this)->pid); + return 0; + } + /* Duplicate the write end of the pipe into the subprocess. Make it inheritable + so that all of the execed children get it. */ + if (!DuplicateHandle (hMainProc, out, hProcess, &((*this)->wr_proc_pipe), 0, + TRUE, DUPLICATE_SAME_ACCESS)) + { + system_printf ("Couldn't duplicate pipe topid %d(%p), %E", (*this)->pid, + hProcess); + return 0; + } + CloseHandle (out); /* Don't need this end in this proces */ + + preserve (); /* Preserve the shared memory associated with the pinfo */ + + /* Fire up a new thread to track the subprocess */ + cygthread *h = new cygthread (proc_waiter, this, "sig"); + if (!h) + sigproc_printf ("tracking thread creation failed for pid %d", (*this)->pid); + else + { + h->zap_h (); + sigproc_printf ("created tracking thread for pid %d, winpid %p, rd_pipe %p", + (*this)->pid, (*this)->dwProcessId, rd_proc_pipe); + } + + return 1; +} + +/* function to send a "signal" to the parent when something interesting happens + in the child. */ +void +pinfo::alert_parent (char sig) +{ + DWORD nb; + /* Send something to our parent. If the parent has gone away, + close the pipe. */ + if (myself->wr_proc_pipe + && WriteFile (myself->wr_proc_pipe, &sig, 1, &nb, NULL)) + /* all is well */; + else if (GetLastError () != ERROR_BROKEN_PIPE) + debug_printf ("sending %d notification to parent failed, %E", sig); + else + { + HANDLE closeit = myself->wr_proc_pipe; + myself->wr_proc_pipe = NULL; + CloseHandle (closeit); + } +} + void pinfo::release () { diff --git a/winsup/cygwin/pinfo.h b/winsup/cygwin/pinfo.h index aa1fb8c..b062934 100644 --- a/winsup/cygwin/pinfo.h +++ b/winsup/cygwin/pinfo.h @@ -36,19 +36,12 @@ public: constants below. */ DWORD process_state; - /* If hProcess is set, it's because it came from a - CreateProcess call. This means it's process relative - to the thing which created the process. That's ok because - we only use this handle from the parent. */ - HANDLE hProcess; - -#define PINFO_REDIR_SIZE ((char *) &myself.procinfo->hProcess - (char *) myself.procinfo) + DWORD exitcode; /* set when process exits */ - /* Handle associated with initial Windows pid which started it all. */ - HANDLE pid_handle; +#define PINFO_REDIR_SIZE ((char *) &myself.procinfo->exitcode - (char *) myself.procinfo) - /* Handle to the logical parent of this pid. */ - HANDLE ppid_handle; + /* > 0 if started by a cygwin process */ + DWORD cygstarted; /* Parent process id. */ pid_t ppid; @@ -120,7 +113,9 @@ public: HANDLE sendsig; private: sigset_t sig_mask; - CRITICAL_SECTION lock; +public: + HANDLE wr_proc_pipe; + friend class pinfo; }; class pinfo @@ -129,12 +124,18 @@ class pinfo _pinfo *procinfo; bool destroy; public: + HANDLE rd_proc_pipe; + HANDLE hProcess; + CRITICAL_SECTION lock; + /* Handle associated with initial Windows pid which started it all. */ + HANDLE pid_handle; void init (pid_t, DWORD, HANDLE = NULL) __attribute__ ((regparm(3))); pinfo () {} - pinfo (_pinfo *x): procinfo (x) {} - pinfo (pid_t n) {init (n, 0);} - pinfo (pid_t n, DWORD flag) {init (n, flag);} + pinfo (_pinfo *x): procinfo (x), hProcess (NULL), pid_handle (NULL) {} + pinfo (pid_t n) : rd_proc_pipe (NULL), hProcess (NULL), pid_handle (NULL) {init (n, 0);} + pinfo (pid_t n, DWORD flag) : rd_proc_pipe (NULL), hProcess (NULL), pid_handle (NULL) {init (n, flag);} void release (); + int wait () __attribute__ ((regparm (1))); ~pinfo () { if (destroy && procinfo) @@ -151,6 +152,8 @@ public: _pinfo *operator * () const {return procinfo;} operator _pinfo * () const {return procinfo;} // operator bool () const {return (int) h;} + void preserve () { destroy = false; } + void alert_parent (char); #ifndef _SIGPROC_H int remember () {system_printf ("remember is not here"); return 0;} #else @@ -210,9 +213,6 @@ extern pinfo myself; #define _P_VFORK 0 #define _P_SYSTEM 512 -extern void __stdcall pinfo_fixup_after_fork (); -extern HANDLE hexec_proc; - /* For mmaps across fork(). */ int __stdcall fixup_mmaps_after_fork (HANDLE parent); /* for shm areas across fork (). */ diff --git a/winsup/cygwin/select.cc b/winsup/cygwin/select.cc index a0dc131..c943b2a 100644 --- a/winsup/cygwin/select.cc +++ b/winsup/cygwin/select.cc @@ -36,9 +36,7 @@ details. */ #include "dtable.h" #include "cygheap.h" #include "sigproc.h" -#include "perthread.h" #include "tty.h" -#include "cygthread.h" #include "ntdll.h" #include "cygtls.h" #include <asm/byteorder.h> @@ -209,7 +207,7 @@ select_stuff::test_and_set (int i, fd_set *readfds, fd_set *writefds, if (s->read_ready || s->write_ready || s->except_ready) always_ready = true; - if (s->windows_handle || s->windows_handle || s->windows_handle) + if (s->windows_handle) windows_used = true; s->next = start.next; diff --git a/winsup/cygwin/signal.cc b/winsup/cygwin/signal.cc index bd75dff..f57e0d0 100644 --- a/winsup/cygwin/signal.cc +++ b/winsup/cygwin/signal.cc @@ -342,7 +342,7 @@ abort (void) raise (SIGABRT); (void) _my_tls.call_signal_handler (); /* Call any signal handler */ - do_exit (1); /* signal handler didn't exit. Goodbye. */ + do_exit (SIGABRT); /* signal handler didn't exit. Goodbye. */ } extern "C" int diff --git a/winsup/cygwin/sigproc.cc b/winsup/cygwin/sigproc.cc index 416761e..844e80a 100644 --- a/winsup/cygwin/sigproc.cc +++ b/winsup/cygwin/sigproc.cc @@ -28,10 +28,8 @@ details. */ #include "cygheap.h" #include "child_info_magic.h" #include "shared_info.h" -#include "cygthread.h" #include "cygtls.h" #include "sigproc.h" -#include "perthread.h" #include "exceptions.h" /* @@ -42,11 +40,9 @@ details. */ #define PSIZE 63 // Number of processes -#define wake_wait_subproc() SetEvent (events[0]) - #define no_signals_available() (!hwait_sig || (myself->sendsig == INVALID_HANDLE_VALUE) || exit_state) -#define NZOMBIES 256 +#define NPROCS 256 /* * Global variables @@ -64,30 +60,15 @@ HANDLE NO_COPY signal_arrived; // Event signaled when a signal has #define Static static NO_COPY -/* How long to wait for message/signals. Normally this is infinite. - On termination, however, these are set to zero as a flag to exit. */ - -Static DWORD proc_loop_wait = 1000; // Wait for subprocesses to exit - HANDLE NO_COPY sigCONT; // Used to "STOP" a process Static cygthread *hwait_sig; // Handle of wait_sig thread -Static cygthread *hwait_subproc; // Handle of sig_subproc thread Static HANDLE wait_sig_inited; // Control synchronization of // message queue startup -/* Used by WaitForMultipleObjects. These are handles to child processes. - */ -Static HANDLE events[PSIZE + 1]; // All my children's handles++ -#define hchildren (events + 1) // Where the children handles begin -Static int nchildren; // Number of active children -Static char cpchildren[PSIZE * sizeof (pinfo)]; // All my children info -Static int nzombies; // Number of deceased children -Static char czombies[(NZOMBIES + 1) * sizeof (pinfo)]; // All my deceased children info - -#define pchildren ((pinfo *) cpchildren) -#define zombies ((pinfo *) czombies) - +Static int nprocs; // Number of deceased children +Static char cprocs[(NPROCS + 1) * sizeof (pinfo)]; // All my deceased children info +#define procs ((pinfo *) cprocs) Static waitq waitq_head = {0, 0, 0, 0, 0, 0, 0};// Start of queue for wait'ing threads muto NO_COPY *sync_proc_subproc = NULL; // Control access to subproc stuff @@ -97,9 +78,8 @@ DWORD NO_COPY sigtid = 0; // ID of the signal thread /* Function declarations */ static int __stdcall checkstate (waitq *) __attribute__ ((regparm (1))); static __inline__ bool get_proc_lock (DWORD, DWORD); -static void __stdcall remove_zombie (int); -static int __stdcall stopped_or_terminated (waitq *, _pinfo *); -static DWORD WINAPI wait_subproc (VOID *); +static bool __stdcall remove_proc (int); +static bool __stdcall stopped_or_terminated (waitq *, _pinfo *); static DWORD WINAPI wait_sig (VOID *arg); /* wait_sig bookkeeping */ @@ -152,33 +132,13 @@ bool __stdcall my_parent_is_alive () { bool res; - if (!myself->ppid_handle) + if (myself->cygstarted) + res = pid_exists (myself->ppid); + else { - debug_printf ("No myself->ppid_handle"); + debug_printf ("Not started by cygwin app"); res = false; } - else - for (int i = 0; i < 2; i++) - switch (res = WaitForSingleObject (myself->ppid_handle, 0)) - { - case WAIT_OBJECT_0: - debug_printf ("parent dead."); - res = false; - goto out; - case WAIT_TIMEOUT: - debug_printf ("parent still alive"); - res = true; - goto out; - case WAIT_FAILED: - DWORD werr = GetLastError (); - if (werr == ERROR_INVALID_HANDLE && i == 0) - continue; - system_printf ("WFSO for myself->ppid_handle(%p) failed, error %d", - myself->ppid_handle, werr); - res = false; - goto out; - } -out: return res; } @@ -193,7 +153,7 @@ wait_for_sigthread () } /* Get the sync_proc_subproc muto to control access to - * children, zombie arrays. + * children, proc arrays. * Attempt to handle case where process is exiting as we try to grab * the mutex. */ @@ -260,16 +220,11 @@ proc_exists (_pinfo *p) /* Return 1 if this is one of our children, zero otherwise. FIXME: This really should be integrated with the rest of the proc_subproc testing. Scanning these lists twice is inefficient. */ -int __stdcall +bool __stdcall mychild (int pid) { - for (int i = 0; i < nchildren; i++) - if (pchildren[i]->pid == pid) - return 1; - for (int i = 0; i < nzombies; i++) - if (zombies[i]->pid == pid) - return 1; - return 0; + pinfo p (pid); + return p && p->ppid == myself->pid; } /* Handle all subprocess requests @@ -283,7 +238,6 @@ proc_subproc (DWORD what, DWORD val) _pinfo *child; int clearing; waitq *w; - int thiszombie; #define wval ((waitq *) val) @@ -301,84 +255,32 @@ proc_subproc (DWORD what, DWORD val) * (usually called from the main thread) */ case PROC_ADDCHILD: - if (nchildren >= PSIZE - 1) + /* Filled up process table? */ + if (nprocs >= NPROCS) { + sigproc_printf ("proc table overflow: hit %d processes, pid %d\n", + nprocs, vchild->pid); rc = 0; + set_errno (EMFILE); // FIXMENOW - what's the right errno? break; } - pchildren[nchildren] = vchild; - hchildren[nchildren] = vchild->hProcess; - if (!DuplicateHandle (hMainProc, vchild->hProcess, hMainProc, &vchild->pid_handle, - 0, 0, DUPLICATE_SAME_ACCESS)) - system_printf ("Couldn't duplicate child handle for pid %d, %E", vchild->pid); - ProtectHandle1 (vchild->pid_handle, pid_handle); - - if (!DuplicateHandle (hMainProc, hMainProc, vchild->hProcess, &vchild->ppid_handle, - SYNCHRONIZE | PROCESS_DUP_HANDLE, TRUE, 0)) - system_printf ("Couldn't duplicate my handle<%p> for pid %d, %E", hMainProc, vchild->pid); + vchild->ppid = myself->pid; vchild->uid = myself->uid; vchild->gid = myself->gid; vchild->pgid = myself->pgid; vchild->sid = myself->sid; vchild->ctty = myself->ctty; + vchild->cygstarted = true; vchild->process_state |= PID_INITIALIZING | (myself->process_state & PID_USETTY); - - sigproc_printf ("added pid %d to wait list, slot %d, winpid %p, handle %p", - vchild->pid, nchildren, vchild->dwProcessId, - vchild->hProcess); - nchildren++; - - wake_wait_subproc (); - break; - - /* A child process had terminated. - Possibly this is just due to an exec(). Cygwin implements an exec() - as a "handoff" from one windows process to another. If child->hProcess - is different from what is recorded in hchildren, then this is an exec(). - Otherwise this is a normal child termination event. - (called from wait_subproc thread) */ - case PROC_CHILDTERMINATED: - if (hchildren[val] != pchildren[val]->hProcess) - { - sigproc_printf ("pid %d[%d], reparented old hProcess %p, new %p", - pchildren[val]->pid, val, hchildren[val], pchildren[val]->hProcess); - HANDLE h = hchildren[val]; - hchildren[val] = pchildren[val]->hProcess; /* Filled out by child */ - ForceCloseHandle1 (h, childhProc); - ProtectHandle1 (pchildren[val]->hProcess, childhProc); - rc = 0; - goto out; // This was an exec() - } - - sigproc_printf ("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) + procs[nprocs] = vchild; + rc = procs[nprocs].wait (); + if (rc) { - sigproc_printf ("zombie table overflow %d", thiszombie); - remove_zombie (thiszombie); + sigproc_printf ("added pid %d to proc table, slot %d", vchild->pid, + nprocs); + nprocs++; } - - /* Don't scan the wait queue yet. Caller will send SIGCHLD to this process. - This will cause an eventual scan of waiters. */ break; /* Handle a wait4() operation. Allocates an event for the calling @@ -401,8 +303,8 @@ proc_subproc (DWORD what, DWORD val) */ if ((wval->ev = wval->thread_ev) == NULL) { - wval->ev = wval->thread_ev = CreateEvent (&sec_none_nih, TRUE, - FALSE, NULL); + wval->ev = wval->thread_ev = CreateEvent (&sec_none_nih, TRUE, FALSE, + NULL); ProtectHandle1 (wval->ev, wq_ev); } @@ -459,9 +361,8 @@ proc_subproc (DWORD what, DWORD val) } if (global_sigs[SIGCHLD].sa_handler == (void *) SIG_IGN) - while (nzombies) - remove_zombie (0); - break; + for (int i = 0; i < nprocs; i += remove_proc (i)) + continue; } out: @@ -492,54 +393,29 @@ _cygtls::remove_wq (DWORD wait) * Called on process exit. * Also called by spawn_guts to disassociate any subprocesses from this * process. Subprocesses will then know to clean up after themselves and - * will not become zombies. + * will not become procs. */ void __stdcall proc_terminate (void) { - sigproc_printf ("nchildren %d, nzombies %d", nchildren, nzombies); + sigproc_printf ("nprocs %d", nprocs); /* Signal processing is assumed to be blocked in this routine. */ - if (hwait_subproc) + if (nprocs) { - proc_loop_wait = 0; // Tell wait_subproc thread to exit sync_proc_subproc->acquire (WPSP); - wake_wait_subproc (); // Wake wait_subproc loop - hwait_subproc = NULL; (void) proc_subproc (PROC_CLEARWAIT, 1); - /* Clean out zombie processes from the pid list. */ + /* Clean out proc processes from the pid list. */ int i; - for (i = 0; i < nzombies; i++) - { - if (zombies[i]->hProcess) - { - ForceCloseHandle1 (zombies[i]->hProcess, childhProc); - ForceCloseHandle1 (zombies[i]->pid_handle, pid_handle); - } - zombies[i]->ppid = 1; - zombies[i]->process_state = PID_EXITED; /* CGF FIXME - still needed? */ - zombies[i].release (); // FIXME: this breaks older gccs for some reason - } - - /* Disassociate my subprocesses */ - for (i = 0; i < nchildren; i++) + for (i = 0; i < nprocs; 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 (); + procs[i]->ppid = 1; + if (!proc_exists (procs[i])) + procs[i]->process_state = PID_EXITED; /* CGF FIXME - still needed? */ + procs[i].release (); } - nchildren = nzombies = 0; + nprocs = 0; sync_proc_subproc->release (); } sigproc_printf ("leaving"); @@ -610,7 +486,7 @@ sigproc_init () ProtectHandle (wait_sig_inited); /* sync_proc_subproc is used by proc_subproc. It serialises - * access to the children and zombie arrays. + * access to the children and proc arrays. */ new_muto (sync_proc_subproc); @@ -648,7 +524,7 @@ sigproc_terminate (void) CloseHandle (sendsig); } } - proc_terminate (); // Terminate process handling thread + proc_terminate (); // clean up process stuff return; } @@ -833,25 +709,6 @@ out: return rc; } -/* Initialize the wait_subproc thread. - * Called from fork() or spawn() to initialize the handling of subprocesses. - */ -void __stdcall -subproc_init (void) -{ - if (hwait_subproc) - return; - - /* A "wakeup" handle which can be toggled to make wait_subproc reexamine - * the hchildren array. - */ - events[0] = CreateEvent (&sec_none_nih, FALSE, FALSE, NULL); - hwait_subproc = new cygthread (wait_subproc, NULL, "proc"); - hwait_subproc->zap_h (); - ProtectHandle (events[0]); - sigproc_printf ("started wait_subproc thread"); -} - /* Initialize some of the memory block passed to child processes by fork/spawn/exec. */ @@ -864,7 +721,6 @@ init_child_info (DWORD chtype, child_info *ch, HANDLE subproc_ready) ch->magic = CHILD_INFO_MAGIC; ch->type = chtype; ch->subproc_ready = subproc_ready; - ch->pppid_handle = myself->ppid_handle; ch->fhandler_union_cb = sizeof (fhandler_union); ch->user_h = cygwin_user_h; } @@ -877,132 +733,107 @@ checkstate (waitq *parent_w) { int potential_match = 0; - sigproc_printf ("nchildren %d, nzombies %d", nchildren, nzombies); + sigproc_printf ("nprocs %d", nprocs); /* Check already dead processes first to see if they match the criteria - * given in w->next. - */ - for (int i = 0; i < nzombies; i++) - switch (stopped_or_terminated (parent_w, zombies[i])) + * given in w->next. */ + int res; + for (int i = 0; i < nprocs; i++) + if ((res = stopped_or_terminated (parent_w, procs[i]))) { - case -1: - potential_match = -1; - break; - case 1: - remove_zombie (i); + remove_proc (i); potential_match = 1; goto out; } - sigproc_printf ("checking alive children"); - - /* No dead terminated children matched. Check for stopped children. */ - for (int i = 0; i < nchildren; i++) - switch (stopped_or_terminated (parent_w, pchildren[i])) - { - case -1: - potential_match = -1; - break; - case 1: - potential_match = 1; - goto out; - } + sigproc_printf ("no matching terminated children found"); + potential_match = -!!nprocs; out: sigproc_printf ("returning %d", potential_match); return potential_match; } -/* Remove a zombie from zombies by swapping it with the last child in the list. - */ -static void __stdcall -remove_zombie (int ci) +/* Remove a proc from procs by swapping it with the last child in the list. + Also releases shared memory of exited processes. */ +static bool __stdcall +remove_proc (int ci) { - sigproc_printf ("removing %d, pid %d, nzombies %d", ci, zombies[ci]->pid, - nzombies); + if (proc_exists (procs[ci])) + return true; - if (zombies[ci]) + sigproc_printf ("removing procs[%d], pid %d, nprocs %d", ci, procs[ci]->pid, + nprocs); + if (procs[ci] != myself) { - ForceCloseHandle1 (zombies[ci]->hProcess, childhProc); - ForceCloseHandle1 (zombies[ci]->pid_handle, pid_handle); - zombies[ci].release (); + procs[ci].release (); + if (procs[ci].pid_handle) + ForceCloseHandle1 (procs[ci].pid_handle, childhProc); + if (procs[ci].hProcess) + ForceCloseHandle1 (procs[ci].hProcess, childhProc); } - - if (ci < --nzombies) - zombies[ci] = zombies[nzombies]; - - return; + if (ci < --nprocs) + procs[ci] = procs[nprocs]; + return 0; } /* Check status of child process vs. waitq member. - * - * parent_w is the pointer to the parent of the waitq member in question. - * child is the subprocess being considered. - * - * Returns - * 1 if stopped or terminated child matches parent_w->next criteria - * -1 if a non-stopped/terminated child matches parent_w->next criteria - * 0 if child does not match parent_w->next criteria - */ -static int __stdcall + + parent_w is the pointer to the parent of the waitq member in question. + child is the subprocess being considered. + + Returns non-zero if waiting thread released. */ +static bool __stdcall stopped_or_terminated (waitq *parent_w, _pinfo *child) { - int potential_match; + int might_match; waitq *w = parent_w->next; sigproc_printf ("considering pid %d", child->pid); if (w->pid == -1) - potential_match = 1; + might_match = 1; else if (w->pid == 0) - potential_match = child->pgid == myself->pgid; + might_match = child->pgid == myself->pgid; else if (w->pid < 0) - potential_match = child->pgid == -w->pid; + might_match = child->pgid == -w->pid; else - potential_match = (w->pid == child->pid); + might_match = (w->pid == child->pid); - if (!potential_match) + if (!might_match) return 0; - bool terminated; + int terminated; - if ((terminated = child->process_state == PID_ZOMBIE) || - ((w->options & WUNTRACED) && child->stopsig)) - { - parent_w->next = w->next; /* successful wait. remove from wait queue */ - w->pid = child->pid; + if (!((terminated = (child->process_state == PID_ZOMBIE)) || + ((w->options & WUNTRACED) && child->stopsig))) + return 0; - if (!terminated) - { - sigproc_printf ("stopped child"); - w->status = (child->stopsig << 8) | 0x7f; - child->stopsig = 0; - } - else /* Should only get here when child has been moved to the 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 ()" */ + parent_w->next = w->next; /* successful wait. remove from wait queue */ + w->pid = child->pid; - add_rusage (&myself->rusage_children, &child->rusage_children); - add_rusage (&myself->rusage_children, &child->rusage_self); + if (!terminated) + { + sigproc_printf ("stopped child"); + w->status = (child->stopsig << 8) | 0x7f; + child->stopsig = 0; + } + else /* Should only get here when child has been moved to the procs array */ + { + w->status = child->exitcode; - if (w->rusage) - { - add_rusage ((struct rusage *) w->rusage, &child->rusage_children); - add_rusage ((struct rusage *) w->rusage, &child->rusage_self); - } - } + add_rusage (&myself->rusage_children, &child->rusage_children); + add_rusage (&myself->rusage_children, &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; + if (w->rusage) + { + add_rusage ((struct rusage *) w->rusage, &child->rusage_children); + add_rusage ((struct rusage *) w->rusage, &child->rusage_self); + } } - return -potential_match; + if (!SetEvent (w->ev)) /* wake up wait4 () immediately */ + system_printf ("couldn't wake up wait event %p, %E", w->ev); + return true; } static void @@ -1078,27 +909,10 @@ wait_sig (VOID *self) signals. Prior to this, dwProcessId was set to the windows pid of of the original windows process which spawned us unless this was a "toplevel" process. */ - myself->dwProcessId = GetCurrentProcessId (); myself->process_state |= PID_ACTIVE; myself->process_state &= ~PID_INITIALIZING; sigproc_printf ("myself->dwProcessId %u", myself->dwProcessId); - /* If we've been execed, then there is still a stub left in the previous - windows process waiting to see if it's started a cygwin process or not. - Signalling subproc_ready indicates that we are a cygwin process. */ - if (child_proc_info && child_proc_info->type == PROC_EXEC) - { - debug_printf ("subproc_ready %p", child_proc_info->subproc_ready); - if (!SetEvent (child_proc_info->subproc_ready)) - system_printf ("SetEvent (subproc_ready) failed, %E"); - ForceCloseHandle1 (child_proc_info->subproc_ready, subproc_ready); - /* Initialize an "indirect" pid block so that if someone looks up this - process via its Windows PID it will be redirected to the appropriate - Cygwin PID shared memory block. */ - static pinfo NO_COPY myself_identity; - myself_identity.init (cygwin_pid (myself->dwProcessId), PID_EXECED); - } - SetEvent (wait_sig_inited); sigtid = GetCurrentThreadId (); @@ -1215,85 +1029,3 @@ wait_sig (VOID *self) sigproc_printf ("done"); ExitThread (0); } - -/* Wait for subprocesses to terminate. Executes in a separate thread. */ -static DWORD WINAPI -wait_subproc (VOID *) -{ - sigproc_printf ("starting"); - int errloop = 0; - - for (;;) - { - DWORD rc = WaitForMultipleObjects (nchildren + 1, events, FALSE, - proc_loop_wait); - if (!proc_loop_wait) - break; - if (rc == WAIT_TIMEOUT) - continue; - - if (rc == WAIT_FAILED) - { - /* It's ok to get an ERROR_INVALID_HANDLE since another thread may have - closed a handle in the children[] array. So, we try looping a couple - of times to stabilize. FIXME - this is not foolproof. Probably, this - thread should be responsible for closing the children. */ - if (!errloop++) - proc_subproc (PROC_NOTHING, 0); // Just synchronize and continue - if (errloop < 10) - continue; - - system_printf ("wait failed. nchildren %d, wait %d, %E", - nchildren, proc_loop_wait); - - for (int i = 0; i <= nchildren; i++) - if ((rc = WaitForSingleObject (events[i], 0)) == WAIT_OBJECT_0 || - rc == WAIT_TIMEOUT) - continue; - else if (i == 0) - system_printf ("nchildren %d, event[%d] %p, %E", nchildren, i, events[i]); - else - { - system_printf ("nchildren %d, event[%d] %p, pchildren[%d] %p, events[0] %p, %E", - nchildren, i, events[i], i - 1, (_pinfo *) pchildren[i - 1], events[0]); - system_printf ("pid %d, dwProcessId %u, hProcess %p, progname '%s'", - pchildren[i - 1]->pid, pchildren[i - 1]->dwProcessId, - pchildren[i - 1]->hProcess, pchildren[i - 1]->progname); - } - break; - } - - errloop = 0; - rc -= WAIT_OBJECT_0; - if (rc-- != 0) - { - siginfo_t si; - si.si_signo = SIGCHLD; - si.si_code = SI_KERNEL; - si.si_pid = pchildren[rc]->pid; - si.si_uid = pchildren[rc]->uid; - si.si_errno = 0; - GetExitCodeProcess (hchildren[rc], (DWORD *) &si.si_status); -#if 0 // FIXME: This is tricky to get right - si.si_utime = pchildren[rc]->rusage_self.ru_utime; - si.si_stime = pchildren[rc].rusage_self.ru_stime; -#else - si.si_utime = 0; - si.si_stime = 0; -#endif - rc = proc_subproc (PROC_CHILDTERMINATED, rc); - - /* Send a SIGCHLD to myself. We do this here, rather than in proc_subproc - to avoid the proc_subproc lock since the signal thread will eventually - be calling proc_subproc and could unnecessarily block. */ - if (rc) - sig_send (myself_nowait, si); - } - sigproc_printf ("looping"); - } - - ForceCloseHandle (events[0]); - events[0] = NULL; - sigproc_printf ("done"); - ExitThread (0); -} diff --git a/winsup/cygwin/sigproc.h b/winsup/cygwin/sigproc.h index 776d1d9..9c7807a 100644 --- a/winsup/cygwin/sigproc.h +++ b/winsup/cygwin/sigproc.h @@ -12,10 +12,6 @@ details. */ #define _SIGPROC_H #include <signal.h> -#define EXIT_SIGNAL 0x010000 -#define EXIT_REPARENTING 0x020000 -#define EXIT_NOCLOSEALL 0x040000 - #ifdef NSIG enum { @@ -26,7 +22,8 @@ enum __SIGDELETE = -(NSIG + 5), __SIGFLUSHFAST = -(NSIG + 6), __SIGHOLD = -(NSIG + 7), - __SIGNOHOLD = -(NSIG + 8) + __SIGNOHOLD = -(NSIG + 8), + __SIGREPARENT = (NSIG + 2) }; #endif @@ -77,7 +74,6 @@ int __stdcall proc_subproc (DWORD, DWORD) __attribute__ ((regparm (2))); class _pinfo; void __stdcall proc_terminate (); void __stdcall sigproc_init (); -void __stdcall subproc_init (); void __stdcall sigproc_terminate (); bool __stdcall proc_exists (_pinfo *) __attribute__ ((regparm(1))); bool __stdcall pid_exists (pid_t) __attribute__ ((regparm(1))); diff --git a/winsup/cygwin/spawn.cc b/winsup/cygwin/spawn.cc index db4210b..426ee11 100644 --- a/winsup/cygwin/spawn.cc +++ b/winsup/cygwin/spawn.cc @@ -29,8 +29,6 @@ details. */ #include "child_info.h" #include "shared_info.h" #include "pinfo.h" -#define NEED_VFORK -#include "perthread.h" #include "registry.h" #include "environ.h" #include "cygthread.h" @@ -384,16 +382,7 @@ spawn_guts (const char * prog_arg, const char *const *argv, else chtype = PROC_EXEC; - HANDLE subproc_ready; - if (chtype != PROC_EXEC) - subproc_ready = NULL; - else - { - subproc_ready = CreateEvent (&sec_all, TRUE, FALSE, NULL); - ProtectHandleINH (subproc_ready); - } - - init_child_info (chtype, &ciresrv, subproc_ready); + init_child_info (chtype, &ciresrv, NULL); ciresrv.moreinfo = (cygheap_exec_info *) ccalloc (HEAP_1_EXEC, 1, sizeof (cygheap_exec_info)); ciresrv.moreinfo->old_title = NULL; @@ -603,7 +592,6 @@ spawn_guts (const char * prog_arg, const char *const *argv, ciresrv.moreinfo->argc = newargv.argc; ciresrv.moreinfo->argv = newargv; - ciresrv.hexec_proc = hexec_proc; if (mode != _P_OVERLAY || !DuplicateHandle (hMainProc, myself.shared_handle (), hMainProc, @@ -627,19 +615,35 @@ spawn_guts (const char * prog_arg, const char *const *argv, if (mode == _P_DETACH || !set_console_state_for_spawn ()) flags |= DETACHED_PROCESS; + + HANDLE saved_sendsig; if (mode != _P_OVERLAY) - flags |= CREATE_SUSPENDED; -#if 0 //someday + saved_sendsig = NULL; else - myself->dwProcessId = 0; -#endif + { + /* 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"); + } - /* Some file types (currently only sockets) need extra effort in the - parent after CreateProcess and before copying the datastructures - to the child. So we have to start the child in suspend state, - unfortunately, to avoid a race condition. */ - if (cygheap->fdtab.need_fixup_before ()) - flags |= CREATE_SUSPENDED; + /* Start the process in a suspended state. Needed so that any potential parent will + be able to take notice of the new "execed" process. This is only really needed + to handle exec'ed windows processes since cygwin processes are smart enough that + the parent doesn't have to bother but what are you gonna do? Cygwin lives in + a windows world. */ + flags |= CREATE_SUSPENDED; const char *runpath = null_app_name ? NULL : (const char *) real_path; @@ -718,7 +722,7 @@ spawn_guts (const char * prog_arg, const char *const *argv, /* Restore impersonation. In case of _P_OVERLAY this isn't allowed since it would overwrite child data. */ if (mode != _P_OVERLAY || !rc) - cygheap->user.reimpersonate (); + cygheap->user.reimpersonate (); MALLOC_CHECK; if (envblock) @@ -732,12 +736,9 @@ spawn_guts (const char * prog_arg, const char *const *argv, { __seterrno (); syscall_printf ("CreateProcess failed, %E"); -#if 0 // someday - if (mode == _P_OVERLAY) - myself->dwProcessId = GetCurrentProcessId (); -#endif - if (subproc_ready) - ForceCloseHandle (subproc_ready); + /* If this was a failed exec, restore the saved sendsig. */ + if (saved_sendsig) + myself->sendsig = saved_sendsig; cygheap_setup_for_child_cleanup (newheap, &ciresrv, 0); return -1; } @@ -765,11 +766,6 @@ spawn_guts (const char * prog_arg, const char *const *argv, { cygheap->fdtab.fixup_before_exec (pi.dwProcessId); cygheap_setup_for_child_cleanup (newheap, &ciresrv, 1); - if (mode == _P_OVERLAY) - { - ResumeThread (pi.hThread); - cygthread::terminate (); - } } if (mode != _P_OVERLAY) @@ -784,18 +780,36 @@ spawn_guts (const char * prog_arg, const char *const *argv, /* Name the handle similarly to proc_subproc. */ ProtectHandle1 (pi.hProcess, childhProc); + int wait_for_myself = false; + DWORD exec_cygstarted; if (mode == _P_OVERLAY) { - /* These are both duplicated in the child code. We do this here, - primarily for strace. */ + /* Store the old exec_cygstarted since this is used as a crude semaphore for + detecting when the parent has noticed the change in windows pid for this + cygwin pid. */ + exec_cygstarted = myself->cygstarted; + myself->dwProcessId = dwExeced = pi.dwProcessId; /* Reparenting needs this */ + myself.alert_parent (__SIGREPARENT); + CloseHandle (saved_sendsig); strace.execing = 1; hExeced = pi.hProcess; - dwExeced = pi.dwProcessId; strcpy (myself->progname, real_path); close_all_files (); + /* If wr_proc_pipe doesn't exist then this process was not started by a cygwin + process. So, we need to wait around until the process we've just "execed" + dies. Use our own wait facility to wait for our own pid to exit (there + is some minor special case code in proc_waiter and friends to accommodeate + this). */ + if (!myself->wr_proc_pipe) + { + myself.hProcess = pi.hProcess; + myself.remember (); + wait_for_myself = true; + } } else { + exec_cygstarted = 0; myself->set_has_pgid_children (); ProtectHandle (pi.hThread); pinfo child (cygpid, PID_IN_USE); @@ -808,7 +822,7 @@ spawn_guts (const char * prog_arg, const char *const *argv, goto out; } child->dwProcessId = pi.dwProcessId; - child->hProcess = pi.hProcess; + child.hProcess = pi.hProcess; if (!child.remember ()) { syscall_printf ("process table full"); @@ -825,101 +839,31 @@ spawn_guts (const char * prog_arg, const char *const *argv, However, we should try to find another way to do this eventually. */ (void) DuplicateHandle (hMainProc, child.shared_handle (), pi.hProcess, NULL, 0, 0, DUPLICATE_SAME_ACCESS); - /* Start the child running */ - ResumeThread (pi.hThread); } + /* Start the child running */ + if (flags & CREATE_SUSPENDED) + ResumeThread (pi.hThread); ForceCloseHandle (pi.hThread); + // ForceCloseHandle (pi.hProcess); // handled by proc_subproc and friends sigproc_printf ("spawned windows pid %d", pi.dwProcessId); - bool exited; - - res = 0; - exited = false; - MALLOC_CHECK; - if (mode == _P_OVERLAY) + if (wait_for_myself) + waitpid (myself->pid, &res, 0); + else { - int nwait = 3; - HANDLE waitbuf[3] = {pi.hProcess, signal_arrived, subproc_ready}; - for (int i = 0; i < 100; i++) - { - switch (WaitForMultipleObjects (nwait, waitbuf, FALSE, INFINITE)) - { - case WAIT_OBJECT_0: - sigproc_printf ("subprocess exited"); - DWORD exitcode; - if (!GetExitCodeProcess (pi.hProcess, &exitcode)) - exitcode = 1; - res |= exitcode; - exited = true; - break; - case WAIT_OBJECT_0 + 1: - sigproc_printf ("signal arrived"); - reset_signal_arrived (); - continue; - case WAIT_OBJECT_0 + 2: - if (my_parent_is_alive ()) - res |= EXIT_REPARENTING; - else if (!myself->ppid_handle) - { - nwait = 2; - sigproc_terminate (); - continue; - } - break; - case WAIT_FAILED: - system_printf ("wait failed: nwait %d, pid %d, winpid %d, %E", - nwait, myself->pid, myself->dwProcessId); - system_printf ("waitbuf[0] %p %d", waitbuf[0], - WaitForSingleObject (waitbuf[0], 0)); - system_printf ("waitbuf[1] %p %d", waitbuf[1], - WaitForSingleObject (waitbuf[1], 0)); - system_printf ("waitbuf[w] %p %d", waitbuf[2], - WaitForSingleObject (waitbuf[2], 0)); - set_errno (ECHILD); - try_to_debug (); - return -1; - } - break; - } - - ForceCloseHandle (subproc_ready); - - sigproc_printf ("res %p", res); - - if (res & EXIT_REPARENTING) - { - /* Try to reparent child process. - * Make handles to child available to parent process and exit with - * EXIT_REPARENTING status. Wait() syscall in parent will then wait - * for newly created child. - */ - HANDLE oldh = myself->hProcess; - HANDLE h = myself->ppid_handle; - sigproc_printf ("parent handle %p", h); - int rc = DuplicateHandle (hMainProc, pi.hProcess, h, &myself->hProcess, - 0, FALSE, DUPLICATE_SAME_ACCESS); - sigproc_printf ("%d = DuplicateHandle, oldh %p, newh %p", - rc, oldh, myself->hProcess); - VerifyHandle (myself->hProcess); - if (!rc && my_parent_is_alive ()) - { - system_printf ("Reparent failed, parent handle %p, %E", h); - system_printf ("my dwProcessId %d, myself->dwProcessId %d", - GetCurrentProcessId (), myself->dwProcessId); - system_printf ("old hProcess %p, hProcess %p", oldh, myself->hProcess); - } - } - + /* Loop, waiting for parent to notice pid change, if exec_cygstarted. + In theory this wait should be a no-op. */ + if (exec_cygstarted) + while (myself->cygstarted == exec_cygstarted) + low_priority_sleep (0); + res = 42; } - MALLOC_CHECK; - switch (mode) { case _P_OVERLAY: - ForceCloseHandle1 (pi.hProcess, childhProc); myself->exit (res, 1); break; case _P_WAIT: @@ -986,7 +930,6 @@ spawnve (int mode, const char *path, const char *const *argv, case _P_WAIT: case _P_DETACH: case _P_SYSTEM: - subproc_init (); ret = spawn_guts (path, argv, envp, mode); #ifdef NEWVFORK if (vf) diff --git a/winsup/cygwin/syscalls.cc b/winsup/cygwin/syscalls.cc index fded062..262dcdd 100644 --- a/winsup/cygwin/syscalls.cc +++ b/winsup/cygwin/syscalls.cc @@ -56,8 +56,6 @@ details. */ #include "pinfo.h" #include "shared_info.h" #include "cygheap.h" -#define NEED_VFORK -#include "perthread.h" #include "pwdgrp.h" #include "cpuid.h" #include "registry.h" diff --git a/winsup/cygwin/timer.cc b/winsup/cygwin/timer.cc index 8e836e9..e7ce45a 100644 --- a/winsup/cygwin/timer.cc +++ b/winsup/cygwin/timer.cc @@ -16,7 +16,6 @@ details. */ #include "hires.h" #include "thread.h" #include "cygtls.h" -#include "cygthread.h" #include "sigproc.h" #include "sync.h" diff --git a/winsup/cygwin/times.cc b/winsup/cygwin/times.cc index 12eb821..a6fac1a 100644 --- a/winsup/cygwin/times.cc +++ b/winsup/cygwin/times.cc @@ -23,7 +23,6 @@ details. */ #include "pinfo.h" #include "hires.h" #include "cygtls.h" -#include "cygthread.h" #include "sigproc.h" #include "sync.h" diff --git a/winsup/cygwin/tlsoffsets.h b/winsup/cygwin/tlsoffsets.h index e6b955c..a99b38b 100644 --- a/winsup/cygwin/tlsoffsets.h +++ b/winsup/cygwin/tlsoffsets.h @@ -1,113 +1,117 @@ //;# autogenerated: Do not edit. -//; $tls::sizeof__cygtls = 3932; -//; $tls::func = -3932; +//; $tls::sizeof__cygtls = 3936; +//; $tls::func = -3936; //; $tls::pfunc = 0; -//; $tls::saved_errno = -3928; +//; $tls::saved_errno = -3932; //; $tls::psaved_errno = 4; -//; $tls::sa_flags = -3924; +//; $tls::sa_flags = -3928; //; $tls::psa_flags = 8; -//; $tls::oldmask = -3920; +//; $tls::oldmask = -3924; //; $tls::poldmask = 12; -//; $tls::deltamask = -3916; +//; $tls::deltamask = -3920; //; $tls::pdeltamask = 16; -//; $tls::event = -3912; +//; $tls::event = -3916; //; $tls::pevent = 20; -//; $tls::errno_addr = -3908; +//; $tls::errno_addr = -3912; //; $tls::perrno_addr = 24; -//; $tls::initialized = -3904; +//; $tls::initialized = -3908; //; $tls::pinitialized = 28; -//; $tls::sigmask = -3900; +//; $tls::sigmask = -3904; //; $tls::psigmask = 32; -//; $tls::sigwait_mask = -3896; +//; $tls::sigwait_mask = -3900; //; $tls::psigwait_mask = 36; -//; $tls::sigwait_info = -3892; +//; $tls::sigwait_info = -3896; //; $tls::psigwait_info = 40; -//; $tls::threadkill = -3888; +//; $tls::threadkill = -3892; //; $tls::pthreadkill = 44; -//; $tls::infodata = -3884; +//; $tls::infodata = -3888; //; $tls::pinfodata = 48; -//; $tls::tid = -3736; +//; $tls::tid = -3740; //; $tls::ptid = 196; -//; $tls::local_clib = -3732; +//; $tls::local_clib = -3736; //; $tls::plocal_clib = 200; -//; $tls::__dontuse = -3732; +//; $tls::__dontuse = -3736; //; $tls::p__dontuse = 200; -//; $tls::locals = -2668; +//; $tls::locals = -2672; //; $tls::plocals = 1264; +//; $tls::_ctinfo = -1084; +//; $tls::p_ctinfo = 2852; //; $tls::wq = -1080; -//; $tls::pwq = 2852; +//; $tls::pwq = 2856; //; $tls::prev = -1052; -//; $tls::pprev = 2880; +//; $tls::pprev = 2884; //; $tls::next = -1048; -//; $tls::pnext = 2884; +//; $tls::pnext = 2888; //; $tls::stackptr = -1044; -//; $tls::pstackptr = 2888; +//; $tls::pstackptr = 2892; //; $tls::sig = -1040; -//; $tls::psig = 2892; +//; $tls::psig = 2896; //; $tls::incyg = -1036; -//; $tls::pincyg = 2896; +//; $tls::pincyg = 2900; //; $tls::spinning = -1032; -//; $tls::pspinning = 2900; +//; $tls::pspinning = 2904; //; $tls::stacklock = -1028; -//; $tls::pstacklock = 2904; +//; $tls::pstacklock = 2908; //; $tls::stack = -1024; -//; $tls::pstack = 2908; +//; $tls::pstack = 2912; //; $tls::padding = 0; -//; $tls::ppadding = 3932; +//; $tls::ppadding = 3936; //; __DATA__ -#define tls_func (-3932) +#define tls_func (-3936) #define tls_pfunc (0) -#define tls_saved_errno (-3928) +#define tls_saved_errno (-3932) #define tls_psaved_errno (4) -#define tls_sa_flags (-3924) +#define tls_sa_flags (-3928) #define tls_psa_flags (8) -#define tls_oldmask (-3920) +#define tls_oldmask (-3924) #define tls_poldmask (12) -#define tls_deltamask (-3916) +#define tls_deltamask (-3920) #define tls_pdeltamask (16) -#define tls_event (-3912) +#define tls_event (-3916) #define tls_pevent (20) -#define tls_errno_addr (-3908) +#define tls_errno_addr (-3912) #define tls_perrno_addr (24) -#define tls_initialized (-3904) +#define tls_initialized (-3908) #define tls_pinitialized (28) -#define tls_sigmask (-3900) +#define tls_sigmask (-3904) #define tls_psigmask (32) -#define tls_sigwait_mask (-3896) +#define tls_sigwait_mask (-3900) #define tls_psigwait_mask (36) -#define tls_sigwait_info (-3892) +#define tls_sigwait_info (-3896) #define tls_psigwait_info (40) -#define tls_threadkill (-3888) +#define tls_threadkill (-3892) #define tls_pthreadkill (44) -#define tls_infodata (-3884) +#define tls_infodata (-3888) #define tls_pinfodata (48) -#define tls_tid (-3736) +#define tls_tid (-3740) #define tls_ptid (196) -#define tls_local_clib (-3732) +#define tls_local_clib (-3736) #define tls_plocal_clib (200) -#define tls___dontuse (-3732) +#define tls___dontuse (-3736) #define tls_p__dontuse (200) -#define tls_locals (-2668) +#define tls_locals (-2672) #define tls_plocals (1264) +#define tls__ctinfo (-1084) +#define tls_p_ctinfo (2852) #define tls_wq (-1080) -#define tls_pwq (2852) +#define tls_pwq (2856) #define tls_prev (-1052) -#define tls_pprev (2880) +#define tls_pprev (2884) #define tls_next (-1048) -#define tls_pnext (2884) +#define tls_pnext (2888) #define tls_stackptr (-1044) -#define tls_pstackptr (2888) +#define tls_pstackptr (2892) #define tls_sig (-1040) -#define tls_psig (2892) +#define tls_psig (2896) #define tls_incyg (-1036) -#define tls_pincyg (2896) +#define tls_pincyg (2900) #define tls_spinning (-1032) -#define tls_pspinning (2900) +#define tls_pspinning (2904) #define tls_stacklock (-1028) -#define tls_pstacklock (2904) +#define tls_pstacklock (2908) #define tls_stack (-1024) -#define tls_pstack (2908) +#define tls_pstack (2912) #define tls_padding (0) -#define tls_ppadding (3932) +#define tls_ppadding (3936) diff --git a/winsup/cygwin/tty.cc b/winsup/cygwin/tty.cc index edad95c..ef77bd5 100644 --- a/winsup/cygwin/tty.cc +++ b/winsup/cygwin/tty.cc @@ -57,7 +57,7 @@ ttyslot (void) void __stdcall tty_init (void) { - if (!myself->ppid_handle && NOTSTATE (myself, PID_CYGPARENT)) + if (!myself->cygstarted && NOTSTATE (myself, PID_CYGPARENT)) cygheap->fdtab.get_debugger_info (); if (NOTSTATE (myself, PID_USETTY)) diff --git a/winsup/cygwin/wait.cc b/winsup/cygwin/wait.cc index 7d1f13a..70febf0 100644 --- a/winsup/cygwin/wait.cc +++ b/winsup/cygwin/wait.cc @@ -13,7 +13,6 @@ details. */ #include <stdlib.h> #include "cygerrno.h" #include "sigproc.h" -#include "perthread.h" #include "thread.h" #include "cygtls.h" diff --git a/winsup/cygwin/window.cc b/winsup/cygwin/window.cc index a04f7c5..2c5fcce 100644 --- a/winsup/cygwin/window.cc +++ b/winsup/cygwin/window.cc @@ -23,7 +23,6 @@ details. */ #include "cygerrno.h" #include "perprocess.h" #include "security.h" -#include "cygthread.h" #include "thread.h" #include "cygtls.h" #include "sync.h" |