* dll_init.c (dll_list::load_after_fork): Don't clear in_forkee here.

* fork.cc (frok::errmsg): Rename from 'error'.
(frok::error): New function.  Handle conditional printing of error messages.
(frok::parent): Record hchild handle for use by error function.  Use
throughout.  Use error function rather than setting error pointer directly.
(fork): Clear is_forkee here.  Accommodate rename of 'error' to 'errmsg'.
* sigproc.cc (child_info::proc_retry): Detect EXITCODE_FORK_FAILED.
This commit is contained in:
Christopher Faylor 2011-05-28 20:09:04 +00:00
parent beaedec545
commit 8551087823
4 changed files with 70 additions and 46 deletions

View File

@ -1,3 +1,17 @@
2011-05-28 Christopher Faylor <me.cygwin2011@cgf.cx>
Ryan Johnson <ryan.johnson@cs.utoronto.ca>
* dll_init.c (dll_list::load_after_fork): Don't clear in_forkee here.
* fork.cc (frok::errmsg): Rename from 'error'.
(frok::error): New function. Handle conditional printing of error
messages.
(frok::parent): Record hchild handle for use by error function. Use
throughout. Use error function rather than setting error pointer
directly.
(fork): Clear is_forkee here. Accommodate rename of 'error' to
'errmsg'.
* sigproc.cc (child_info::proc_retry): Detect EXITCODE_FORK_FAILED.
2011-05-28 Christopher Faylor <me.cygwin2011@cgf.cx> 2011-05-28 Christopher Faylor <me.cygwin2011@cgf.cx>
* fhandler.cc (handler_base_overlapped::wait_overlapped): Rework to * fhandler.cc (handler_base_overlapped::wait_overlapped): Rework to

View File

@ -387,7 +387,6 @@ dll_list::load_after_fork (HANDLE parent)
preferred_block = reserve_at (d->name, (DWORD) h); preferred_block = reserve_at (d->name, (DWORD) h);
} }
in_forkee = false;
} }
struct dllcrt0_info struct dllcrt0_info

View File

