* 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.
This commit is contained in:
Christopher Faylor 2005-09-28 15:18:49 +00:00
parent 9edadc960e
commit 280fdd0b67
4 changed files with 131 additions and 64 deletions

View File

@ -1,3 +1,22 @@
2005-09-28 Christopher Faylor <cgf@timesys.com>
* 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 <cgf@timesys.com> 2005-09-28 Christopher Faylor <cgf@timesys.com>
* pinfo.cc (_pinfo::dup_proc_pipe): Ignore error if the child process * pinfo.cc (_pinfo::dup_proc_pipe): Ignore error if the child process

View File

@ -502,22 +502,29 @@ alloc_stack_hard_way (child_info_fork *ci, volatile char *b)
b[0] = '\0'; 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 */ /* extend the stack prior to fork longjmp */
static void static void
alloc_stack (child_info_fork *ci) alloc_stack (child_info_fork *ci)
{ {
/* FIXME: adding 16384 seems to avoid a stack copy problem during volatile char *esp;
fork on Win95, but I don't know exactly why yet. DJ */ __asm__ volatile ("movl %%esp,%0": "=r" (esp));
volatile char b[ci->stacksize + 16384]; if (_tlsbase != ci->stackbottom)
alloc_stack_hard_way (ci, esp);
if (!VirtualQuery ((LPCVOID) &b, &sm, sizeof sm))
api_fatal ("fork: couldn't get stack info, %E");
if (sm.AllocationBase == ci->stacktop)
ci->stacksize = 0;
else else
alloc_stack_hard_way (ci, b + sizeof (b) - 1); {
while (_tlstop > ci->stacktop)
esp = getstack (esp);
ci->stacksize = 0;
}
} }
#ifdef DEBUGGING #ifdef DEBUGGING
@ -629,6 +636,12 @@ get_cygwin_startup_info ()
void __stdcall void __stdcall
dll_crt0_0 () 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 (); wincap.init ();
initial_env (); initial_env ();
@ -931,11 +944,6 @@ _dll_crt0 ()
*main_environ = NULL; *main_environ = NULL;
char padding[CYGTLS_PADSIZE]; 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) if (child_proc_info && child_proc_info->type == _PROC_FORK)
user_data->forkee = true; user_data->forkee = true;

View File

@ -42,20 +42,28 @@ details. */
#define dll_bss_start &_bss_start__ #define dll_bss_start &_bss_start__
#define dll_bss_end &_bss_end__ #define dll_bss_end &_bss_end__
static void class frok
stack_base (child_info_fork &ch)
{ {
MEMORY_BASIC_INFORMATION m; dll *first_dll;
memset (&m, 0, sizeof m); bool load_dlls;
if (!VirtualQuery ((LPCVOID) &m, &m, sizeof m)) child_info_fork ch;
system_printf ("couldn't get memory info, %E"); 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; static void
ch.stackbottom = (LPBYTE) m.BaseAddress + m.RegionSize; stack_base (child_info_fork *ch)
ch.stacksize = (DWORD) ch.stackbottom - (DWORD) &m; {
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", debug_printf ("bottom %p, top %p, stack %p, size %d, reserve %d",
ch.stackbottom, ch.stacktop, &m, ch.stacksize, ch->stackbottom, ch->stacktop, &ch, ch->stacksize,
(DWORD) ch.stackbottom - (DWORD) ch.stacktop); (char *) ch->stackbottom - (char *) ch->stacktop);
} }
/* Copy memory from parent to child. /* Copy memory from parent to child.
@ -153,9 +161,10 @@ sync_with_parent (const char *s, bool hang_self)
} }
} }
static int __stdcall int __stdcall
fork_child (HANDLE& hParent, dll *&first_dll, bool& load_dlls) frok::child (void *)
{ {
HANDLE& hParent = ch.parent;
extern void fixup_hooks_after_fork (); extern void fixup_hooks_after_fork ();
extern void fixup_timers_after_fork (); extern void fixup_timers_after_fork ();
debug_printf ("child is running. pid %d, ppid %d, stack here %p", 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; return 0;
} }
#define NO_SLOW_PID_REUSE
#ifndef NO_SLOW_PID_REUSE #ifndef NO_SLOW_PID_REUSE
static void static void
slow_pid_reuse (HANDLE h) slow_pid_reuse (HANDLE h)
@ -274,12 +284,17 @@ slow_pid_reuse (HANDLE h)
} }
#endif #endif
static int __stdcall int __stdcall
fork_parent (HANDLE&, dll *&first_dll, bool& load_dlls, void *stack_here, child_info_fork &ch) frok::parent (void *stack_here)
{ {
HANDLE forker_finished; HANDLE forker_finished;
DWORD rc; DWORD rc;
PROCESS_INFORMATION pi = {0, NULL, 0, 0}; PROCESS_INFORMATION pi = {0, NULL, 0, 0};
child_pid = -1;
error = NULL;
this_errno = 0;
bool fix_impersonation = false;
pinfo child;
pthread::atforkprepare (); 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); forker_finished = CreateEvent (&sec_all, FALSE, FALSE, NULL);
if (forker_finished == 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; return -1;
} }
@ -326,7 +342,7 @@ fork_parent (HANDLE&, dll *&first_dll, bool& load_dlls, void *stack_here, child_
ch.forker_finished = forker_finished; ch.forker_finished = forker_finished;
stack_base (ch); stack_base (&ch);
si.cb = sizeof (STARTUPINFO); si.cb = sizeof (STARTUPINFO);
si.lpReserved2 = (LPBYTE) &ch; si.lpReserved2 = (LPBYTE) &ch;
@ -334,6 +350,7 @@ fork_parent (HANDLE&, dll *&first_dll, bool& load_dlls, void *stack_here, child_
/* Remove impersonation */ /* Remove impersonation */
cygheap->user.deimpersonate (); cygheap->user.deimpersonate ();
fix_impersonation = true;
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);
@ -351,15 +368,12 @@ fork_parent (HANDLE&, dll *&first_dll, bool& load_dlls, void *stack_here, child_
if (!rc) if (!rc)
{ {
__seterrno (); this_errno = geterrno_from_win_error ();
syscall_printf ("CreateProcessA failed, %E"); error = "child %d - CreateProcessA failed, %E";
ForceCloseHandle (forker_finished); goto cleanup;
/* Restore impersonation */
cygheap->user.reimpersonate ();
__malloc_unlock ();
return -1;
} }
/* Fixup the parent datastructure if needed and resume the child's /* Fixup the parent datastructure if needed and resume the child's
main thread. */ main thread. */
if (cygheap->fdtab.need_fixup_before ()) 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); ResumeThread (pi.hThread);
} }
int child_pid = cygwin_pid (pi.dwProcessId); child_pid = cygwin_pid (pi.dwProcessId);
pinfo child (child_pid, 1); child.init (child_pid, 1, NULL);
if (!child) if (!child)
{ {
this_errno = get_errno () == ENOMEM ? ENOMEM : EAGAIN;
#ifdef DEBUGGING
error = "child %d - pinfo failed";
#else
syscall_printf ("pinfo failed"); syscall_printf ("pinfo failed");
if (get_errno () != ENOMEM) #endif
set_errno (EAGAIN);
goto cleanup; goto cleanup;
} }
@ -388,6 +405,7 @@ fork_parent (HANDLE&, dll *&first_dll, bool& load_dlls, void *stack_here, child_
/* Restore impersonation */ /* Restore impersonation */
cygheap->user.reimpersonate (); cygheap->user.reimpersonate ();
fix_impersonation = false;
ProtectHandle (pi.hThread); ProtectHandle (pi.hThread);
/* Protect the handle but name it similarly to the way it will /* 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)) if (!child.remember (false))
{ {
TerminateProcess (pi.hProcess, 1); TerminateProcess (pi.hProcess, 1);
set_errno (EAGAIN); this_errno = EAGAIN;
#ifdef DEBUGGING
error = "child %d - child.remember failed";
#endif
goto cleanup; 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. */ /* Wait for subproc to initialize itself. */
if (!ch.sync (child->pid, pi.hProcess, FORK_WAIT_TIMEOUT)) if (!ch.sync (child->pid, pi.hProcess, FORK_WAIT_TIMEOUT))
{ {
if (NOTSTATE (child, PID_EXITED)) this_errno = EAGAIN;
system_printf ("child %d died waiting for longjmp before initialization", child_pid); error = "child %d - died waiting for longjmp before initialization";
goto cleanup; 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, if (!fork_copy (pi, "linked dll data/bss", d->p.data_start, d->p.data_end,
d->p.bss_start, d->p.bss_end, d->p.bss_start, d->p.bss_end,
NULL)) 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. */ /* 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; goto cleanup;
else if (!ch.sync (child->pid, pi.hProcess, FORK_WAIT_TIMEOUT)) else if (!ch.sync (child->pid, pi.hProcess, FORK_WAIT_TIMEOUT))
{ {
if (NOTSTATE (child, PID_EXITED)) this_errno = EAGAIN;
system_printf ("child %d died waiting for dll loading", child_pid); error = "child %d died waiting for dll loading";
goto cleanup; 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, if (!fork_copy (pi, "loaded dll data/bss", d->p.data_start, d->p.data_end,
d->p.bss_start, d->p.bss_end, d->p.bss_start, d->p.bss_end,
NULL)) 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. */ /* Start the child up again. */
resume_child (forker_finished); resume_child (forker_finished);
@ -502,7 +535,9 @@ fork_parent (HANDLE&, dll *&first_dll, bool& load_dlls, void *stack_here, child_
return child_pid; return child_pid;
/* Common cleanup code for failure cases */ /* Common cleanup code for failure cases */
cleanup: cleanup:
if (fix_impersonation)
cygheap->user.reimpersonate ();
if (locked) if (locked)
__malloc_unlock (); __malloc_unlock ();
@ -513,19 +548,14 @@ fork_parent (HANDLE&, dll *&first_dll, bool& load_dlls, void *stack_here, child_
ForceCloseHandle (pi.hThread); ForceCloseHandle (pi.hThread);
if (forker_finished) if (forker_finished)
ForceCloseHandle (forker_finished); ForceCloseHandle (forker_finished);
debug_printf ("returning -1");
return -1; return -1;
} }
extern "C" int extern "C" int
fork () fork ()
{ {
struct frok grouped;
{
dll *first_dll;
bool load_dlls;
child_info_fork ch;
} grouped;
MALLOC_CHECK; MALLOC_CHECK;
debug_printf ("entering"); debug_printf ("entering");
@ -546,15 +576,26 @@ fork ()
} }
sig_send (NULL, __SIGHOLD); sig_send (NULL, __SIGHOLD);
int res = setjmp (grouped.ch.jmp); int res;
if (res) int ischild = setjmp (grouped.ch.jmp);
res = fork_child (grouped.ch.parent, grouped.first_dll, grouped.load_dlls); if (!ischild)
res = grouped.parent (esp);
else else
res = fork_parent (grouped.ch.parent, grouped.first_dll, grouped.load_dlls, esp, grouped.ch); res = grouped.child (esp);
sig_send (NULL, __SIGNOHOLD);
MALLOC_CHECK; 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); syscall_printf ("%d = fork()", res);
sig_send (NULL, __SIGNOHOLD);
return res; return res;
} }
#ifdef DEBUGGING #ifdef DEBUGGING

View File

@ -148,7 +148,6 @@ dll_entry (HANDLE h, DWORD reason, void *static_load)
case DLL_PROCESS_ATTACH: case DLL_PROCESS_ATTACH:
cygwin_hmodule = (HMODULE) h; cygwin_hmodule = (HMODULE) h;
dynamically_loaded = (static_load == NULL); dynamically_loaded = (static_load == NULL);
init_console_handler (TRUE);
/* Is the stack at an unusual address? This is, an address which /* Is the stack at an unusual address? This is, an address which
is in the usual space occupied by the process image, but below is in the usual space occupied by the process image, but below