* child_info.h (child_info_fork::handle_failure): Declare new function.

(child_info_fork::retry): New field.
* dcrt0.cc (__api_fatal_exit_val): Define.
(child_info_fork::handle_failure): Define new function.
(__api_fatal): Exit using __api_fatal_exit_val value.
* environ.cc (set_fork_retry): Set fork_retry based on CYGWIN environment
variable.
(parse_thing): Add "fork_retry" setting.
* fork.cc (fork_retry): Define.
(frok::parent): Reorganize to allow retry of failed child creation if child
signalled that it was ok to do so.
* heap.cc (heap_init): Signal parent via handle_failure when VirtualAlloc
fails.
* pinfo.h (EXITCODE_RETRY): Declare.
* sigproc.cc (child_info::sync): Properly exit with failure condition if called
for fork and didn't see subproc_ready.
* spawn.cc (spawn_guts): Use windows pid as first argument.
* winsup.h: Remove obsolete NEW_MACRO_VARARGS define.
(__api_fatal_exit_val): Declare.
(set_api_fatal_return): Define.
(in_dllentry): Declare.
* exceptions.cc (inside_kernel): Remove unneeded in_dllentry declaration.
This commit is contained in:
Christopher Faylor 2006-03-13 21:10:14 +00:00
parent 063fd12660
commit 84d3817405
11 changed files with 121 additions and 59 deletions

View File

@ -1,3 +1,29 @@
2006-03-13 Christopher Faylor <cgf@timesys.com>
* child_info.h (child_info_fork::handle_failure): Declare new function.
(child_info_fork::retry): New field.
* dcrt0.cc (__api_fatal_exit_val): Define.
(child_info_fork::handle_failure): Define new function.
(__api_fatal): Exit using __api_fatal_exit_val value.
* environ.cc (set_fork_retry): Set fork_retry based on CYGWIN
environment variable.
(parse_thing): Add "fork_retry" setting.
* fork.cc (fork_retry): Define.
(frok::parent): Reorganize to allow retry of failed child creation if
child signalled that it was ok to do so.
* heap.cc (heap_init): Signal parent via handle_failure when
VirtualAlloc fails.
* pinfo.h (EXITCODE_RETRY): Declare.
* sigproc.cc (child_info::sync): Properly exit with failure condition
if called for fork and didn't see subproc_ready.
* spawn.cc (spawn_guts): Use windows pid as first argument.
* winsup.h: Remove obsolete NEW_MACRO_VARARGS define.
(__api_fatal_exit_val): Declare.
(set_api_fatal_return): Define.
(in_dllentry): Declare.
* exceptions.cc (inside_kernel): Remove unneeded in_dllentry
declaration.
2006-03-13 Christopher Faylor <cgf@timesys.com> 2006-03-13 Christopher Faylor <cgf@timesys.com>
* dcrt0.cc (dll_crt0_0): Reorganize so that sigproc_init is called a * dcrt0.cc (dll_crt0_0): Reorganize so that sigproc_init is called a

View File

@ -29,7 +29,7 @@ enum child_info_types
#define EXEC_MAGIC_SIZE sizeof(child_info) #define EXEC_MAGIC_SIZE sizeof(child_info)
#define CURR_CHILD_INFO_MAGIC 0xc87757a7U #define CURR_CHILD_INFO_MAGIC 0x4160e87bU
/* NOTE: Do not make gratuitous changes to the names or organization of the /* NOTE: Do not make gratuitous changes to the names or organization of the
below class. The layout is checksummed to determine compatibility between below class. The layout is checksummed to determine compatibility between
@ -68,8 +68,10 @@ public:
jmp_buf jmp; // where child will jump to jmp_buf jmp; // where child will jump to
void *stacktop; // location of top of parent stack void *stacktop; // location of top of parent stack
void *stackbottom; // location of bottom of parent stack void *stackbottom; // location of bottom of parent stack
int retry; // number of times we've tried to fork
child_info_fork (); child_info_fork ();
void handle_fork (); void handle_fork ();
bool handle_failure (DWORD);
}; };
class fhandler_base; class fhandler_base;

View File

@ -122,6 +122,7 @@ extern "C"
#ifdef DEBUGGING #ifdef DEBUGGING
int pinger; int pinger;
#endif #endif
int NO_COPY __api_fatal_exit_val = 1;
}; };
char *old_title; char *old_title;
@ -640,6 +641,14 @@ get_cygwin_startup_info ()
return res; return res;
} }
bool
child_info_fork::handle_failure (DWORD err)
{
if (retry > 0)
ExitProcess (EXITCODE_RETRY);
return 0;
}
#define dll_data_start &_data_start__ #define dll_data_start &_data_start__
#define dll_data_end &_data_end__ #define dll_data_end &_data_end__
#define dll_bss_start &_bss_start__ #define dll_bss_start &_bss_start__
@ -1157,7 +1166,7 @@ __api_fatal (const char *fmt, ...)
#ifdef DEBUGGING #ifdef DEBUGGING
try_to_debug (); try_to_debug ();
#endif #endif
myself.exit (1); myself.exit (__api_fatal_exit_val);
} }
void void

View File

@ -39,6 +39,7 @@ static bool envcache = true;
#ifdef USE_SERVER #ifdef USE_SERVER
extern bool allow_server; extern bool allow_server;
#endif #endif
extern int fork_retry;
static char **lastenviron; static char **lastenviron;
@ -515,7 +516,13 @@ subauth_id_init (const char *buf)
static void static void
set_chunksize (const char *buf) set_chunksize (const char *buf)
{ {
wincap.set_chunksize (strtol (buf, NULL, 0)); wincap.set_chunksize (strtoul (buf, NULL, 0));
}
static void
set_fork_retry (const char *buf)
{
fork_retry = strtoul (buf, NULL, 0);
} }
static void static void
@ -587,6 +594,7 @@ static struct parse_thing
{"tty", {NULL}, set_process_state, NULL, {{0}, {PID_USETTY}}}, {"tty", {NULL}, set_process_state, NULL, {{0}, {PID_USETTY}}},
{"winsymlinks", {&allow_winsymlinks}, justset, NULL, {{false}, {true}}}, {"winsymlinks", {&allow_winsymlinks}, justset, NULL, {{false}, {true}}},
{"transparent_exe", {&transparent_exe}, justset, NULL, {{false}, {true}}}, {"transparent_exe", {&transparent_exe}, justset, NULL, {{false}, {true}}},
{"fork_retry", {func: set_fork_retry}, isfunc, NULL, {{0}, {5}}},
{NULL, {0}, justset, 0, {{0}, {0}}} {NULL, {0}, justset, 0, {{0}, {0}}}
}; };

View File

@ -293,7 +293,6 @@ inside_kernel (CONTEXT *cx)
{ {
int res; int res;
MEMORY_BASIC_INFORMATION m; MEMORY_BASIC_INFORMATION m;
extern bool in_dllentry;
if (in_dllentry) if (in_dllentry)
return true; return true;

View File

@ -33,6 +33,8 @@ details. */
#define NPIDS_HELD 4 #define NPIDS_HELD 4
int fork_retry = 5;
/* Timeout to wait for child to start, parent to init child, etc. */ /* Timeout to wait for child to start, parent to init child, etc. */
/* FIXME: Once things stabilize, bump up to a few minutes. */ /* FIXME: Once things stabilize, bump up to a few minutes. */
#define FORK_WAIT_TIMEOUT (300 * 1000) /* 300 seconds */ #define FORK_WAIT_TIMEOUT (300 * 1000) /* 300 seconds */
@ -287,34 +289,55 @@ frok::parent (void *stack_here)
syscall_printf ("CreateProcess (%s, %s, 0, 0, 1, %p, 0, 0, %p, %p)", syscall_printf ("CreateProcess (%s, %s, 0, 0, 1, %p, 0, 0, %p, %p)",
myself->progname, myself->progname, c_flags, &si, &pi); myself->progname, myself->progname, c_flags, &si, &pi);
bool locked = __malloc_lock (); bool locked = __malloc_lock ();
rc = CreateProcess (myself->progname, /* image to run */ time_t start_time;
myself->progname, /* what we send in arg0 */ ch.retry = fork_retry;
&sec_none_nih, while (1)
&sec_none_nih,
TRUE, /* inherit handles from parent */
c_flags,
NULL, /* environment filled in later */
0, /* use current drive/directory */
&si,
&pi);
if (!rc)
{ {
this_errno = geterrno_from_win_error (); start_time = time (NULL);
error = "CreateProcessA failed"; rc = CreateProcess (myself->progname, /* image to run */
memset (&pi, 0, sizeof (pi)); myself->progname, /* what we send in arg0 */
goto cleanup; &sec_none_nih,
} &sec_none_nih,
TRUE, /* inherit handles from parent */
c_flags,
NULL, /* environment filled in later */
0, /* use current drive/directory */
&si,
&pi);
/* Fixup the parent datastructure if needed and resume the child's if (!rc)
main thread. */ {
if (c_flags & CREATE_SUSPENDED) this_errno = geterrno_from_win_error ();
{ error = "CreateProcessA failed";
cygheap->fdtab.fixup_before_fork (pi.dwProcessId); memset (&pi, 0, sizeof (pi));
ResumeThread (pi.hThread); goto cleanup;
} }
strace.write_childpid (ch, pi.dwProcessId); /* Fixup the parent datastructure if needed and resume the child's
main thread. */
if (c_flags & CREATE_SUSPENDED)
{
cygheap->fdtab.fixup_before_fork (pi.dwProcessId);
ResumeThread (pi.hThread);
}
strace.write_childpid (ch, pi.dwProcessId);
/* Wait for subproc to initialize itself. */
if (!ch.sync (pi.dwProcessId, pi.hProcess, FORK_WAIT_TIMEOUT))
{
DWORD exit_code;
if (GetExitCodeProcess (pi.hProcess, &exit_code) && exit_code == EXITCODE_RETRY)
{
ch.retry--;
continue;
}
this_errno = EAGAIN;
error = "died waiting for longjmp before initialization";
goto cleanup;
}
break;
}
child_pid = cygwin_pid (pi.dwProcessId); child_pid = cygwin_pid (pi.dwProcessId);
child.init (child_pid, 1, NULL); child.init (child_pid, 1, NULL);
@ -330,7 +353,7 @@ frok::parent (void *stack_here)
goto cleanup; goto cleanup;
} }
child->start_time = time (NULL); /* Register child's starting time. */ child->start_time = start_time; /* Register child's starting time. */
child->nice = myself->nice; child->nice = myself->nice;
/* Initialize things that are done later in dll_crt0_1 that aren't done /* Initialize things that are done later in dll_crt0_1 that aren't done
@ -369,14 +392,6 @@ frok::parent (void *stack_here)
slow_pid_reuse (pi.hProcess); slow_pid_reuse (pi.hProcess);
#endif #endif
/* Wait for subproc to initialize itself. */
if (!ch.sync (child->pid, pi.hProcess, FORK_WAIT_TIMEOUT))
{
this_errno = EAGAIN;
error = "died waiting for longjmp before initialization";
goto cleanup;
}
/* CHILD IS STOPPED */ /* CHILD IS STOPPED */
debug_printf ("child is alive (but stopped)"); debug_printf ("child is alive (but stopped)");