@ -37,11 +37,13 @@ class frok
{ {
bool load_dlls; bool load_dlls;
child_info_fork ch; child_info_fork ch;
const char *error; const char *errmsg;
int child_pid; int child_pid;
int this_errno; int this_errno;
HANDLE hchild;
int __stdcall parent (volatile char * volatile here); int __stdcall parent (volatile char * volatile here);
int __stdcall child (volatile char * volatile here); int __stdcall child (volatile char * volatile here);
bool error (const char *fmt, ...);
friend int fork (); friend int fork ();
}; };
@ -163,6 +165,27 @@ sync_with_parent (const char *s, bool hang_self)
} }
} }
bool
frok::error (const char *fmt, ...)
{
DWORD exit_code = ch.exit_code;
if (!exit_code && hchild)
{
exit_code = ch.proc_retry (hchild);
if (!exit_code)
return false;
}
if (exit_code != EXITCODE_FORK_FAILED)
{
va_list ap;
static char buf[NT_MAX_PATH + 256];
va_start (ap, fmt);
__small_vsprintf (buf, fmt, ap);
errmsg = buf;
}
return true;
}
int __stdcall int __stdcall
frok::child (volatile char * volatile here) frok::child (volatile char * volatile here)
{ {
@ -282,15 +305,16 @@ frok::parent (volatile char * volatile stack_here)
HANDLE forker_finished; HANDLE forker_finished;
DWORD rc; DWORD rc;
child_pid = -1; child_pid = -1;
error = NULL;
this_errno = 0; this_errno = 0;
bool fix_impersonation = false; bool fix_impersonation = false;
pinfo child; pinfo child;
static char errbuf[NT_MAX_PATH + 256];
int c_flags = GetPriorityClass (GetCurrentProcess ()); int c_flags = GetPriorityClass (GetCurrentProcess ());
debug_printf ("priority class %d", c_flags); debug_printf ("priority class %d", c_flags);
errmsg = NULL;
hchild = NULL;
/* If we don't have a console, then don't create a console for the /* If we don't have a console, then don't create a console for the
child either. */ child either. */
HANDLE console_handle = CreateFile ("CONOUT$", GENERIC_WRITE, HANDLE console_handle = CreateFile ("CONOUT$", GENERIC_WRITE,
@ -319,7 +343,7 @@ frok::parent (volatile char * volatile stack_here)
if (forker_finished == NULL) if (forker_finished == NULL)
{ {
this_errno = geterrno_from_win_error (); this_errno = geterrno_from_win_error ();
error = "unable to allocate forker_finished event"; error ("unable to allocate forker_finished event");
return -1; return -1;
} }
@ -376,6 +400,7 @@ frok::parent (volatile char * volatile stack_here)
while (1) while (1)
{ {
hchild = NULL;
rc = CreateProcessW (myself->progname, /* image to run */ rc = CreateProcessW (myself->progname, /* image to run */
myself->progname, /* what we send in arg0 */ myself->progname, /* what we send in arg0 */
&sec_none_nih, &sec_none_nih,
@ -390,8 +415,7 @@ frok::parent (volatile char * volatile stack_here)
if (!rc) if (!rc)
{ {
this_errno = geterrno_from_win_error (); this_errno = geterrno_from_win_error ();
__small_sprintf (errbuf, "CreateProcessW failed for '%W'", myself->progname); error ("CreateProcessW failed for '%W'", myself->progname);
error = errbuf;
memset (&pi, 0, sizeof (pi)); memset (&pi, 0, sizeof (pi));
goto cleanup; goto cleanup;
} }
@ -403,24 +427,21 @@ frok::parent (volatile char * volatile stack_here)
} }
CloseHandle (pi.hThread); CloseHandle (pi.hThread);
hchild = pi.hProcess;
/* Protect the handle but name it similarly to the way it will /* Protect the handle but name it similarly to the way it will
be called in subproc handling. */ be called in subproc handling. */
ProtectHandle1 (pi.hProcess, childhProc); ProtectHandle1 (hchild, childhProc);
strace.write_childpid (ch, pi.dwProcessId); strace.write_childpid (ch, pi.dwProcessId);
/* Wait for subproc to initialize itself. */ /* Wait for subproc to initialize itself. */
if (!ch.sync (pi.dwProcessId, pi.hProcess, FORK_WAIT_TIMEOUT)) if (!ch.sync (pi.dwProcessId, hchild, FORK_WAIT_TIMEOUT))
{ {
DWORD exit_code = ch.proc_retry (pi.hProcess); if (!error ("forked process died unexpectedly, retry %d, exit code %d",
if (!exit_code) ch.retry, ch.exit_code))
continue; continue;
this_errno = EAGAIN; this_errno = EAGAIN;
/* Not thread safe, but do we care? */
__small_sprintf (errbuf, "died waiting for longjmp before initialization, "
"retry %d, exit code %p", ch.retry, exit_code);
error = errbuf;
goto cleanup; goto cleanup;
} }
break; break;
@ -436,11 +457,7 @@ frok::parent (volatile char * volatile stack_here)
if (!child) if (!child)
{ {
this_errno = get_errno () == ENOMEM ? ENOMEM : EAGAIN; this_errno = get_errno () == ENOMEM ? ENOMEM : EAGAIN;
#ifdef DEBUGGING
error = "pinfo failed";
#else
syscall_printf ("pinfo failed"); syscall_printf ("pinfo failed");
#endif
goto cleanup; goto cleanup;
} }
@ -453,7 +470,7 @@ frok::parent (volatile char * volatile stack_here)
/* Fill in fields in the child's process table entry. */ /* Fill in fields in the child's process table entry. */
child->dwProcessId = pi.dwProcessId; child->dwProcessId = pi.dwProcessId;
child.hProcess = pi.hProcess; child.hProcess = hchild;
/* Hopefully, this will succeed. The alternative to doing things this /* Hopefully, this will succeed. The alternative to doing things this
way is to reserve space prior to calling CreateProcess and then fill way is to reserve space prior to calling CreateProcess and then fill
@ -462,16 +479,16 @@ frok::parent (volatile char * volatile stack_here)
we can't actually record the pid in the internal table. */ we can't actually record the pid in the internal table. */
if (!child.remember (false)) if (!child.remember (false))
{ {
TerminateProcess (pi.hProcess, 1); TerminateProcess (hchild, 1);
this_errno = EAGAIN; this_errno = EAGAIN;
#ifdef DEBUGGING0 #ifdef DEBUGGING0
error = "child.remember failed"; error ("child remember failed");
#endif #endif
goto cleanup; goto cleanup;
} }
#ifndef NO_SLOW_PID_REUSE #ifndef NO_SLOW_PID_REUSE
slow_pid_reuse (pi.hProcess); slow_pid_reuse (hchild);
#endif #endif
/* CHILD IS STOPPED */ /* CHILD IS STOPPED */
@ -494,7 +511,7 @@ frok::parent (volatile char * volatile stack_here)
impure_beg = _impure_ptr; impure_beg = _impure_ptr;
impure_end = _impure_ptr + 1; impure_end = _impure_ptr + 1;
} }
rc = child_copy (pi.hProcess, true, rc = child_copy (hchild, true,
"stack", stack_here, ch.stackbottom, "stack", stack_here, ch.stackbottom,
impure, impure_beg, impure_end, impure, impure_beg, impure_end,
NULL); NULL);
@ -505,11 +522,7 @@ frok::parent (volatile char * volatile stack_here)
if (!rc) if (!rc)
{ {
this_errno = get_errno (); this_errno = get_errno ();
DWORD exit_code; error ("pid %u, exitval %p", pi.dwProcessId, ch.exit_code);
if (!GetExitCodeProcess (pi.hProcess, &exit_code))
exit_code = 0xdeadbeef;
__small_sprintf (errbuf, "pid %u, exitval %p", pi.dwProcessId, exit_code);
error = errbuf;
goto cleanup; goto cleanup;
} }
@ -517,29 +530,23 @@ frok::parent (volatile char * volatile stack_here)
for (dll *d = dlls.istart (DLL_LINK); d; d = dlls.inext ()) for (dll *d = dlls.istart (DLL_LINK); d; d = dlls.inext ())
{ {
debug_printf ("copying data/bss of a linked dll"); debug_printf ("copying data/bss of a linked dll");
if (!child_copy (pi.hProcess, true, if (!child_copy (hchild, true,
"linked dll data", d->p.data_start, d->p.data_end, "linked dll data", d->p.data_start, d->p.data_end,
"linked dll bss", d->p.bss_start, d->p.bss_end, "linked dll bss", d->p.bss_start, d->p.bss_end,
NULL)) NULL))
{ {
this_errno = get_errno (); this_errno = get_errno ();
#ifdef DEBUGGING error ("couldn't copy linked dll data/bss");
DWORD exit_code;
if (!GetExitCodeProcess (pi.hProcess, &exit_code))
exit_code = 0xdeadbeef;
__small_sprintf (errbuf, "pid %u, exitval %p", pi.dwProcessId, exit_code);
error = errbuf;
#endif
goto cleanup; goto cleanup;
} }
} }
/* Start thread, and then wait for it to reload dlls. */ /* Start thread, and then wait for it to reload dlls. */
resume_child (forker_finished); resume_child (forker_finished);
if (!ch.sync (child->pid, pi.hProcess, FORK_WAIT_TIMEOUT)) if (!ch.sync (child->pid, hchild, FORK_WAIT_TIMEOUT))
{ {
this_errno = EAGAIN; this_errno = EAGAIN;
error = "died waiting for dll loading"; error ("died waiting for dll loading");
goto cleanup; goto cleanup;
} }
@ -553,14 +560,14 @@ frok::parent (volatile char * volatile stack_here)
for (dll *d = dlls.istart (DLL_LOAD); d; d = dlls.inext ()) for (dll *d = dlls.istart (DLL_LOAD); d; d = dlls.inext ())
{ {
debug_printf ("copying data/bss for a loaded dll"); debug_printf ("copying data/bss for a loaded dll");
if (!child_copy (pi.hProcess, true, if (!child_copy (hchild, true,
"loaded dll data", d->p.data_start, d->p.data_end, "loaded dll data", d->p.data_start, d->p.data_end,
"loaded dll bss", d->p.bss_start, d->p.bss_end, "loaded dll bss", d->p.bss_start, d->p.bss_end,
NULL)) NULL))
{ {
this_errno = get_errno (); this_errno = get_errno ();
#ifdef DEBUGGING #ifdef DEBUGGING
error = "copying data/bss for a loaded dll"; error ("copying data/bss for a loaded dll");
#endif #endif
goto cleanup; goto cleanup;
} }
@ -582,8 +589,8 @@ cleanup:
__malloc_unlock (); __malloc_unlock ();
/* Remember to de-allocate the fd table. */ /* Remember to de-allocate the fd table. */
if (pi.hProcess && !child.hProcess) if (hchild && !child.hProcess)
ForceCloseHandle1 (pi.hProcess, childhProc); ForceCloseHandle1 (hchild, childhProc);
if (forker_finished) if (forker_finished)
ForceCloseHandle (forker_finished); ForceCloseHandle (forker_finished);
debug_printf ("returning -1"); debug_printf ("returning -1");
@ -637,6 +644,7 @@ fork ()
else else
{ {
res = grouped.child (esp); res = grouped.child (esp);
in_forkee = false;
ischild = true; /* might have been reset by fork mem copy */ ischild = true; /* might have been reset by fork mem copy */
} }
} }
@ -649,13 +657,13 @@ fork ()
} }
else if (res < 0) else if (res < 0)
{ {
if (!grouped.error) if (!grouped.errmsg)
syscall_printf ("fork failed - child pid %d, errno %d", grouped.child_pid, grouped.this_errno); syscall_printf ("fork failed - child pid %d, errno %d", grouped.child_pid, grouped.this_errno);
else else
{ {
char buf[strlen (grouped.error) + sizeof ("child %d - , errno 4294967295 ")]; char buf[strlen (grouped.errmsg) + sizeof ("child %d - , errno 4294967295 ")];
strcpy (buf, "child %d - "); strcpy (buf, "child %d - ");
strcat (buf, grouped.error); strcat (buf, grouped.errmsg);
strcat (buf, ", errno %d"); strcat (buf, ", errno %d");
system_printf (buf, grouped.child_pid, grouped.this_errno); system_printf (buf, grouped.child_pid, grouped.this_errno);
} }

View File

@ -912,6 +912,9 @@ child_info::proc_retry (HANDLE h)
if (retry-- > 0) if (retry-- > 0)
exit_code = 0; exit_code = 0;
break; break;
case EXITCODE_FORK_FAILED: /* windows prevented us from forking */
break;
/* Count down non-recognized exit codes more quickly since they aren't /* Count down non-recognized exit codes more quickly since they aren't
due to known conditions. */ due to known conditions. */
default: default: