diff --git a/winsup/cygwin/ChangeLog b/winsup/cygwin/ChangeLog index 6df8c85d6..65d7a0fb9 100644 --- a/winsup/cygwin/ChangeLog +++ b/winsup/cygwin/ChangeLog @@ -1,3 +1,22 @@ +2005-09-28 Christopher Faylor + + * dcrt0.cc (getstack): New function. + (alloc_stack): Use tls stuff for stack info rather than calling + VirtualQuery. + (dll_crt0_0): Initialize _impure_ptr stuff much earlier. Move + init_console_handler here. + * fork.cc (class frok): New class renamed from local fork() struct. + (stack_base): Change argument type. Use tls stuff to determine stack + info rather than calling VirtualQuery. + (frok::child): Rename from fork_child. Eliminate now unneeded + arguments. + (frok::parent): Rename from fork_parent and ditto. Set error and errno + as appropriate. Fixup impersonation in cleanup, if needed. Try harder + to set errno appropriately. + (fork): Define "grouped" as a frok type. Deal with errors from + fork_parent here. + * init.cc (dll_entry): Remove init_console_handler call. + 2005-09-28 Christopher Faylor * pinfo.cc (_pinfo::dup_proc_pipe): Ignore error if the child process diff --git a/winsup/cygwin/dcrt0.cc b/winsup/cygwin/dcrt0.cc index ca8b601c9..953c93ec0 100644 --- a/winsup/cygwin/dcrt0.cc +++ b/winsup/cygwin/dcrt0.cc @@ -502,22 +502,29 @@ alloc_stack_hard_way (child_info_fork *ci, volatile char *b) b[0] = '\0'; } +void *getstack (void *) __attribute__ ((noinline)); +volatile char * +getstack (volatile char *p) +{ + *p |= 0; + return p - 4096; +} + /* extend the stack prior to fork longjmp */ static void alloc_stack (child_info_fork *ci) { - /* FIXME: adding 16384 seems to avoid a stack copy problem during - fork on Win95, but I don't know exactly why yet. DJ */ - volatile char b[ci->stacksize + 16384]; - - if (!VirtualQuery ((LPCVOID) &b, &sm, sizeof sm)) - api_fatal ("fork: couldn't get stack info, %E"); - - if (sm.AllocationBase == ci->stacktop) - ci->stacksize = 0; + volatile char *esp; + __asm__ volatile ("movl %%esp,%0": "=r" (esp)); + if (_tlsbase != ci->stackbottom) + alloc_stack_hard_way (ci, esp); else - alloc_stack_hard_way (ci, b + sizeof (b) - 1); + { + while (_tlstop > ci->stacktop) + esp = getstack (esp); + ci->stacksize = 0; + } } #ifdef DEBUGGING @@ -629,6 +636,12 @@ get_cygwin_startup_info () void __stdcall dll_crt0_0 () { + init_console_handler (TRUE); + _impure_ptr = _GLOBAL_REENT; + _impure_ptr->_stdin = &_impure_ptr->__sf[0]; + _impure_ptr->_stdout = &_impure_ptr->__sf[1]; + _impure_ptr->_stderr = &_impure_ptr->__sf[2]; + _impure_ptr->_current_locale = "C"; wincap.init (); initial_env (); @@ -931,11 +944,6 @@ _dll_crt0 () *main_environ = NULL; char padding[CYGTLS_PADSIZE]; - _impure_ptr = _GLOBAL_REENT; - _impure_ptr->_stdin = &_impure_ptr->__sf[0]; - _impure_ptr->_stdout = &_impure_ptr->__sf[1]; - _impure_ptr->_stderr = &_impure_ptr->__sf[2]; - _impure_ptr->_current_locale = "C"; if (child_proc_info && child_proc_info->type == _PROC_FORK) user_data->forkee = true; diff --git a/winsup/cygwin/fork.cc b/winsup/cygwin/fork.cc index 92e27aa78..64fd53893 100644 --- a/winsup/cygwin/fork.cc +++ b/winsup/cygwin/fork.cc @@ -42,20 +42,28 @@ details. */ #define dll_bss_start &_bss_start__ #define dll_bss_end &_bss_end__ -static void -stack_base (child_info_fork &ch) +class frok { - MEMORY_BASIC_INFORMATION m; - memset (&m, 0, sizeof m); - if (!VirtualQuery ((LPCVOID) &m, &m, sizeof m)) - system_printf ("couldn't get memory info, %E"); + dll *first_dll; + bool load_dlls; + child_info_fork ch; + const char *error; + int child_pid; + int this_errno; + int __stdcall parent (void *esp); + int __stdcall child (void *esp); + friend int fork (); +}; - ch.stacktop = m.AllocationBase; - ch.stackbottom = (LPBYTE) m.BaseAddress + m.RegionSize; - ch.stacksize = (DWORD) ch.stackbottom - (DWORD) &m; +static void +stack_base (child_info_fork *ch) +{ + ch->stackbottom = _tlsbase; + ch->stacktop = &ch; + ch->stacksize = (char *) ch->stackbottom - (char *) &ch; debug_printf ("bottom %p, top %p, stack %p, size %d, reserve %d", - ch.stackbottom, ch.stacktop, &m, ch.stacksize, - (DWORD) ch.stackbottom - (DWORD) ch.stacktop); + ch->stackbottom, ch->stacktop, &ch, ch->stacksize, + (char *) ch->stackbottom - (char *) ch->stacktop); } /* Copy memory from parent to child. @@ -153,9 +161,10 @@ sync_with_parent (const char *s, bool hang_self) } } -static int __stdcall -fork_child (HANDLE& hParent, dll *&first_dll, bool& load_dlls) +int __stdcall +frok::child (void *) { + HANDLE& hParent = ch.parent; extern void fixup_hooks_after_fork (); extern void fixup_timers_after_fork (); debug_printf ("child is running. pid %d, ppid %d, stack here %p", @@ -247,6 +256,7 @@ fork_child (HANDLE& hParent, dll *&first_dll, bool& load_dlls) return 0; } +#define NO_SLOW_PID_REUSE #ifndef NO_SLOW_PID_REUSE static void slow_pid_reuse (HANDLE h) @@ -274,12 +284,17 @@ slow_pid_reuse (HANDLE h) } #endif -static int __stdcall -fork_parent (HANDLE&, dll *&first_dll, bool& load_dlls, void *stack_here, child_info_fork &ch) +int __stdcall +frok::parent (void *stack_here) { HANDLE forker_finished; DWORD rc; PROCESS_INFORMATION pi = {0, NULL, 0, 0}; + child_pid = -1; + error = NULL; + this_errno = 0; + bool fix_impersonation = false; + pinfo child; pthread::atforkprepare (); @@ -318,7 +333,8 @@ fork_parent (HANDLE&, dll *&first_dll, bool& load_dlls, void *stack_here, child_ forker_finished = CreateEvent (&sec_all, FALSE, FALSE, NULL); if (forker_finished == NULL) { - system_printf ("unable to allocate forker_finished event, %E"); + this_errno = geterrno_from_win_error (); + error = "child %d - unable to allocate forker_finished event, %E"; return -1; } @@ -326,7 +342,7 @@ fork_parent (HANDLE&, dll *&first_dll, bool& load_dlls, void *stack_here, child_ ch.forker_finished = forker_finished; - stack_base (ch); + stack_base (&ch); si.cb = sizeof (STARTUPINFO); si.lpReserved2 = (LPBYTE) &ch; @@ -334,6 +350,7 @@ fork_parent (HANDLE&, dll *&first_dll, bool& load_dlls, void *stack_here, child_ /* Remove impersonation */ cygheap->user.deimpersonate (); + fix_impersonation = true; syscall_printf ("CreateProcess (%s, %s, 0, 0, 1, %p, 0, 0, %p, %p)", myself->progname, myself->progname, c_flags, &si, &pi); @@ -351,15 +368,12 @@ fork_parent (HANDLE&, dll *&first_dll, bool& load_dlls, void *stack_here, child_ if (!rc) { - __seterrno (); - syscall_printf ("CreateProcessA failed, %E"); - ForceCloseHandle (forker_finished); - /* Restore impersonation */ - cygheap->user.reimpersonate (); - __malloc_unlock (); - return -1; + this_errno = geterrno_from_win_error (); + error = "child %d - CreateProcessA failed, %E"; + goto cleanup; } + /* Fixup the parent datastructure if needed and resume the child's main thread. */ if (cygheap->fdtab.need_fixup_before ()) @@ -368,14 +382,17 @@ fork_parent (HANDLE&, dll *&first_dll, bool& load_dlls, void *stack_here, child_ ResumeThread (pi.hThread); } - int child_pid = cygwin_pid (pi.dwProcessId); - pinfo child (child_pid, 1); + child_pid = cygwin_pid (pi.dwProcessId); + child.init (child_pid, 1, NULL); if (!child) { + this_errno = get_errno () == ENOMEM ? ENOMEM : EAGAIN; +#ifdef DEBUGGING + error = "child %d - pinfo failed"; +#else syscall_printf ("pinfo failed"); - if (get_errno () != ENOMEM) - set_errno (EAGAIN); +#endif goto cleanup; } @@ -388,6 +405,7 @@ fork_parent (HANDLE&, dll *&first_dll, bool& load_dlls, void *stack_here, child_ /* Restore impersonation */ cygheap->user.reimpersonate (); + fix_impersonation = false; ProtectHandle (pi.hThread); /* Protect the handle but name it similarly to the way it will @@ -406,7 +424,10 @@ fork_parent (HANDLE&, dll *&first_dll, bool& load_dlls, void *stack_here, child_ if (!child.remember (false)) { TerminateProcess (pi.hProcess, 1); - set_errno (EAGAIN); + this_errno = EAGAIN; +#ifdef DEBUGGING + error = "child %d - child.remember failed"; +#endif goto cleanup; } @@ -417,8 +438,8 @@ fork_parent (HANDLE&, dll *&first_dll, bool& load_dlls, void *stack_here, child_ /* Wait for subproc to initialize itself. */ if (!ch.sync (child->pid, pi.hProcess, FORK_WAIT_TIMEOUT)) { - if (NOTSTATE (child, PID_EXITED)) - system_printf ("child %d died waiting for longjmp before initialization", child_pid); + this_errno = EAGAIN; + error = "child %d - died waiting for longjmp before initialization"; goto cleanup; } @@ -461,7 +482,13 @@ fork_parent (HANDLE&, dll *&first_dll, bool& load_dlls, void *stack_here, child_ if (!fork_copy (pi, "linked dll data/bss", d->p.data_start, d->p.data_end, d->p.bss_start, d->p.bss_end, NULL)) - goto cleanup; + { + this_errno = get_errno (); +#ifdef DEBUGGING + error = "child %d - fork_copy for linked dll data/bss failed"; +#endif + goto cleanup; + } } /* Start thread, and wait for it to reload dlls. */ @@ -469,8 +496,8 @@ fork_parent (HANDLE&, dll *&first_dll, bool& load_dlls, void *stack_here, child_ goto cleanup; else if (!ch.sync (child->pid, pi.hProcess, FORK_WAIT_TIMEOUT)) { - if (NOTSTATE (child, PID_EXITED)) - system_printf ("child %d died waiting for dll loading", child_pid); + this_errno = EAGAIN; + error = "child %d died waiting for dll loading"; goto cleanup; } @@ -487,7 +514,13 @@ fork_parent (HANDLE&, dll *&first_dll, bool& load_dlls, void *stack_here, child_ if (!fork_copy (pi, "loaded dll data/bss", d->p.data_start, d->p.data_end, d->p.bss_start, d->p.bss_end, NULL)) - goto cleanup; + { + this_errno = get_errno (); +#ifdef DEBUGGING + error = "child %d - copying data/bss for a loaded dll"; +#endif + goto cleanup; + } } /* Start the child up again. */ resume_child (forker_finished); @@ -502,7 +535,9 @@ fork_parent (HANDLE&, dll *&first_dll, bool& load_dlls, void *stack_here, child_ return child_pid; /* Common cleanup code for failure cases */ - cleanup: +cleanup: + if (fix_impersonation) + cygheap->user.reimpersonate (); if (locked) __malloc_unlock (); @@ -513,19 +548,14 @@ fork_parent (HANDLE&, dll *&first_dll, bool& load_dlls, void *stack_here, child_ ForceCloseHandle (pi.hThread); if (forker_finished) ForceCloseHandle (forker_finished); + debug_printf ("returning -1"); return -1; } extern "C" int fork () { - struct - { - dll *first_dll; - bool load_dlls; - child_info_fork ch; - } grouped; - + frok grouped; MALLOC_CHECK; debug_printf ("entering"); @@ -546,15 +576,26 @@ fork () } sig_send (NULL, __SIGHOLD); - int res = setjmp (grouped.ch.jmp); - if (res) - res = fork_child (grouped.ch.parent, grouped.first_dll, grouped.load_dlls); + int res; + int ischild = setjmp (grouped.ch.jmp); + if (!ischild) + res = grouped.parent (esp); else - res = fork_parent (grouped.ch.parent, grouped.first_dll, grouped.load_dlls, esp, grouped.ch); - sig_send (NULL, __SIGNOHOLD); + res = grouped.child (esp); MALLOC_CHECK; + if (ischild || res > 0) + /* everything is ok */; + else + { + if (!grouped.error) + syscall_printf ("fork failed - child pid %d", grouped.child_pid); + else + system_printf (grouped.error, grouped.child_pid); + set_errno (grouped.this_errno); + } syscall_printf ("%d = fork()", res); + sig_send (NULL, __SIGNOHOLD); return res; } #ifdef DEBUGGING diff --git a/winsup/cygwin/init.cc b/winsup/cygwin/init.cc index 96dda7c1e..655d89160 100644 --- a/winsup/cygwin/init.cc +++ b/winsup/cygwin/init.cc @@ -148,7 +148,6 @@ dll_entry (HANDLE h, DWORD reason, void *static_load) case DLL_PROCESS_ATTACH: cygwin_hmodule = (HMODULE) h; dynamically_loaded = (static_load == NULL); - init_console_handler (TRUE); /* Is the stack at an unusual address? This is, an address which is in the usual space occupied by the process image, but below