From 2380dfe14ca24fcc7ddb63feb8f7e4958c1a76ea Mon Sep 17 00:00:00 2001 From: Christopher Faylor Date: Tue, 11 Jan 2005 15:31:04 +0000 Subject: * pinfo.h (_pinfo::set_exit_state): Declare new function. (pinfo::exit): Move here from _pinfo::exit. * sigproc.cc (child_info::sync): Use new function to set exitcode and process_state. * pinfo.cc (_pinfo::exit): Ditto. (proc_waiter): Ditto. (_pinfo::set_exit_state): Define new function. (_pinfo::dup_proc_pipe): Close handle when there is no parent process around to care about the exit value. * dcrt0.cc (dll_crt0_0): Move subproc_ready synchronization later to make sure that myself is still mapped in parent. (do_exit): Reflect movement to pinfo::exit. (__api_fatal): Ditto. * exceptions.cc (signal_exit): Ditto. * errno.cc (errmap): Map PROC_NOT_FOUND. * init.cc (dll_entry): Release myself before exiting. * sigproc.cc (proc_can_be_signalled): Set errno appropriately. (sig_send): Ditto. Also remove ill-advised test for !myself->sendsig since this is an indication of a process which is still initializating -- it is not an error. (child_info::sync): Don't set exitcode here. Assume that will happen in proc_waiter, if necessary. * spawn.cc (spawn_guts): Delay "wait_for_myself" logic until later. Don't wait at all if the process has already exited. Reflect movement to pinfo::exit. --- winsup/cygwin/ChangeLog | 28 ++++++++++++++++ winsup/cygwin/dcrt0.cc | 14 ++++---- winsup/cygwin/errno.cc | 1 + winsup/cygwin/exceptions.cc | 2 +- winsup/cygwin/init.cc | 9 +++-- winsup/cygwin/pinfo.cc | 80 ++++++++++++++++++++++++------------------- winsup/cygwin/pinfo.h | 6 ++-- winsup/cygwin/sigproc.cc | 25 +++++++------- winsup/cygwin/spawn.cc | 82 ++++++++++++++++++++++++--------------------- winsup/cygwin/strace.cc | 4 +-- 10 files changed, 150 insertions(+), 101 deletions(-) (limited to 'winsup') diff --git a/winsup/cygwin/ChangeLog b/winsup/cygwin/ChangeLog index b07de4aaa..23dc35e5c 100644 --- a/winsup/cygwin/ChangeLog +++ b/winsup/cygwin/ChangeLog @@ -1,3 +1,31 @@ +2005-01-11 Christopher Faylor + + * pinfo.h (_pinfo::set_exit_state): Declare new function. + (pinfo::exit): Move here from _pinfo::exit. + * sigproc.cc (child_info::sync): Use new function to set exitcode and + process_state. + * pinfo.cc (_pinfo::exit): Ditto. + (proc_waiter): Ditto. + (_pinfo::set_exit_state): Define new function. + (_pinfo::dup_proc_pipe): Close handle when there is no parent process + around to care about the exit value. + * dcrt0.cc (dll_crt0_0): Move subproc_ready synchronization later to + make sure that myself is still mapped in parent. + (do_exit): Reflect movement to pinfo::exit. + (__api_fatal): Ditto. + * exceptions.cc (signal_exit): Ditto. + * errno.cc (errmap): Map PROC_NOT_FOUND. + * init.cc (dll_entry): Release myself before exiting. + * sigproc.cc (proc_can_be_signalled): Set errno appropriately. + (sig_send): Ditto. Also remove ill-advised test for !myself->sendsig + since this is an indication of a process which is still initializating + -- it is not an error. + (child_info::sync): Don't set exitcode here. Assume that will happen + in proc_waiter, if necessary. + * spawn.cc (spawn_guts): Delay "wait_for_myself" logic until later. + Don't wait at all if the process has already exited. Reflect movement + to pinfo::exit. + 2005-01-11 Corinna Vinschen * environ.cc (build_env): Disallow empty strings and strings starting diff --git a/winsup/cygwin/dcrt0.cc b/winsup/cygwin/dcrt0.cc index b5ce6d53d..df639c20f 100644 --- a/winsup/cygwin/dcrt0.cc +++ b/winsup/cygwin/dcrt0.cc @@ -625,12 +625,8 @@ dll_crt0_0 () else if (sizeof (fhandler_union) != child_proc_info->fhandler_union_cb) multiple_cygwin_problem ("fhandler size", child_proc_info->fhandler_union_cb, sizeof (fhandler_union)); else - { - if (child_proc_info->type != _PROC_FORK) - child_proc_info->ready (true); - cygwin_user_h = child_proc_info->user_h; - break; - } + cygwin_user_h = child_proc_info->user_h; + break; default: system_printf ("unknown exec type %d", child_proc_info->type); /* intentionally fall through */ @@ -667,6 +663,8 @@ dll_crt0_0 () DUPLICATE_SAME_ACCESS | DUPLICATE_CLOSE_SOURCE)) h = NULL; set_myself (h); + if (child_proc_info->type != _PROC_FORK) + child_proc_info->ready (true); __argc = spawn_info->moreinfo->argc; __argv = spawn_info->moreinfo->argv; envp = spawn_info->moreinfo->envp; @@ -1060,7 +1058,7 @@ do_exit (int status) } minimal_printf ("winpid %d, exit %d", GetCurrentProcessId (), n); - myself->exit (n); + myself.exit (n); } static muto *atexit_lock; @@ -1123,7 +1121,7 @@ __api_fatal (const char *fmt, ...) #ifdef DEBUGGING (void) try_to_debug (); #endif - myself->exit (1); + myself.exit (1); } void diff --git a/winsup/cygwin/errno.cc b/winsup/cygwin/errno.cc index fb7923c16..141afb7f3 100644 --- a/winsup/cygwin/errno.cc +++ b/winsup/cygwin/errno.cc @@ -121,6 +121,7 @@ static NO_COPY struct X (DEVICE_DOOR_OPEN, EIO), X (IO_PENDING, EAGAIN), X (TOO_MANY_LINKS, EMLINK), + X (PROC_NOT_FOUND, ESRCH), { 0, NULL, 0} }; diff --git a/winsup/cygwin/exceptions.cc b/winsup/cygwin/exceptions.cc index 9993ef466..2531e6cb8 100644 --- a/winsup/cygwin/exceptions.cc +++ b/winsup/cygwin/exceptions.cc @@ -1080,7 +1080,7 @@ signal_exit (int rc) { EnterCriticalSection (&exit_lock); if (exit_already++) - myself->exit (rc); + myself.exit (rc); /* We'd like to stop the main thread from executing but when we do that it causes random, inexplicable hangs. So, instead, we set up the priority diff --git a/winsup/cygwin/init.cc b/winsup/cygwin/init.cc index 7417f05b4..ad4761820 100644 --- a/winsup/cygwin/init.cc +++ b/winsup/cygwin/init.cc @@ -111,6 +111,7 @@ extern "C" int WINAPI dll_entry (HANDLE h, DWORD reason, void *static_load) { BOOL is_64bit_machine = FALSE; + extern HANDLE hExeced; switch (reason) { @@ -127,8 +128,12 @@ dll_entry (HANDLE h, DWORD reason, void *static_load) dll_crt0_0 (); break; case DLL_PROCESS_DETACH: - if (myself && myself->exitcode == EXITCODE_UNSET) - myself->exitcode = 1 << 8; + if (myself) + { + if (!hExeced && myself->exitcode == EXITCODE_UNSET) + myself->exitcode = 1 << 8; + myself.release (); + } break; case DLL_THREAD_ATTACH: munge_threadfunc (); diff --git a/winsup/cygwin/pinfo.cc b/winsup/cygwin/pinfo.cc index 8b184a6f6..6d55dc464 100644 --- a/winsup/cygwin/pinfo.cc +++ b/winsup/cygwin/pinfo.cc @@ -39,6 +39,8 @@ static char NO_COPY pinfo_dummy[sizeof (_pinfo)] = {0}; pinfo NO_COPY myself ((_pinfo *)&pinfo_dummy); // Avoid myself != NULL checks +bool is_toplevel_proc; + /* Initialize the process table. This is done once when the dll is first loaded. */ @@ -101,40 +103,55 @@ pinfo_init (char **envp, int envc) debug_printf ("pid %d, pgid %d", myself->pid, myself->pgid); } +# define self (*this) void -_pinfo::exit (UINT n, bool norecord) +pinfo::set_exit_state (DWORD pidstate) +{ + DWORD x = 0xdeadbeef; + DWORD oexitcode = self->exitcode; + if (hProcess && self->exitcode == EXITCODE_UNSET) + { + GetExitCodeProcess (hProcess, &x); + self->exitcode = (x & 0xff) << 8; + } + sigproc_printf ("exit value - old %p, windows %p, cygwin %p", oexitcode, x, + self->exitcode); + if (self->exitcode != EXITCODE_NOSET) + self->process_state = pidstate; +} + +void +pinfo::exit (DWORD n) { exit_state = ES_FINAL; cygthread::terminate (); - if (norecord) - sigproc_terminate (); /* Just terminate signal and process stuff */ - else - exitcode = n; /* We're really exiting. Record the UNIX exit code. */ - - if (this) + if (n != EXITCODE_EXEC) { - /* 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; - /* Ensure that the parent knows that this logical process has - terminated. */ - myself->alert_parent (0); - - } + sigproc_terminate (); /* Just terminate signal and process stuff */ + self->exitcode = n; /* We're really exiting. Record the UNIX exit code. */ } - - sigproc_printf ("Calling ExitProcess norecord %d, n %p, exitcode %p", - norecord, n, exitcode); + sigproc_printf ("1 hProcess %p, n %p, exitcode %p", hProcess, n, self->exitcode); + + /* 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 (&self->rusage_self, &r); + + set_exit_state (PID_EXITED); + sigproc_printf ("2 hProcess %p, n %p, exitcode %p, EXITCODE_EXEC %p", hProcess, n, self->exitcode, EXITCODE_EXEC); + if (n != EXITCODE_EXEC) +{sigproc_printf ("3 hProcess %p, n %p, exitcode %p, EXITCODE_EXE %pC", hProcess, n, self->exitcode, EXITCODE_EXEC); + myself->alert_parent (0); +} + _my_tls.stacklock = 0; _my_tls.stackptr = _my_tls.stack; - ExitProcess (exitcode); + sigproc_printf ("Calling ExitProcess hProcess %p, n %p, exitcode %p", + hProcess, n, self->exitcode); + ExitProcess (self->exitcode); } +# undef self void pinfo::init (pid_t n, DWORD flag, HANDLE in_h) @@ -664,7 +681,6 @@ _pinfo::cmdline (size_t& n) static DWORD WINAPI proc_waiter (void *arg) { - extern HANDLE hExeced; pinfo& vchild = *(pinfo *) arg; siginfo_t si; @@ -685,6 +701,8 @@ proc_waiter (void *arg) { DWORD nb; char buf = '\0'; + extern HANDLE hExeced; + if (!ReadFile (vchild.rd_proc_pipe, &buf, 1, &nb, NULL) && GetLastError () != ERROR_BROKEN_PIPE) { @@ -702,12 +720,7 @@ proc_waiter (void *arg) /* Child exited. Do some cleanup and signal myself. */ CloseHandle (vchild.rd_proc_pipe); vchild.rd_proc_pipe = NULL; - if (vchild->exitcode == EXITCODE_UNSET) - { - DWORD x; - GetExitCodeProcess (vchild.hProcess, &x); - vchild->exitcode = (x & 0xff) << 8; - } + vchild.set_exit_state (PID_ZOMBIE); if (WIFEXITED (vchild->exitcode)) si.si_sigval.sival_int = CLD_EXITED; else if (WCOREDUMP (vchild->exitcode)) @@ -715,7 +728,6 @@ proc_waiter (void *arg) else si.si_sigval.sival_int = CLD_KILLED; si.si_status = vchild->exitcode; - vchild->process_state = PID_ZOMBIE; break; case SIGTTIN: case SIGTTOU: @@ -769,7 +781,7 @@ _pinfo::dup_proc_pipe (HANDLE hProcess) /* Grr. Can't set DUPLICATE_CLOSE_SOURCE for exec case because we could be execing a non-cygwin process and we need to set the exit value before the parent sees it. */ - if (this != myself) + if (this != myself || is_toplevel_proc) flags |= DUPLICATE_CLOSE_SOURCE; bool res = DuplicateHandle (hMainProc, wr_proc_pipe, hProcess, &wr_proc_pipe, 0, FALSE, flags); diff --git a/winsup/cygwin/pinfo.h b/winsup/cygwin/pinfo.h index b649e0fbd..776e6359f 100644 --- a/winsup/cygwin/pinfo.h +++ b/winsup/cygwin/pinfo.h @@ -27,6 +27,8 @@ enum picom }; #define EXITCODE_UNSET 0x80000000 +#define EXITCODE_NOSET EXITCODE_UNSET +#define EXITCODE_EXEC EXITCODE_UNSET class _pinfo { @@ -83,8 +85,6 @@ public: HANDLE tothem; HANDLE fromthem; - void exit (UINT n, bool norecord = 0) __attribute__ ((noreturn, regparm(2))); - inline void set_has_pgid_children () { if (pgid == pid) @@ -155,6 +155,8 @@ public: if (destroy && procinfo) release (); } + void exit (DWORD n) __attribute__ ((noreturn, regparm(2))); + void set_exit_state (DWORD) __attribute__ ((regparm(2))); void initialize_lock () {InitializeCriticalSection (&_lock);} void lock () {EnterCriticalSection (&_lock);} void unlock () {LeaveCriticalSection (&_lock);} diff --git a/winsup/cygwin/sigproc.cc b/winsup/cygwin/sigproc.cc index 6ec9a2838..1f65712b6 100644 --- a/winsup/cygwin/sigproc.cc +++ b/winsup/cygwin/sigproc.cc @@ -170,7 +170,13 @@ proc_can_be_signalled (_pinfo *p) if (p->sendsig != INVALID_HANDLE_VALUE) { if (p == myself_nowait || p == myself) - return hwait_sig; + if (hwait_sig) + return true; + else + { + set_errno (EAGAIN); + return hwait_sig; + } if (ISSTATE (p, PID_INITIALIZING) || (((p)->process_state & (PID_ACTIVE | PID_IN_USE)) == @@ -544,9 +550,6 @@ sig_send (_pinfo *p, siginfo_t& si, _cygtls *tls) sigpacket pack; pack.wakeup = NULL; - if (!myself->sendsig) // FIXME: This catches the exec case but what if the exec is going to fail? - goto out; - bool wait_for_completion; if (!(its_me = (p == NULL || p == myself || p == myself_nowait))) wait_for_completion = false; @@ -556,6 +559,7 @@ sig_send (_pinfo *p, siginfo_t& si, _cygtls *tls) { sigproc_printf ("hwait_sig %p, myself->sendsig %p, exit_state %d", hwait_sig, myself->sendsig, exit_state); + set_errno (EAGAIN); goto out; // Either exiting or not yet initializing } if (wait_sig_inited) @@ -601,8 +605,8 @@ sig_send (_pinfo *p, siginfo_t& si, _cygtls *tls) HANDLE hp = OpenProcess (PROCESS_DUP_HANDLE, false, dwProcessId); if (!hp) { - sigproc_printf ("OpenProcess failed, %E"); __seterrno (); + sigproc_printf ("OpenProcess failed, %E"); goto out; } VerifyHandle (hp); @@ -651,8 +655,8 @@ sig_send (_pinfo *p, siginfo_t& si, _cygtls *tls) process is exiting. */ if (!its_me) { - sigproc_printf ("WriteFile for pipe %p failed, %E", sendsig); __seterrno (); + sigproc_printf ("WriteFile for pipe %p failed, %E", sendsig); ForceCloseHandle (sendsig); } else @@ -662,6 +666,7 @@ sig_send (_pinfo *p, siginfo_t& si, _cygtls *tls) else if (!hExeced) system_printf ("error sending signal %d to pid %d, pipe handle %p, %E", si.si_signo, p->pid, sendsig); + set_errno (EACCES); } goto out; } @@ -796,15 +801,9 @@ child_info::sync (pinfo& vchild, DWORD howlong) res = true; break; case WAIT_OBJECT_0 + 1: + sigproc_printf ("process exited before subproc_ready"); if (WaitForSingleObject (subproc_ready, 0) == WAIT_OBJECT_0) sigproc_printf ("should never happen. noticed subproc_ready after process exit"); - else - { - DWORD exitcode = 0; - (void) GetExitCodeProcess (vchild.hProcess, &exitcode); - vchild->exitcode = (exitcode & 0xff) << 8; - sigproc_printf ("non-cygwin exit value is %p", exitcode); - } res = false; break; default: diff --git a/winsup/cygwin/spawn.cc b/winsup/cygwin/spawn.cc index e18b3e20a..d41c58673 100644 --- a/winsup/cygwin/spawn.cc +++ b/winsup/cygwin/spawn.cc @@ -645,7 +645,7 @@ spawn_guts (const char * prog_arg, const char *const *argv, 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 (wincap.start_proc_suspended() || mode != _P_OVERLAY + if (wincap.start_proc_suspended () || mode != _P_OVERLAY || cygheap->fdtab.need_fixup_before ()) flags |= CREATE_SUSPENDED; @@ -787,7 +787,7 @@ spawn_guts (const char * prog_arg, const char *const *argv, /* Name the handle similarly to proc_subproc. */ ProtectHandle1 (pi.hProcess, childhProc); - bool wait_for_myself = false; + bool synced; if (mode == _P_OVERLAY) { myself->dwProcessId = dwExeced = pi.dwProcessId; @@ -807,12 +807,7 @@ spawn_guts (const char * prog_arg, const char *const *argv, on this fact when we exit. dup_proc_pipe also closes our end of the pipe. Note that wr_proc_pipe may also be == INVALID_HANDLE_VALUE. That will make dup_proc_pipe essentially a no-op. */ - if (!myself->wr_proc_pipe) - { - myself.remember (false); - wait_for_myself = true; - } - else + if (myself->wr_proc_pipe) { /* Make sure that we own wr_proc_pipe just in case we've been previously execed. */ @@ -855,42 +850,51 @@ spawn_guts (const char * prog_arg, const char *const *argv, } } -/* Start the child running */ -if (flags & CREATE_SUSPENDED) - ResumeThread (pi.hThread); -ForceCloseHandle (pi.hThread); + /* Start the child running */ + if (flags & CREATE_SUSPENDED) + ResumeThread (pi.hThread); + ForceCloseHandle (pi.hThread); -sigproc_printf ("spawned windows pid %d", pi.dwProcessId); + sigproc_printf ("spawned windows pid %d", pi.dwProcessId); -ciresrv.sync (myself, INFINITE); + synced = ciresrv.sync (myself, INFINITE); -switch (mode) - { - case _P_OVERLAY: - if (wait_for_myself) - waitpid (myself->pid, &res, 0); - myself->exit (res, 1); - break; - case _P_WAIT: - case _P_SYSTEM: - if (waitpid (cygpid, (int *) &res, 0) != cygpid) - res = -1; - break; - case _P_DETACH: - res = 0; /* Lost all memory of this child. */ - break; - case _P_NOWAIT: - case _P_NOWAITO: - case _P_VFORK: - res = cygpid; - break; - default: - break; - } + switch (mode) + { + case _P_OVERLAY: + if (!synced) + /* let myself.exit handle this */; + else if (myself->wr_proc_pipe) + myself.hProcess = NULL; + else + { + extern bool is_toplevel_proc; + is_toplevel_proc = true; + myself.remember (false); + waitpid (myself->pid, &res, 0); + } + myself.exit (EXITCODE_EXEC); + break; + case _P_WAIT: + case _P_SYSTEM: + if (waitpid (cygpid, &res, 0) != cygpid) + res = -1; + break; + case _P_DETACH: + res = 0; /* Lost all memory of this child. */ + break; + case _P_NOWAIT: + case _P_NOWAITO: + case _P_VFORK: + res = cygpid; + break; + default: + break; + } out: -pthread_cleanup_pop (1); -return (int) res; + pthread_cleanup_pop (1); + return (int) res; } extern "C" int diff --git a/winsup/cygwin/strace.cc b/winsup/cygwin/strace.cc index 4c0f08e68..960a89460 100644 --- a/winsup/cygwin/strace.cc +++ b/winsup/cygwin/strace.cc @@ -125,7 +125,7 @@ strace::vsprntf (char *buf, const char *func, const char *infmt, va_list ap) int microsec = microseconds (); lmicrosec = microsec; - __small_sprintf (fmt, "%7d [%s] %s ", microsec, tn, "%s %d%s"); + __small_sprintf (fmt, "%7d [%s] %s ", microsec, tn, "%s %d/%d%s"); SetLastError (err); @@ -147,7 +147,7 @@ strace::vsprntf (char *buf, const char *func, const char *infmt, va_list ap) *p = '\000'; p = progname; count = __small_sprintf (buf, fmt, p && *p ? p : "?", - myself->pid ?: GetCurrentProcessId (), + myself->pid ?: GetCurrentProcessId (), GetCurrentProcessId (), execing ? "!" : ""); if (func) count += getfunc (buf + count, func); -- cgit v1.2.3