(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 Christopher Faylor <cgf@timesys.com>
+
+ * 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 <corinna@vinschen.de>
* environ.cc (build_env): Disallow empty strings and strings starting
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 */
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;
}
minimal_printf ("winpid %d, exit %d", GetCurrentProcessId (), n);
- myself->exit (n);
+ myself.exit (n);
}
static muto *atexit_lock;
#ifdef DEBUGGING
(void) try_to_debug ();
#endif
- myself->exit (1);
+ myself.exit (1);
}
void
X (DEVICE_DOOR_OPEN, EIO),
X (IO_PENDING, EAGAIN),
X (TOO_MANY_LINKS, EMLINK),
+ X (PROC_NOT_FOUND, ESRCH),
{ 0, NULL, 0}
};
{
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
dll_entry (HANDLE h, DWORD reason, void *static_load)
{
BOOL is_64bit_machine = FALSE;
+ extern HANDLE hExeced;
switch (reason)
{
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 ();
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. */
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)
static DWORD WINAPI
proc_waiter (void *arg)
{
- extern HANDLE hExeced;
pinfo& vchild = *(pinfo *) arg;
siginfo_t si;
{
DWORD nb;
char buf = '\0';
+ extern HANDLE hExeced;
+
if (!ReadFile (vchild.rd_proc_pipe, &buf, 1, &nb, NULL)
&& GetLastError () != ERROR_BROKEN_PIPE)
{
/* 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))
else
si.si_sigval.sival_int = CLD_KILLED;
si.si_status = vchild->exitcode;
- vchild->process_state = PID_ZOMBIE;
break;
case SIGTTIN:
case SIGTTOU:
/* 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);
};
#define EXITCODE_UNSET 0x80000000
+#define EXITCODE_NOSET EXITCODE_UNSET
+#define EXITCODE_EXEC EXITCODE_UNSET
class _pinfo
{
HANDLE tothem;
HANDLE fromthem;
- void exit (UINT n, bool norecord = 0) __attribute__ ((noreturn, regparm(2)));
-
inline void set_has_pgid_children ()
{
if (pgid == pid)
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);}
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)) ==
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;
{
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)
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);
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
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;
}
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:
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;
/* 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;
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. */
}
}
-/* 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
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);
*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);