From 84d38174056e438860213eb0cda919df89c06bd2 Mon Sep 17 00:00:00 2001 From: Christopher Faylor Date: Mon, 13 Mar 2006 21:10:14 +0000 Subject: [PATCH] * 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. --- winsup/cygwin/ChangeLog | 26 ++++++++++++ winsup/cygwin/child_info.h | 4 +- winsup/cygwin/dcrt0.cc | 11 ++++- winsup/cygwin/environ.cc | 10 ++++- winsup/cygwin/exceptions.cc | 1 - winsup/cygwin/fork.cc | 83 ++++++++++++++++++++++--------------- winsup/cygwin/heap.cc | 3 +- winsup/cygwin/pinfo.h | 5 ++- winsup/cygwin/sigproc.cc | 19 +++++---- winsup/cygwin/spawn.cc | 2 +- winsup/cygwin/winsup.h | 16 +++---- 11 files changed, 121 insertions(+), 59 deletions(-) diff --git a/winsup/cygwin/ChangeLog b/winsup/cygwin/ChangeLog index b99e6d9fe..ac979fcdb 100644 --- a/winsup/cygwin/ChangeLog +++ b/winsup/cygwin/ChangeLog @@ -1,3 +1,29 @@ +2006-03-13 Christopher Faylor + + * 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 * dcrt0.cc (dll_crt0_0): Reorganize so that sigproc_init is called a diff --git a/winsup/cygwin/child_info.h b/winsup/cygwin/child_info.h index 9e6433dd5..03e8af58f 100644 --- a/winsup/cygwin/child_info.h +++ b/winsup/cygwin/child_info.h @@ -29,7 +29,7 @@ enum child_info_types #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 below class. The layout is checksummed to determine compatibility between @@ -68,8 +68,10 @@ public: jmp_buf jmp; // where child will jump to void *stacktop; // location of top of parent stack void *stackbottom; // location of bottom of parent stack + int retry; // number of times we've tried to fork child_info_fork (); void handle_fork (); + bool handle_failure (DWORD); }; class fhandler_base; diff --git a/winsup/cygwin/dcrt0.cc b/winsup/cygwin/dcrt0.cc index 149d37794..892a46581 100644 --- a/winsup/cygwin/dcrt0.cc +++ b/winsup/cygwin/dcrt0.cc @@ -122,6 +122,7 @@ extern "C" #ifdef DEBUGGING int pinger; #endif + int NO_COPY __api_fatal_exit_val = 1; }; char *old_title; @@ -640,6 +641,14 @@ get_cygwin_startup_info () 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_end &_data_end__ #define dll_bss_start &_bss_start__ @@ -1157,7 +1166,7 @@ __api_fatal (const char *fmt, ...) #ifdef DEBUGGING try_to_debug (); #endif - myself.exit (1); + myself.exit (__api_fatal_exit_val); } void diff --git a/winsup/cygwin/environ.cc b/winsup/cygwin/environ.cc index eb99d2b51..23d0993a7 100644 --- a/winsup/cygwin/environ.cc +++ b/winsup/cygwin/environ.cc @@ -39,6 +39,7 @@ static bool envcache = true; #ifdef USE_SERVER extern bool allow_server; #endif +extern int fork_retry; static char **lastenviron; @@ -515,7 +516,13 @@ subauth_id_init (const char *buf) static void 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 @@ -587,6 +594,7 @@ static struct parse_thing {"tty", {NULL}, set_process_state, NULL, {{0}, {PID_USETTY}}}, {"winsymlinks", {&allow_winsymlinks}, 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}}} }; diff --git a/winsup/cygwin/exceptions.cc b/winsup/cygwin/exceptions.cc index 587001e7a..60c1d1783 100644 --- a/winsup/cygwin/exceptions.cc +++ b/winsup/cygwin/exceptions.cc @@ -293,7 +293,6 @@ inside_kernel (CONTEXT *cx) { int res; MEMORY_BASIC_INFORMATION m; - extern bool in_dllentry; if (in_dllentry) return true; diff --git a/winsup/cygwin/fork.cc b/winsup/cygwin/fork.cc index eba4337a1..d31fd61a5 100644 --- a/winsup/cygwin/fork.cc +++ b/winsup/cygwin/fork.cc @@ -33,6 +33,8 @@ details. */ #define NPIDS_HELD 4 +int fork_retry = 5; + /* Timeout to wait for child to start, parent to init child, etc. */ /* FIXME: Once things stabilize, bump up to a few minutes. */ #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)", myself->progname, myself->progname, c_flags, &si, &pi); bool locked = __malloc_lock (); - rc = CreateProcess (myself->progname, /* image to run */ - myself->progname, /* what we send in arg0 */ - &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); - - if (!rc) + time_t start_time; + ch.retry = fork_retry; + while (1) { - this_errno = geterrno_from_win_error (); - error = "CreateProcessA failed"; - memset (&pi, 0, sizeof (pi)); - goto cleanup; - } + start_time = time (NULL); + rc = CreateProcess (myself->progname, /* image to run */ + myself->progname, /* what we send in arg0 */ + &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 - main thread. */ - if (c_flags & CREATE_SUSPENDED) - { - cygheap->fdtab.fixup_before_fork (pi.dwProcessId); - ResumeThread (pi.hThread); - } + if (!rc) + { + this_errno = geterrno_from_win_error (); + error = "CreateProcessA failed"; + memset (&pi, 0, sizeof (pi)); + 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.init (child_pid, 1, NULL); @@ -330,7 +353,7 @@ frok::parent (void *stack_here) 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; /* 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); #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 */ debug_printf ("child is alive (but stopped)"); diff --git a/winsup/cygwin/heap.cc b/winsup/cygwin/heap.cc index b45019981..bdf7a757f 100644 --- a/winsup/cygwin/heap.cc +++ b/winsup/cygwin/heap.cc @@ -21,6 +21,7 @@ details. */ #include "cygheap.h" #include "registry.h" #include "cygwin_version.h" +#include "child_info.h" #define assert(x) @@ -75,7 +76,7 @@ heap_init () if ((reserve_size -= page_const) < allocsize) break; } - if (!p) + if (!p && in_forkee && !fork_info->handle_failure (GetLastError ())) api_fatal ("couldn't allocate heap, %E, base %p, top %p, " "reserve_size %d, allocsize %d, page_const %d", cygheap->user_heap.base, cygheap->user_heap.top, diff --git a/winsup/cygwin/pinfo.h b/winsup/cygwin/pinfo.h index 047fdae5b..93a862688 100644 --- a/winsup/cygwin/pinfo.h +++ b/winsup/cygwin/pinfo.h @@ -32,8 +32,9 @@ enum picom PICOM_PIPE_FHANDLER = 7 }; -#define EXITCODE_SET 0x8000000 -#define EXITCODE_NOSET 0x4000000 +#define EXITCODE_SET 0x8000000 +#define EXITCODE_NOSET 0x4000000 +#define EXITCODE_RETRY 0x2000000 class fhandler_pipe; diff --git a/winsup/cygwin/sigproc.cc b/winsup/cygwin/sigproc.cc index c8f11324a..8f49320fa 100644 --- a/winsup/cygwin/sigproc.cc +++ b/winsup/cygwin/sigproc.cc @@ -39,7 +39,7 @@ details. */ #define WSSC 60000 // Wait for signal completion #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 @@ -856,18 +856,23 @@ child_info::sync (pid_t pid, HANDLE& hProcess, DWORD howlong) x -= WAIT_OBJECT_0; if (x >= n) { - system_printf ("wait failed, pid %d, %E", pid); + system_printf ("wait failed, pid %u, %E", pid); res = false; } else { - if (type == _PROC_EXEC && x == nsubproc_ready && myself->wr_proc_pipe) + if (x != nsubproc_ready) + res = type != _PROC_FORK; + else { - ForceCloseHandle1 (hProcess, childhProc); - hProcess = NULL; + if (type == _PROC_EXEC && myself->wr_proc_pipe) + { + ForceCloseHandle1 (hProcess, childhProc); + hProcess = NULL; + } + res = true; } - sigproc_printf ("process %d synchronized, WFMO returned %d", pid, x); - res = true; + sigproc_printf ("pid %u, WFMO returned %d, res %d", pid, x, res); } return res; } diff --git a/winsup/cygwin/spawn.cc b/winsup/cygwin/spawn.cc index 668fb46ea..cac02d988 100644 --- a/winsup/cygwin/spawn.cc +++ b/winsup/cygwin/spawn.cc @@ -846,7 +846,7 @@ spawn_guts (const char * prog_arg, const char *const *argv, 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) { diff --git a/winsup/cygwin/winsup.h b/winsup/cygwin/winsup.h index eaae8e0ab..b8cdd15b7 100644 --- a/winsup/cygwin/winsup.h +++ b/winsup/cygwin/winsup.h @@ -35,10 +35,6 @@ details. */ #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 #define _WIN32_WINNT 0x0501 #endif @@ -157,11 +153,9 @@ extern HANDLE tty_mutex; #define SIGTOMASK(sig) (1 << ((sig) - signal_shift_subtract)) extern unsigned int signal_shift_subtract; -#ifdef NEW_MACRO_VARARGS -# define api_fatal(...) __api_fatal (__VA_ARGS__) -#else -# define api_fatal(fmt, args...) __api_fatal ("%P: *** " fmt,## args) -#endif +extern int __api_fatal_exit_val; +#define set_api_fatal_return(n) do {extern int __api_fatal_exit_val; __api_fatal_exit_val = (n);} while (0) +#define api_fatal(fmt, args...) __api_fatal ("%P: *** " fmt,## args) #undef issep #define issep(ch) (strchr (" \t\n\r", (ch)) != NULL) @@ -346,9 +340,11 @@ extern SYSTEM_INFO system_info; /* The title on program start. */ extern char *old_title; extern bool display_title; -extern bool in_forkee; extern bool transparent_exe; +extern bool in_forkee; +extern bool in_dllentry; + extern HANDLE hMainThread; extern HANDLE hMainProc; extern HANDLE hProcToken;