* winsup.h (child_copy): Change prototype to match new functionality.
* cygheap.cc (cygheap_fixup_in_child): Accommodate new child_copy arguments. * dcrt0.cc (dll_data_start): Move definition here from fork. (dll_data_end): Ditto. (dll_bss_start): Ditto. (dll_bss_end): Ditto. (handle_fork): New function. Called when forked to deal with fork issues and copy data to this process from the parent. (dll_crt0_0): Call handle_fork when _PROC_FORK condition. (dll_crt0): Don't copy user_data when we've forked. Don't zero first element of main_environment ever. (cygwin_dll_init): Ditto. * fork.cc (child_copy): Rename from fork_copy and change arguments so that each pair of things to copy gets its own descriptor. (frok::child): Remove fixup_mmaps_after_fork call here. Move to handle_fork in dcrt0.cc. (frok::parent): Use child_copy rather than fork_copy and accommodate changes in parameters. * exceptions.cc (setup_handler): Delay test of whether we're locked until after GetThreadContext has been called since there are apparently cases where SuspendThread does not cause an immediate thread suspension.
This commit is contained in:
parent
a249fd1c9b
commit
ad02bb70e3
@ -1,3 +1,30 @@
|
||||
2005-12-16 Christopher Faylor <cgf@timesys.com>
|
||||
|
||||
* winsup.h (child_copy): Change prototype to match new functionality.
|
||||
* cygheap.cc (cygheap_fixup_in_child): Accommodate new child_copy
|
||||
arguments.
|
||||
* dcrt0.cc (dll_data_start): Move definition here from fork.
|
||||
(dll_data_end): Ditto.
|
||||
(dll_bss_start): Ditto.
|
||||
(dll_bss_end): Ditto.
|
||||
(handle_fork): New function. Called when forked to deal with fork
|
||||
issues and copy data to this process from the parent.
|
||||
(dll_crt0_0): Call handle_fork when _PROC_FORK condition.
|
||||
(dll_crt0): Don't copy user_data when we've forked. Don't zero first
|
||||
element of main_environment ever.
|
||||
(cygwin_dll_init): Ditto.
|
||||
* fork.cc (child_copy): Rename from fork_copy and change arguments so
|
||||
that each pair of things to copy gets its own descriptor.
|
||||
(frok::child): Remove fixup_mmaps_after_fork call here. Move to
|
||||
handle_fork in dcrt0.cc.
|
||||
(frok::parent): Use child_copy rather than fork_copy and accommodate
|
||||
changes in parameters.
|
||||
|
||||
* exceptions.cc (setup_handler): Delay test of whether we're locked
|
||||
until after GetThreadContext has been called since there are apparently
|
||||
cases where SuspendThread does not cause an immediate thread
|
||||
suspension.
|
||||
|
||||
2005-12-16 Christopher Faylor <cgf@timesys.com>
|
||||
|
||||
* init.cc (dll_entry): Call prime_threads after dll_crt0_0 to avoid
|
||||
|
@ -59,7 +59,7 @@ cygheap_fixup_in_child (bool execed)
|
||||
cygheap_max = child_proc_info->cygheap;
|
||||
cygheap = (init_cygheap *) cygheap_max;
|
||||
_csbrk ((char *) child_proc_info->cygheap_max - (char *) cygheap);
|
||||
child_copy (child_proc_info->parent, child_proc_info->dwProcessId, "cygheap", cygheap, cygheap_max);
|
||||
child_copy (child_proc_info->parent, false, "cygheap", cygheap, cygheap_max, NULL);
|
||||
cygheap_init ();
|
||||
debug_fixup_after_fork_exec ();
|
||||
|
||||
|
@ -635,6 +635,35 @@ get_cygwin_startup_info ()
|
||||
return res;
|
||||
}
|
||||
|
||||
#define dll_data_start &_data_start__
|
||||
#define dll_data_end &_data_end__
|
||||
#define dll_bss_start &_bss_start__
|
||||
#define dll_bss_end &_bss_end__
|
||||
|
||||
void
|
||||
handle_fork ()
|
||||
{
|
||||
alloc_stack (fork_info);
|
||||
cygheap_fixup_in_child (false);
|
||||
memory_init ();
|
||||
set_myself (NULL);
|
||||
HANDLE hp = fork_info->parent;
|
||||
child_copy (hp, false,
|
||||
"dll data", dll_data_start, dll_data_end,
|
||||
"dll bss", dll_bss_start, dll_bss_end,
|
||||
"user heap", cygheap->user_heap.base, cygheap->user_heap.ptr,
|
||||
NULL);
|
||||
/* step 2 now that the dll has its heap filled in, we can fill in the
|
||||
user's data and bss since user_data is now filled out. */
|
||||
child_copy (hp, false,
|
||||
"data", user_data->data_start, user_data->data_end,
|
||||
"bss", user_data->bss_start, user_data->bss_end,
|
||||
NULL);
|
||||
|
||||
if (fixup_mmaps_after_fork (hp))
|
||||
api_fatal ("recreate_mmaps_after_fork_failed");
|
||||
}
|
||||
|
||||
void __stdcall
|
||||
dll_crt0_0 ()
|
||||
{
|
||||
@ -675,10 +704,7 @@ dll_crt0_0 ()
|
||||
switch (child_proc_info->type)
|
||||
{
|
||||
case _PROC_FORK:
|
||||
alloc_stack (fork_info);
|
||||
cygheap_fixup_in_child (false);
|
||||
memory_init ();
|
||||
set_myself (NULL);
|
||||
handle_fork ();
|
||||
break;
|
||||
case _PROC_SPAWN:
|
||||
case _PROC_EXEC:
|
||||
@ -937,7 +963,9 @@ _dll_crt0 ()
|
||||
system_printf ("internal error: couldn't determine location of thread function on stack. Expect signal problems.");
|
||||
|
||||
main_environ = user_data->envptr;
|
||||
#if 0
|
||||
*main_environ = NULL;
|
||||
#endif
|
||||
|
||||
char padding[CYGTLS_PADSIZE];
|
||||
|
||||
@ -954,7 +982,7 @@ void
|
||||
dll_crt0 (per_process *uptr)
|
||||
{
|
||||
/* Set the local copy of the pointer into the user space. */
|
||||
if (uptr && uptr != user_data)
|
||||
if (!user_data->forkee && uptr && uptr != user_data)
|
||||
{
|
||||
memcpy (user_data, uptr, per_process_overwrite);
|
||||
*(user_data->impure_ptr_ptr) = _GLOBAL_REENT;
|
||||
@ -989,7 +1017,9 @@ cygwin_dll_init ()
|
||||
user_data->fmode_ptr = &_fmode;
|
||||
|
||||
main_environ = user_data->envptr;
|
||||
#if 0
|
||||
*main_environ = NULL;
|
||||
#endif
|
||||
initialize_main_tls((char *)&_my_tls);
|
||||
dll_crt0_1 (NULL);
|
||||
}
|
||||
|
@ -786,17 +786,12 @@ setup_handler (int sig, void *handler, struct sigaction& siga, _cygtls *tls)
|
||||
ResumeThread (hth);
|
||||
break;
|
||||
}
|
||||
if (tls->incyg || tls->spinning || tls->locked ())
|
||||
sigproc_printf ("incyg %d, spinning %d, locked %d\n",
|
||||
tls->incyg, tls->spinning, tls->locked ());
|
||||
else
|
||||
{
|
||||
cx.ContextFlags = CONTEXT_CONTROL | CONTEXT_INTEGER;
|
||||
if (!GetThreadContext (hth, &cx))
|
||||
system_printf ("couldn't get context of main thread, %E");
|
||||
else if (interruptible (cx.Eip))
|
||||
interrupted = tls->interrupt_now (&cx, sig, handler, siga);
|
||||
}
|
||||
cx.ContextFlags = CONTEXT_CONTROL | CONTEXT_INTEGER;
|
||||
if (!GetThreadContext (hth, &cx))
|
||||
system_printf ("couldn't get context of main thread, %E");
|
||||
else if (interruptible (cx.Eip) &&
|
||||
!(tls->incyg || tls->spinning || tls->locked ()))
|
||||
interrupted = tls->interrupt_now (&cx, sig, handler, siga);
|
||||
|
||||
res = ResumeThread (hth);
|
||||
if (interrupted)
|
||||
|
@ -37,11 +37,6 @@ details. */
|
||||
/* FIXME: Once things stabilize, bump up to a few minutes. */
|
||||
#define FORK_WAIT_TIMEOUT (300 * 1000) /* 300 seconds */
|
||||
|
||||
#define dll_data_start &_data_start__
|
||||
#define dll_data_end &_data_end__
|
||||
#define dll_bss_start &_bss_start__
|
||||
#define dll_bss_end &_bss_end__
|
||||
|
||||
class frok
|
||||
{
|
||||
dll *first_dll;
|
||||
@ -55,60 +50,6 @@ class frok
|
||||
friend int fork ();
|
||||
};
|
||||
|
||||
/* Copy memory from parent to child.
|
||||
The result is a boolean indicating success. */
|
||||
|
||||
static int
|
||||
fork_copy (PROCESS_INFORMATION& pi, const char *what, ...)
|
||||
{
|
||||
va_list args;
|
||||
char *low;
|
||||
int pass = 0;
|
||||
|
||||
va_start (args, what);
|
||||
|
||||
while ((low = va_arg (args, char *)))
|
||||
{
|
||||
char *high = va_arg (args, char *);
|
||||
DWORD todo = wincap.chunksize () ?: high - low;
|
||||
char *here;
|
||||
|
||||
for (here = low; here < high; here += todo)
|
||||
{
|
||||
DWORD done = 0;
|
||||
if (here + todo > high)
|
||||
todo = high - here;
|
||||
int res;
|
||||
if (pi.hThread)
|
||||
res = WriteProcessMemory (pi.hProcess, here, here, todo, &done);
|
||||
else
|
||||
res = ReadProcessMemory (pi.hProcess, here, here, todo, &done);
|
||||
debug_printf ("child handle %p, low %p, high %p, res %d", pi.hProcess,
|
||||
low, high, res);
|
||||
if (!res || todo != done)
|
||||
{
|
||||
if (!res)
|
||||
__seterrno ();
|
||||
/* If this happens then there is a bug in our fork
|
||||
implementation somewhere. */
|
||||
system_printf ("%s pass %d failed, %p..%p, done %d, windows pid %u, %E",
|
||||
what, pass, low, high, done, pi.dwProcessId);
|
||||
goto err;
|
||||
}
|
||||
}
|
||||
|
||||
pass++;
|
||||
}
|
||||
|
||||
debug_printf ("done");
|
||||
return 1;
|
||||
|
||||
err:
|
||||
TerminateProcess (pi.hProcess, 1);
|
||||
set_errno (EAGAIN);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int
|
||||
resume_child (HANDLE forker_finished)
|
||||
{
|
||||
@ -198,9 +139,6 @@ frok::child (void *)
|
||||
|
||||
MALLOC_CHECK;
|
||||
|
||||
if (fixup_mmaps_after_fork (hParent))
|
||||
api_fatal ("recreate_mmaps_after_fork_failed");
|
||||
|
||||
#ifdef USE_SERVER
|
||||
/* Incredible but true: If we use sockets and SYSV IPC shared memory,
|
||||
there's a good chance that a duplicated socket in the child occupies
|
||||
@ -367,7 +305,6 @@ frok::parent (void *stack_here)
|
||||
goto cleanup;
|
||||
}
|
||||
|
||||
|
||||
/* Fixup the parent datastructure if needed and resume the child's
|
||||
main thread. */
|
||||
if (cygheap->fdtab.need_fixup_before ())
|
||||
@ -446,22 +383,21 @@ frok::parent (void *stack_here)
|
||||
|
||||
|
||||
MALLOC_CHECK;
|
||||
void *impure_beg;
|
||||
void *impure_end;
|
||||
const void *impure_beg;
|
||||
const void *impure_end;
|
||||
const char *impure;
|
||||
if (&_my_tls == _main_tls)
|
||||
impure_beg = impure_end = NULL;
|
||||
impure_beg = impure_end = impure = NULL;
|
||||
else
|
||||
{
|
||||
impure = "impure";
|
||||
impure_beg = _impure_ptr;
|
||||
impure_end = _impure_ptr + 1;
|
||||
}
|
||||
rc = fork_copy (pi, "user/cygwin data",
|
||||
user_data->data_start, user_data->data_end,
|
||||
user_data->bss_start, user_data->bss_end,
|
||||
cygheap->user_heap.base, cygheap->user_heap.ptr,
|
||||
stack_here, ch.stackbottom,
|
||||
dll_data_start, dll_data_end,
|
||||
dll_bss_start, dll_bss_end, impure_beg, impure_end, NULL);
|
||||
rc = child_copy (pi.hProcess, true,
|
||||
"stack", stack_here, ch.stackbottom,
|
||||
impure, impure_beg, impure_end,
|
||||
NULL);
|
||||
|
||||
__malloc_unlock ();
|
||||
locked = false;
|
||||
@ -473,9 +409,10 @@ frok::parent (void *stack_here)
|
||||
for (dll *d = dlls.istart (DLL_LINK); d; d = dlls.inext ())
|
||||
{
|
||||
debug_printf ("copying data/bss of a linked dll");
|
||||
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))
|
||||
if (!child_copy (pi.hProcess, true,
|
||||
"linked dll data", d->p.data_start, d->p.data_end,
|
||||
"linked dll bss", d->p.bss_start, d->p.bss_end,
|
||||
NULL))
|
||||
{
|
||||
this_errno = get_errno ();
|
||||
#ifdef DEBUGGING
|
||||
@ -505,9 +442,10 @@ frok::parent (void *stack_here)
|
||||
for (dll *d = dlls.istart (DLL_LOAD); d; d = dlls.inext ())
|
||||
{
|
||||
debug_printf ("copying data/bss for a loaded dll");
|
||||
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))
|
||||
if (!child_copy (pi.hProcess, true,
|
||||
"loaded dll data", d->p.data_start, d->p.data_end,
|
||||
"loaded dll bss", d->p.bss_start, d->p.bss_end,
|
||||
NULL))
|
||||
{
|
||||
this_errno = get_errno ();
|
||||
#ifdef DEBUGGING
|
||||
@ -690,13 +628,52 @@ vfork ()
|
||||
#endif
|
||||
}
|
||||
|
||||
int
|
||||
child_copy (HANDLE h, DWORD pid, const char *what, void *child_start, void *child_end)
|
||||
/* Copy memory from one process to another. */
|
||||
|
||||
bool
|
||||
child_copy (HANDLE hp, bool write, ...)
|
||||
{
|
||||
PROCESS_INFORMATION pi;
|
||||
pi.hProcess = h;
|
||||
pi.dwProcessId = pid;
|
||||
pi.hThread = NULL;
|
||||
debug_printf ("%s, start %p, end %p", what, child_start, child_end);
|
||||
return fork_copy (pi, what, child_start, child_end, NULL);
|
||||
va_list args;
|
||||
va_start (args, write);
|
||||
static const char *huh[] = {"read", "write"};
|
||||
|
||||
char *what;
|
||||
while ((what = va_arg (args, char *)))
|
||||
{
|
||||
char *low = va_arg (args, char *);
|
||||
char *high = va_arg (args, char *);
|
||||
DWORD todo = wincap.chunksize () ?: high - low;
|
||||
char *here;
|
||||
|
||||
for (here = low; here < high; here += todo)
|
||||
{
|
||||
DWORD done = 0;
|
||||
if (here + todo > high)
|
||||
todo = high - here;
|
||||
int res;
|
||||
if (write)
|
||||
res = WriteProcessMemory (hp, here, here, todo, &done);
|
||||
else
|
||||
res = ReadProcessMemory (hp, here, here, todo, &done);
|
||||
debug_printf ("hp %p, low %p, high %p, res %d", hp, low, high, res);
|
||||
if (!res || todo != done)
|
||||
{
|
||||
if (!res)
|
||||
__seterrno ();
|
||||
/* If this happens then there is a bug in our fork
|
||||
implementation somewhere. */
|
||||
system_printf ("%s %s copy failed, %p..%p, done %d, windows pid %u, %E",
|
||||
what, huh[write], low, high, done);
|
||||
goto err;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
debug_printf ("done");
|
||||
return true;
|
||||
|
||||
err:
|
||||
TerminateProcess (hp, 1);
|
||||
set_errno (EAGAIN);
|
||||
return false;
|
||||
}
|
||||
|
@ -284,7 +284,7 @@ extern void multiple_cygwin_problem (const char *, unsigned, unsigned);
|
||||
|
||||
extern "C" void vklog (int priority, const char *message, va_list ap);
|
||||
extern "C" void klog (int priority, const char *message, ...);
|
||||
int child_copy (HANDLE, DWORD, const char *, void *, void *);
|
||||
bool child_copy (HANDLE, bool, ...);
|
||||
|
||||
int symlink_worker (const char *, const char *, bool, bool)
|
||||
__attribute__ ((regparm (3)));
|
||||
|
Loading…
x
Reference in New Issue
Block a user