View File

@ -21,6 +21,7 @@ details. */
#include "cygheap.h" #include "cygheap.h"
#include "registry.h" #include "registry.h"
#include "cygwin_version.h" #include "cygwin_version.h"
#include "child_info.h"
#define assert(x) #define assert(x)
@ -75,7 +76,7 @@ heap_init ()
if ((reserve_size -= page_const) < allocsize) if ((reserve_size -= page_const) < allocsize)
break; break;
} }
if (!p) if (!p && in_forkee && !fork_info->handle_failure (GetLastError ()))
api_fatal ("couldn't allocate heap, %E, base %p, top %p, " api_fatal ("couldn't allocate heap, %E, base %p, top %p, "
"reserve_size %d, allocsize %d, page_const %d", "reserve_size %d, allocsize %d, page_const %d",
cygheap->user_heap.base, cygheap->user_heap.top, cygheap->user_heap.base, cygheap->user_heap.top,

View File

@ -32,8 +32,9 @@ enum picom
PICOM_PIPE_FHANDLER = 7 PICOM_PIPE_FHANDLER = 7
}; };
#define EXITCODE_SET 0x8000000 #define EXITCODE_SET 0x8000000
#define EXITCODE_NOSET 0x4000000 #define EXITCODE_NOSET 0x4000000
#define EXITCODE_RETRY 0x2000000
class fhandler_pipe; class fhandler_pipe;

View File

@ -39,7 +39,7 @@ details. */
#define WSSC 60000 // Wait for signal completion #define WSSC 60000 // Wait for signal completion
#define WPSP 40000 // Wait for proc_subproc mutex #define WPSP 40000 // Wait for proc_subproc mutex
#define no_signals_available(x) (!hwait_sig || ((x) && myself->exitcode & EXITCODE_SET) || &_my_tls == _sig_tls) #define no_signals_available(x) (!hwait_sig || ((x) && myself->exitcode & EXITCODE_SET) || &_my_tls == _sig_tls || in_dllentry)
#define NPROCS 256 #define NPROCS 256
@ -856,18 +856,23 @@ child_info::sync (pid_t pid, HANDLE& hProcess, DWORD howlong)
x -= WAIT_OBJECT_0; x -= WAIT_OBJECT_0;
if (x >= n) if (x >= n)
{ {
system_printf ("wait failed, pid %d, %E", pid); system_printf ("wait failed, pid %u, %E", pid);
res = false; res = false;
} }
else else
{ {
if (type == _PROC_EXEC && x == nsubproc_ready && myself->wr_proc_pipe) if (x != nsubproc_ready)
res = type != _PROC_FORK;
else
{ {
ForceCloseHandle1 (hProcess, childhProc); if (type == _PROC_EXEC && myself->wr_proc_pipe)
hProcess = NULL; {
ForceCloseHandle1 (hProcess, childhProc);
hProcess = NULL;
}
res = true;
} }
sigproc_printf ("process %d synchronized, WFMO returned %d", pid, x); sigproc_printf ("pid %u, WFMO returned %d, res %d", pid, x, res);
res = true;
} }
return res; return res;
} }

View File

@ -846,7 +846,7 @@ spawn_guts (const char * prog_arg, const char *const *argv,
sigproc_printf ("spawned windows pid %d", pi.dwProcessId); sigproc_printf ("spawned windows pid %d", pi.dwProcessId);
synced = ch.sync (pid, pi.hProcess, INFINITE); synced = ch.sync (pi.dwProcessId, pi.hProcess, INFINITE);
switch (mode) switch (mode)
{ {

View File

@ -35,10 +35,6 @@ details. */
#define EXPORT_ALIAS(sym,symalias) extern "C" __typeof (sym) symalias __attribute__ ((alias(#sym))); #define EXPORT_ALIAS(sym,symalias) extern "C" __typeof (sym) symalias __attribute__ ((alias(#sym)));
#if !defined(__STDC_VERSION__) || __STDC_VERSION__ >= 199900L
#define NEW_MACRO_VARARGS
#endif
#ifndef _WIN32_WINNT #ifndef _WIN32_WINNT
#define _WIN32_WINNT 0x0501 #define _WIN32_WINNT 0x0501
#endif #endif
@ -157,11 +153,9 @@ extern HANDLE tty_mutex;
#define SIGTOMASK(sig) (1 << ((sig) - signal_shift_subtract)) #define SIGTOMASK(sig) (1 << ((sig) - signal_shift_subtract))
extern unsigned int signal_shift_subtract; extern unsigned int signal_shift_subtract;
#ifdef NEW_MACRO_VARARGS extern int __api_fatal_exit_val;
# define api_fatal(...) __api_fatal (__VA_ARGS__) #define set_api_fatal_return(n) do {extern int __api_fatal_exit_val; __api_fatal_exit_val = (n);} while (0)
#else #define api_fatal(fmt, args...) __api_fatal ("%P: *** " fmt,## args)
# define api_fatal(fmt, args...) __api_fatal ("%P: *** " fmt,## args)
#endif
#undef issep #undef issep
#define issep(ch) (strchr (" \t\n\r", (ch)) != NULL) #define issep(ch) (strchr (" \t\n\r", (ch)) != NULL)
@ -346,9 +340,11 @@ extern SYSTEM_INFO system_info;
/* The title on program start. */ /* The title on program start. */
extern char *old_title; extern char *old_title;
extern bool display_title; extern bool display_title;
extern bool in_forkee;
extern bool transparent_exe; extern bool transparent_exe;
extern bool in_forkee;
extern bool in_dllentry;
extern HANDLE hMainThread; extern HANDLE hMainThread;
extern HANDLE hMainProc; extern HANDLE hMainProc;
extern HANDLE hProcToken; extern HANDLE hProcToken;