* child_info: Bump child_info "version".
(child_info): Move some fields from child_info_spawn to here. * cygheap.cc: Make cygheap pointers NOCOPY. * dcrt0.cc (dll_crt0_1): Copy cygwin heap here regardless of whether we've been forked or execed. * dtable.cc (dtable::fixup_after_fork): Just release close-on-exec fds. * exceptions.cc (stackdump): Respond to C warning. * fork.cc: Reorganize to minimize stack copying. (fork_child): New function. (fork_parent): Ditto. (sync_with_child): Don't suspend the forkee. (sync_with_parent): Ditto. Make into a function. * heap.cc (heap_init): Add some debugging output. * path.cc (path_conv::check): Add an assertion. (has_suffix): Ditto. * security.cc (get_pw_sid): Defend against NULL. * sigproc.cc (proc_subproc): Fix debugging output. (wait_sig): Ditto. * strace.cc: Make statics NO_COPY throughout. (strace::vsprntf): Defend against NULL.
This commit is contained in:
parent
5e0d760fb8
commit
1ec4f618fe
|
@ -1,3 +1,26 @@
|
||||||
|
Thu Oct 12 17:58:03 2000 Christopher Faylor <cgf@cygnus.com>
|
||||||
|
|
||||||
|
* child_info: Bump child_info "version".
|
||||||
|
(child_info): Move some fields from child_info_spawn to here.
|
||||||
|
* cygheap.cc: Make cygheap pointers NOCOPY.
|
||||||
|
* dcrt0.cc (dll_crt0_1): Copy cygwin heap here regardless of whether
|
||||||
|
we've been forked or execed.
|
||||||
|
* dtable.cc (dtable::fixup_after_fork): Just release close-on-exec fds.
|
||||||
|
* exceptions.cc (stackdump): Respond to C warning.
|
||||||
|
* fork.cc: Reorganize to minimize stack copying.
|
||||||
|
(fork_child): New function.
|
||||||
|
(fork_parent): Ditto.
|
||||||
|
(sync_with_child): Don't suspend the forkee.
|
||||||
|
(sync_with_parent): Ditto. Make into a function.
|
||||||
|
* heap.cc (heap_init): Add some debugging output.
|
||||||
|
* path.cc (path_conv::check): Add an assertion.
|
||||||
|
(has_suffix): Ditto.
|
||||||
|
* security.cc (get_pw_sid): Defend against NULL.
|
||||||
|
* sigproc.cc (proc_subproc): Fix debugging output.
|
||||||
|
(wait_sig): Ditto.
|
||||||
|
* strace.cc: Make statics NO_COPY throughout.
|
||||||
|
(strace::vsprntf): Defend against NULL.
|
||||||
|
|
||||||
Thu Oct 12 00:25:29 2000 Christopher Faylor <cgf@cygnus.com>
|
Thu Oct 12 00:25:29 2000 Christopher Faylor <cgf@cygnus.com>
|
||||||
|
|
||||||
* errno.cc (seterrno_from_win_error): Fix debugging output.
|
* errno.cc (seterrno_from_win_error): Fix debugging output.
|
||||||
|
|
|
@ -12,7 +12,7 @@ details. */
|
||||||
|
|
||||||
enum
|
enum
|
||||||
{
|
{
|
||||||
PROC_MAGIC = 0xaf08f000,
|
PROC_MAGIC = 0xaf09f000,
|
||||||
PROC_FORK = PROC_MAGIC + 1,
|
PROC_FORK = PROC_MAGIC + 1,
|
||||||
PROC_EXEC = PROC_MAGIC + 2,
|
PROC_EXEC = PROC_MAGIC + 2,
|
||||||
PROC_SPAWN = PROC_MAGIC + 3,
|
PROC_SPAWN = PROC_MAGIC + 3,
|
||||||
|
@ -37,6 +37,9 @@ public:
|
||||||
HANDLE shared_h;
|
HANDLE shared_h;
|
||||||
HANDLE console_h;
|
HANDLE console_h;
|
||||||
HANDLE parent_alive; // handle of thread used to track children
|
HANDLE parent_alive; // handle of thread used to track children
|
||||||
|
HANDLE parent;
|
||||||
|
void *cygheap;
|
||||||
|
void *cygheap_max;
|
||||||
};
|
};
|
||||||
|
|
||||||
class child_info_fork: public child_info
|
class child_info_fork: public child_info
|
||||||
|
@ -72,13 +75,9 @@ public:
|
||||||
class child_info_spawn: public child_info
|
class child_info_spawn: public child_info
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
HANDLE parent;
|
|
||||||
void *cygheap;
|
|
||||||
void *cygheap_max;
|
|
||||||
cygheap_exec_info *moreinfo;
|
cygheap_exec_info *moreinfo;
|
||||||
|
|
||||||
child_info_spawn (): parent (NULL), cygheap (NULL),
|
child_info_spawn (): moreinfo (NULL) {}
|
||||||
cygheap_max (NULL), moreinfo (NULL) {}
|
|
||||||
~child_info_spawn ()
|
~child_info_spawn ()
|
||||||
{
|
{
|
||||||
if (parent)
|
if (parent)
|
||||||
|
|
|
@ -18,8 +18,8 @@
|
||||||
#include "cygerrno.h"
|
#include "cygerrno.h"
|
||||||
#include "sync.h"
|
#include "sync.h"
|
||||||
|
|
||||||
void *cygheap = NULL;
|
void NO_COPY *cygheap = NULL;
|
||||||
void *cygheap_max = NULL;
|
void NO_COPY *cygheap_max = NULL;
|
||||||
|
|
||||||
static NO_COPY muto *cygheap_protect = NULL;
|
static NO_COPY muto *cygheap_protect = NULL;
|
||||||
|
|
||||||
|
|
|
@ -662,10 +662,13 @@ dll_crt0_1 ()
|
||||||
|
|
||||||
if (child_proc_info)
|
if (child_proc_info)
|
||||||
{
|
{
|
||||||
|
cygheap = child_proc_info->cygheap;
|
||||||
|
cygheap_max = child_proc_info->cygheap_max;
|
||||||
switch (child_proc_info->type)
|
switch (child_proc_info->type)
|
||||||
{
|
{
|
||||||
case PROC_FORK:
|
case PROC_FORK:
|
||||||
case PROC_FORK1:
|
case PROC_FORK1:
|
||||||
|
cygheap_fixup_in_child (child_proc_info->parent, 0);
|
||||||
alloc_stack (fork_info);
|
alloc_stack (fork_info);
|
||||||
set_myself (mypid);
|
set_myself (mypid);
|
||||||
user_data->forkee = child_proc_info->cygpid;
|
user_data->forkee = child_proc_info->cygpid;
|
||||||
|
@ -677,8 +680,6 @@ dll_crt0_1 ()
|
||||||
case PROC_EXEC:
|
case PROC_EXEC:
|
||||||
case PROC_SPAWN:
|
case PROC_SPAWN:
|
||||||
HANDLE h;
|
HANDLE h;
|
||||||
cygheap = spawn_info->cygheap;
|
|
||||||
cygheap_max = spawn_info->cygheap_max;
|
|
||||||
cygheap_fixup_in_child (spawn_info->parent, 1);
|
cygheap_fixup_in_child (spawn_info->parent, 1);
|
||||||
if (!spawn_info->moreinfo->myself_pinfo ||
|
if (!spawn_info->moreinfo->myself_pinfo ||
|
||||||
!DuplicateHandle (hMainProc, spawn_info->moreinfo->myself_pinfo,
|
!DuplicateHandle (hMainProc, spawn_info->moreinfo->myself_pinfo,
|
||||||
|
|
|
@ -306,6 +306,10 @@ close_handle (const char *func, int ln, HANDLE h, const char *name, BOOL force)
|
||||||
}
|
}
|
||||||
|
|
||||||
unlock_debug ();
|
unlock_debug ();
|
||||||
|
#if 0 /* Uncomment to see CloseHandle failures */
|
||||||
|
if (!ret)
|
||||||
|
small_printf ("CloseHandle(%s) failed %s:%d\n", name, func, ln);
|
||||||
|
#endif
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
#endif /*DEBUGGING*/
|
#endif /*DEBUGGING*/
|
||||||
|
|
|
@ -472,7 +472,9 @@ dtable::fixup_after_fork (HANDLE parent)
|
||||||
for (size_t i = 0; i < size; i++)
|
for (size_t i = 0; i < size; i++)
|
||||||
if ((fh = fds[i]) != NULL)
|
if ((fh = fds[i]) != NULL)
|
||||||
{
|
{
|
||||||
if (fh->get_close_on_exec () || fh->get_need_fork_fixup ())
|
if (fds[i]->get_close_on_exec ())
|
||||||
|
release (i);
|
||||||
|
else if (fh->get_need_fork_fixup ())
|
||||||
{
|
{
|
||||||
debug_printf ("fd %d(%s)", i, fh->get_name ());
|
debug_printf ("fd %d(%s)", i, fh->get_name ());
|
||||||
fh->fixup_after_fork (parent);
|
fh->fixup_after_fork (parent);
|
||||||
|
|
|
@ -385,7 +385,7 @@ try_to_debug ()
|
||||||
static void
|
static void
|
||||||
stackdump (EXCEPTION_RECORD *e, CONTEXT *in)
|
stackdump (EXCEPTION_RECORD *e, CONTEXT *in)
|
||||||
{
|
{
|
||||||
char *p;
|
const char *p;
|
||||||
if (myself->progname[0])
|
if (myself->progname[0])
|
||||||
{
|
{
|
||||||
/* write to progname.stackdump if possible */
|
/* write to progname.stackdump if possible */
|
||||||
|
|
|
@ -173,150 +173,151 @@ sync_with_child (PROCESS_INFORMATION &pi, HANDLE subproc_ready,
|
||||||
}
|
}
|
||||||
|
|
||||||
debug_printf ("child signalled me");
|
debug_printf ("child signalled me");
|
||||||
if (hang_child)
|
|
||||||
{
|
|
||||||
int n = SuspendThread (pi.hThread);
|
|
||||||
debug_printf ("suspend count %d", n); \
|
|
||||||
}
|
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int
|
static int
|
||||||
resume_child (PROCESS_INFORMATION &pi, HANDLE forker_finished)
|
resume_child (PROCESS_INFORMATION &pi, HANDLE forker_finished)
|
||||||
{
|
{
|
||||||
int rc;
|
|
||||||
|
|
||||||
debug_printf ("here");
|
|
||||||
SetEvent (forker_finished);
|
SetEvent (forker_finished);
|
||||||
|
debug_printf ("signalled child");
|
||||||
rc = ResumeThread (pi.hThread);
|
return 1;
|
||||||
|
|
||||||
debug_printf ("rc %d", rc);
|
|
||||||
if (rc == 1)
|
|
||||||
return 1; // Successful resumption
|
|
||||||
|
|
||||||
/* Can't resume the thread. Not sure why this would happen unless
|
|
||||||
there's a bug in the system. Things seem to be working OK now
|
|
||||||
though, so flag this with EAGAIN, but print a message on the
|
|
||||||
console. */
|
|
||||||
small_printf ("fork: ResumeThread failed, rc = %d, %E\n", rc);
|
|
||||||
set_errno (EAGAIN);
|
|
||||||
syscall_printf ("-1 = fork(), ResumeThread failed");
|
|
||||||
TerminateProcess (pi.hProcess, 1);
|
|
||||||
return 0;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Notify parent that it is time for the next step.
|
/* Notify parent that it is time for the next step.
|
||||||
Note that this has to be a macro since the parent may be messing with
|
Note that this has to be a macro since the parent may be messing with
|
||||||
our stack. */
|
our stack. */
|
||||||
#define sync_with_parent(s, hang_self) \
|
static void __stdcall
|
||||||
((void) ({ \
|
sync_with_parent(const char *s, bool hang_self)
|
||||||
debug_printf ("signalling parent: %s", s); \
|
|
||||||
/* Tell our parent we're waiting. */ \
|
|
||||||
if (!SetEvent (child_proc_info->subproc_ready)) \
|
|
||||||
api_fatal ("fork child - SetEvent failed, %E"); \
|
|
||||||
if (hang_self) \
|
|
||||||
{ \
|
|
||||||
/* Wait for the parent to fill in our stack and heap. \
|
|
||||||
Don't wait forever here. If our parent dies we don't want to clog \
|
|
||||||
the system. If the wait fails, we really can't continue so exit. */ \
|
|
||||||
DWORD psync_rc = WaitForSingleObject (child_proc_info->forker_finished, FORK_WAIT_TIMEOUT); \
|
|
||||||
switch (psync_rc) \
|
|
||||||
{ \
|
|
||||||
case WAIT_TIMEOUT: \
|
|
||||||
api_fatal ("sync_with_parent - WFSO timed out"); \
|
|
||||||
break; \
|
|
||||||
case WAIT_FAILED: \
|
|
||||||
if (GetLastError () == ERROR_INVALID_HANDLE && \
|
|
||||||
WaitForSingleObject (child_proc_info->forker_finished, 1) != WAIT_FAILED) \
|
|
||||||
break; \
|
|
||||||
api_fatal ("sync_with_parent - WFSO failed, fork_finished %p, %E", child_proc_info->forker_finished); \
|
|
||||||
break; \
|
|
||||||
default: \
|
|
||||||
break; \
|
|
||||||
} \
|
|
||||||
debug_printf ("awake"); \
|
|
||||||
} \
|
|
||||||
0; \
|
|
||||||
}))
|
|
||||||
|
|
||||||
static volatile void grow_stack_slack();
|
|
||||||
|
|
||||||
static void *
|
|
||||||
stack_dummy (int here)
|
|
||||||
{
|
{
|
||||||
return &here;
|
debug_printf ("signalling parent: %s", s);
|
||||||
|
/* Tell our parent we're waiting. */
|
||||||
|
if (!SetEvent (child_proc_info->subproc_ready))
|
||||||
|
api_fatal ("fork child - SetEvent failed, %E");
|
||||||
|
if (hang_self)
|
||||||
|
{
|
||||||
|
HANDLE h = child_proc_info->forker_finished;
|
||||||
|
/* Wait for the parent to fill in our stack and heap.
|
||||||
|
Don't wait forever here. If our parent dies we don't want to clog
|
||||||
|
the system. If the wait fails, we really can't continue so exit. */
|
||||||
|
DWORD psync_rc = WaitForSingleObject (h, FORK_WAIT_TIMEOUT);
|
||||||
|
debug_printf ("awake");
|
||||||
|
switch (psync_rc)
|
||||||
|
{
|
||||||
|
case WAIT_TIMEOUT:
|
||||||
|
api_fatal ("WFSO timed out");
|
||||||
|
break;
|
||||||
|
case WAIT_FAILED:
|
||||||
|
if (GetLastError () == ERROR_INVALID_HANDLE &&
|
||||||
|
WaitForSingleObject (child_proc_info->forker_finished, 1) != WAIT_FAILED)
|
||||||
|
break;
|
||||||
|
api_fatal ("WFSO failed, fork_finished %p, %E", child_proc_info->forker_finished);
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
debug_printf ("no problems");
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
extern "C" int
|
static int __stdcall
|
||||||
fork ()
|
fork_child (HANDLE& hParent, dll *&first_dll, bool& load_dlls)
|
||||||
{
|
{
|
||||||
int res;
|
debug_printf ("child is running. pid %d, ppid %d, stack here %p",
|
||||||
DWORD rc;
|
myself->pid, myself->ppid, __builtin_frame_address (0));
|
||||||
HANDLE hParent;
|
child_info_fork ch;
|
||||||
HANDLE subproc_ready, forker_finished;
|
stack_base (ch);
|
||||||
void *stack_here;
|
|
||||||
int x;
|
/* Restore the inheritance state as in parent
|
||||||
PROCESS_INFORMATION pi = {0, NULL, 0, 0};
|
Don't call setuid here! The flags are already set. */
|
||||||
static NO_COPY HANDLE last_fork_proc = NULL;
|
if (myself->impersonated)
|
||||||
|
{
|
||||||
|
debug_printf ("Impersonation of child, token: %d", myself->token);
|
||||||
|
if (myself->token == INVALID_HANDLE_VALUE)
|
||||||
|
RevertToSelf (); // probably not needed
|
||||||
|
else if (!ImpersonateLoggedOnUser (myself->token))
|
||||||
|
system_printf ("Impersonate for forked child failed: %E");
|
||||||
|
}
|
||||||
|
|
||||||
|
sync_with_parent ("after longjmp.", TRUE);
|
||||||
|
debug_printf ("hParent %p", hParent);
|
||||||
|
ProtectHandle (hParent);
|
||||||
|
// small_printf ("child 1 first_dll %p, load_dlls %d\n", first_dll, load_dlls);
|
||||||
|
|
||||||
|
#ifdef DEBUGGING
|
||||||
|
char c;
|
||||||
|
if (GetEnvironmentVariable ("FORKDEBUG", &c, 1))
|
||||||
|
try_to_debug ();
|
||||||
|
char buf[80];
|
||||||
|
/* This is useful for debugging fork problems. Use gdb to attach to
|
||||||
|
the pid reported here. */
|
||||||
|
if (GetEnvironmentVariable ("CYGWIN_FORK_SLEEP", buf, sizeof (buf)))
|
||||||
|
{
|
||||||
|
small_printf ("Sleeping %d after fork, pid %u\n", atoi (buf), GetCurrentProcessId ());
|
||||||
|
Sleep (atoi(buf));
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/* If we've played with the stack, stacksize != 0. That means that
|
||||||
|
fork() was invoked from other than the main thread. Make sure that
|
||||||
|
when the "main" thread exits it calls do_exit, like a normal process.
|
||||||
|
Exit with a status code of 0. */
|
||||||
|
if (child_proc_info->stacksize)
|
||||||
|
{
|
||||||
|
((DWORD *)child_proc_info->stackbottom)[-17] = (DWORD)do_exit;
|
||||||
|
((DWORD *)child_proc_info->stackbottom)[-15] = (DWORD)0;
|
||||||
|
}
|
||||||
|
|
||||||
MALLOC_CHECK;
|
MALLOC_CHECK;
|
||||||
|
|
||||||
/* FIXME: something is broken when copying the stack from the parent
|
fdtab.fixup_after_fork (hParent);
|
||||||
to the child; we try various tricks here to make sure that the
|
signal_fixup_after_fork ();
|
||||||
stack is good enough to prevent page faults, but the true cause
|
exec_fixup_after_fork ();
|
||||||
is still unknown. DJ */
|
|
||||||
volatile char dummy[4096];
|
|
||||||
dummy[0] = dummy[4095] = 0; // Just to leave some slack in the stack
|
|
||||||
|
|
||||||
grow_stack_slack ();
|
MALLOC_CHECK;
|
||||||
|
|
||||||
debug_printf ("entering");
|
/* If we haven't dynamically loaded any dlls, just signal
|
||||||
/* Calculate how much of stack to copy to child */
|
the parent. Otherwise, load all the dlls, tell the parent
|
||||||
stack_here = stack_dummy (0);
|
that we're done, and wait for the parent to fill in the.
|
||||||
|
loaded dlls' data/bss. */
|
||||||
if (ISSTATE(myself, PID_SPLIT_HEAP))
|
if (!load_dlls)
|
||||||
|
sync_with_parent ("performed fork fixup.", FALSE);
|
||||||
|
else
|
||||||
{
|
{
|
||||||
system_printf ("The heap has been split, CYGWIN can't fork this process.");
|
dlls.load_after_fork (hParent, first_dll);
|
||||||
system_printf ("Increase the heap_chunk_size in the registry and try again.");
|
sync_with_parent ("loaded dlls", TRUE);
|
||||||
set_errno (ENOMEM);
|
|
||||||
syscall_printf ("-1 = fork (), split heap");
|
|
||||||
return -1;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Remember the address of the first loaded dll and decide
|
ForceCloseHandle (hParent);
|
||||||
if we need to load dlls. We do this here so that this
|
(void) ForceCloseHandle (child_proc_info->subproc_ready);
|
||||||
information will be available in the parent and, when
|
(void) ForceCloseHandle (child_proc_info->forker_finished);
|
||||||
the stack is copied, in the child. */
|
|
||||||
dll *first_dll = dlls.start.next;
|
|
||||||
int load_dlls = dlls.reload_on_fork && dlls.loaded_dlls;
|
|
||||||
|
|
||||||
static child_info_fork ch;
|
if (recreate_mmaps_after_fork (myself->mmap_ptr))
|
||||||
x = setjmp (ch.jmp);
|
api_fatal ("recreate_mmaps_after_fork_failed");
|
||||||
|
|
||||||
if (x == 0)
|
/* Set thread local stuff to zero. Under Windows 95/98 this is sometimes
|
||||||
{
|
non-zero, for some reason.
|
||||||
/* This will help some of the confusion. */
|
FIXME: There is a memory leak here after a fork. */
|
||||||
fflush (stdout);
|
for (per_thread **t = threadstuff; *t; t++)
|
||||||
|
if ((*t)->clear_on_fork ())
|
||||||
|
(*t)->set ();
|
||||||
|
|
||||||
subproc_ready = CreateEvent (&sec_all, FALSE, FALSE, NULL);
|
/* Initialize signal/process handling */
|
||||||
forker_finished = CreateEvent (&sec_all, FALSE, FALSE, NULL);
|
sigproc_init ();
|
||||||
ProtectHandle (subproc_ready);
|
return 0;
|
||||||
ProtectHandle (forker_finished);
|
|
||||||
|
|
||||||
/* If we didn't obtain all the resources we need to fork, allow the program
|
|
||||||
to continue, but record the fact that fork won't work. */
|
|
||||||
if (forker_finished == NULL || subproc_ready == NULL)
|
|
||||||
{
|
|
||||||
system_printf ("unable to allocate fork() resources.");
|
|
||||||
system_printf ("fork() disabled.");
|
|
||||||
return -1;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static int __stdcall
|
||||||
|
fork_parent (HANDLE& hParent, dll *&first_dll, bool& load_dlls, child_info_fork &ch)
|
||||||
|
{
|
||||||
|
HANDLE subproc_ready, forker_finished;
|
||||||
|
void *stack_here = &hParent;
|
||||||
|
DWORD rc;
|
||||||
|
PROCESS_INFORMATION pi = {0, NULL, 0, 0};
|
||||||
|
static NO_COPY HANDLE last_fork_proc = NULL;
|
||||||
|
|
||||||
subproc_init ();
|
subproc_init ();
|
||||||
|
|
||||||
debug_printf ("about to call setjmp");
|
|
||||||
/* Parent. */
|
|
||||||
#ifdef DEBUGGING
|
#ifdef DEBUGGING
|
||||||
/* The ProtectHandle call allocates memory so we need to make sure
|
/* The ProtectHandle call allocates memory so we need to make sure
|
||||||
that enough is set aside here so that the sbrk pointer does not
|
that enough is set aside here so that the sbrk pointer does not
|
||||||
|
@ -327,23 +328,9 @@ fork ()
|
||||||
free (malloc (4096));
|
free (malloc (4096));
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
init_child_info (PROC_FORK1, &ch, 1, subproc_ready);
|
|
||||||
|
|
||||||
ch.forker_finished = forker_finished;
|
|
||||||
ch.heaptop = user_data->heaptop;
|
|
||||||
ch.heapbase = user_data->heapbase;
|
|
||||||
ch.heapptr = user_data->heapptr;
|
|
||||||
|
|
||||||
stack_base (ch);
|
|
||||||
|
|
||||||
STARTUPINFO si = {0, NULL, NULL, NULL, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, NULL, NULL, NULL, NULL};
|
|
||||||
|
|
||||||
si.cb = sizeof (STARTUPINFO);
|
|
||||||
si.lpReserved2 = (LPBYTE)&ch;
|
|
||||||
si.cbReserved2 = sizeof(ch);
|
|
||||||
|
|
||||||
int c_flags = GetPriorityClass (hMainProc) /*|
|
int c_flags = GetPriorityClass (hMainProc) /*|
|
||||||
CREATE_NEW_PROCESS_GROUP*/;
|
CREATE_NEW_PROCESS_GROUP*/;
|
||||||
|
STARTUPINFO si = {0, NULL, NULL, NULL, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, NULL, NULL, NULL, NULL};
|
||||||
|
|
||||||
/* If we don't have a console, then don't create a console for the
|
/* If we don't have a console, then don't create a console for the
|
||||||
child either. */
|
child either. */
|
||||||
|
@ -364,14 +351,61 @@ fork ()
|
||||||
DUPLICATE_SAME_ACCESS))
|
DUPLICATE_SAME_ACCESS))
|
||||||
{
|
{
|
||||||
system_printf ("couldn't create handle to myself for child, %E");
|
system_printf ("couldn't create handle to myself for child, %E");
|
||||||
goto cleanup;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Remember the address of the first loaded dll and decide
|
||||||
|
if we need to load dlls. We do this here so that this
|
||||||
|
information will be available in the parent and, when
|
||||||
|
the stack is copied, in the child. */
|
||||||
|
first_dll = dlls.start.next;
|
||||||
|
load_dlls = dlls.reload_on_fork && dlls.loaded_dlls;
|
||||||
|
|
||||||
|
/* This will help some of the confusion. */
|
||||||
|
fflush (stdout);
|
||||||
|
|
||||||
|
subproc_ready = CreateEvent (&sec_all, FALSE, FALSE, NULL);
|
||||||
|
if (subproc_ready == NULL)
|
||||||
|
{
|
||||||
|
CloseHandle (hParent);
|
||||||
|
system_printf ("unable to allocate subproc_ready event, %E");
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
forker_finished = CreateEvent (&sec_all, FALSE, FALSE, NULL);
|
||||||
|
if (forker_finished == NULL)
|
||||||
|
{
|
||||||
|
CloseHandle (hParent);
|
||||||
|
CloseHandle (subproc_ready);
|
||||||
|
system_printf ("unable to allocate subproc_ready event, %E");
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
ProtectHandle (subproc_ready);
|
||||||
|
ProtectHandle (forker_finished);
|
||||||
|
|
||||||
|
init_child_info (PROC_FORK1, &ch, 1, subproc_ready);
|
||||||
|
|
||||||
|
ch.forker_finished = forker_finished;
|
||||||
|
ch.heaptop = user_data->heaptop;
|
||||||
|
ch.heapbase = user_data->heapbase;
|
||||||
|
ch.heapptr = user_data->heapptr;
|
||||||
|
|
||||||
|
stack_base (ch);
|
||||||
|
|
||||||
|
si.cb = sizeof (STARTUPINFO);
|
||||||
|
si.lpReserved2 = (LPBYTE)&ch;
|
||||||
|
si.cbReserved2 = sizeof(ch);
|
||||||
|
|
||||||
/* Remove impersonation */
|
/* Remove impersonation */
|
||||||
uid_t uid = geteuid();
|
uid_t uid;
|
||||||
|
uid = geteuid();
|
||||||
if (myself->impersonated && myself->token != INVALID_HANDLE_VALUE)
|
if (myself->impersonated && myself->token != INVALID_HANDLE_VALUE)
|
||||||
seteuid (myself->orig_uid);
|
seteuid (myself->orig_uid);
|
||||||
|
|
||||||
|
ch.parent = hParent;
|
||||||
|
ch.cygheap = cygheap;
|
||||||
|
ch.cygheap_max = cygheap_max;
|
||||||
|
|
||||||
char sa_buf[1024];
|
char sa_buf[1024];
|
||||||
rc = CreateProcessA (myself->progname, /* image to run */
|
rc = CreateProcessA (myself->progname, /* image to run */
|
||||||
myself->progname, /* what we send in arg0 */
|
myself->progname, /* what we send in arg0 */
|
||||||
|
@ -389,10 +423,9 @@ fork ()
|
||||||
if (!rc)
|
if (!rc)
|
||||||
{
|
{
|
||||||
__seterrno ();
|
__seterrno ();
|
||||||
syscall_printf ("-1 = fork(), CreateProcessA failed");
|
syscall_printf ("CreateProcessA failed, %E");
|
||||||
ForceCloseHandle(subproc_ready);
|
ForceCloseHandle(subproc_ready);
|
||||||
ForceCloseHandle(forker_finished);
|
ForceCloseHandle(forker_finished);
|
||||||
subproc_ready = forker_finished = NULL;
|
|
||||||
/* Restore impersonation */
|
/* Restore impersonation */
|
||||||
if (myself->impersonated && myself->token != INVALID_HANDLE_VALUE)
|
if (myself->impersonated && myself->token != INVALID_HANDLE_VALUE)
|
||||||
seteuid (uid);
|
seteuid (uid);
|
||||||
|
@ -520,100 +553,7 @@ fork ()
|
||||||
forker_finished = NULL;
|
forker_finished = NULL;
|
||||||
pi.hThread = NULL;
|
pi.hThread = NULL;
|
||||||
|
|
||||||
res = forked->pid;
|
return forked->pid;
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
/**** Child *****/
|
|
||||||
|
|
||||||
/* We arrive here via a longjmp from "crt0". */
|
|
||||||
(void) stack_dummy (0); // Just to make sure
|
|
||||||
debug_printf ("child is running %d", x);
|
|
||||||
|
|
||||||
debug_printf ("pid %d, ppid %d", x, myself->ppid);
|
|
||||||
|
|
||||||
/* Restore the inheritance state as in parent
|
|
||||||
Don't call setuid here! The flags are already set. */
|
|
||||||
if (myself->impersonated)
|
|
||||||
{
|
|
||||||
debug_printf ("Impersonation of child, token: %d", myself->token);
|
|
||||||
if (myself->token == INVALID_HANDLE_VALUE)
|
|
||||||
RevertToSelf (); // probably not needed
|
|
||||||
else if (!ImpersonateLoggedOnUser (myself->token))
|
|
||||||
system_printf ("Impersonate for forked child failed: %E");
|
|
||||||
}
|
|
||||||
|
|
||||||
sync_with_parent ("after longjmp.", TRUE);
|
|
||||||
ProtectHandle (hParent);
|
|
||||||
|
|
||||||
#ifdef DEBUGGING
|
|
||||||
char c;
|
|
||||||
if (GetEnvironmentVariable ("FORKDEBUG", &c, 1))
|
|
||||||
try_to_debug ();
|
|
||||||
char buf[80];
|
|
||||||
/* This is useful for debugging fork problems. Use gdb to attach to
|
|
||||||
the pid reported here. */
|
|
||||||
if (GetEnvironmentVariable ("CYGWIN_FORK_SLEEP", buf, sizeof (buf)))
|
|
||||||
{
|
|
||||||
small_printf ("Sleeping %d after fork, pid %u\n", atoi (buf), GetCurrentProcessId ());
|
|
||||||
Sleep (atoi(buf));
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
|
|
||||||
/* If we've played with the stack, stacksize != 0. That means that
|
|
||||||
fork() was invoked from other than the main thread. Make sure that
|
|
||||||
when the "main" thread exits it calls do_exit, like a normal process.
|
|
||||||
Exit with a status code of 0. */
|
|
||||||
if (child_proc_info->stacksize)
|
|
||||||
{
|
|
||||||
((DWORD *)child_proc_info->stackbottom)[-17] = (DWORD)do_exit;
|
|
||||||
((DWORD *)child_proc_info->stackbottom)[-15] = (DWORD)0;
|
|
||||||
}
|
|
||||||
|
|
||||||
MALLOC_CHECK;
|
|
||||||
|
|
||||||
cygheap_fixup_in_child (hParent, 0);
|
|
||||||
fdtab.fixup_after_fork (hParent);
|
|
||||||
signal_fixup_after_fork ();
|
|
||||||
exec_fixup_after_fork ();
|
|
||||||
|
|
||||||
MALLOC_CHECK;
|
|
||||||
|
|
||||||
/* If we haven't dynamically loaded any dlls, just signal
|
|
||||||
the parent. Otherwise, load all the dlls, tell the parent
|
|
||||||
that we're done, and wait for the parent to fill in the.
|
|
||||||
loaded dlls' data/bss. */
|
|
||||||
if (!load_dlls)
|
|
||||||
sync_with_parent ("performed fork fixup.", FALSE);
|
|
||||||
else
|
|
||||||
{
|
|
||||||
dlls.load_after_fork (hParent, first_dll);
|
|
||||||
sync_with_parent ("loaded dlls", TRUE);
|
|
||||||
}
|
|
||||||
|
|
||||||
ForceCloseHandle (hParent);
|
|
||||||
(void) ForceCloseHandle (child_proc_info->subproc_ready);
|
|
||||||
(void) ForceCloseHandle (child_proc_info->forker_finished);
|
|
||||||
|
|
||||||
if (recreate_mmaps_after_fork (myself->mmap_ptr))
|
|
||||||
api_fatal ("recreate_mmaps_after_fork_failed");
|
|
||||||
|
|
||||||
res = 0;
|
|
||||||
/* Set thread local stuff to zero. Under Windows 95/98 this is sometimes
|
|
||||||
non-zero, for some reason.
|
|
||||||
FIXME: There is a memory leak here after a fork. */
|
|
||||||
for (per_thread **t = threadstuff; *t; t++)
|
|
||||||
if ((*t)->clear_on_fork ())
|
|
||||||
(*t)->set ();
|
|
||||||
|
|
||||||
/* Initialize signal/process handling */
|
|
||||||
sigproc_init ();
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
MALLOC_CHECK;
|
|
||||||
syscall_printf ("%d = fork()", res);
|
|
||||||
return res;
|
|
||||||
|
|
||||||
/* Common cleanup code for failure cases */
|
/* Common cleanup code for failure cases */
|
||||||
cleanup:
|
cleanup:
|
||||||
|
@ -626,15 +566,48 @@ cleanup:
|
||||||
ForceCloseHandle (subproc_ready);
|
ForceCloseHandle (subproc_ready);
|
||||||
if (forker_finished)
|
if (forker_finished)
|
||||||
ForceCloseHandle (forker_finished);
|
ForceCloseHandle (forker_finished);
|
||||||
forker_finished = subproc_ready = NULL;
|
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
static volatile void
|
extern "C" int
|
||||||
grow_stack_slack ()
|
fork ()
|
||||||
{
|
{
|
||||||
volatile char dummy[16384];
|
struct
|
||||||
dummy[0] = dummy[16383] = 0; // Just to make some slack in the stack
|
{
|
||||||
|
HANDLE hParent;
|
||||||
|
dll *first_dll;
|
||||||
|
bool load_dlls;
|
||||||
|
} grouped;
|
||||||
|
|
||||||
|
int res;
|
||||||
|
int x;
|
||||||
|
|
||||||
|
MALLOC_CHECK;
|
||||||
|
|
||||||
|
// grow_stack_slack ();
|
||||||
|
|
||||||
|
debug_printf ("entering");
|
||||||
|
|
||||||
|
if (ISSTATE(myself, PID_SPLIT_HEAP))
|
||||||
|
{
|
||||||
|
system_printf ("The heap has been split, CYGWIN can't fork this process.");
|
||||||
|
system_printf ("Increase the heap_chunk_size in the registry and try again.");
|
||||||
|
set_errno (ENOMEM);
|
||||||
|
syscall_printf ("-1 = fork (), split heap");
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
child_info_fork ch;
|
||||||
|
x = setjmp (ch.jmp);
|
||||||
|
|
||||||
|
if (x != 0)
|
||||||
|
res = fork_child (grouped.hParent, grouped.first_dll, grouped.load_dlls);
|
||||||
|
else
|
||||||
|
res = fork_parent (grouped.hParent, grouped.first_dll, grouped.load_dlls, ch);
|
||||||
|
|
||||||
|
MALLOC_CHECK;
|
||||||
|
syscall_printf ("%d = fork()", res);
|
||||||
|
return res;
|
||||||
}
|
}
|
||||||
|
|
||||||
#ifdef NEWVFORK
|
#ifdef NEWVFORK
|
||||||
|
|
|
@ -75,6 +75,7 @@ heap_init ()
|
||||||
brkchunk);
|
brkchunk);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
debug_printf ("heap base %p, heap top %p", brkbase, brktop);
|
||||||
page_const--;
|
page_const--;
|
||||||
malloc_init ();
|
malloc_init ();
|
||||||
}
|
}
|
||||||
|
|
|
@ -70,6 +70,7 @@ details. */
|
||||||
#include "shared_info.h"
|
#include "shared_info.h"
|
||||||
#include "registry.h"
|
#include "registry.h"
|
||||||
#include "security.h"
|
#include "security.h"
|
||||||
|
#include <assert.h>
|
||||||
|
|
||||||
static int normalize_win32_path (const char *src, char *dst);
|
static int normalize_win32_path (const char *src, char *dst);
|
||||||
static void slashify (const char *src, char *dst, int trailing_slash_p);
|
static void slashify (const char *src, char *dst, int trailing_slash_p);
|
||||||
|
@ -190,6 +191,7 @@ path_conv::check (const char *src, unsigned opt,
|
||||||
for (;;)
|
for (;;)
|
||||||
{
|
{
|
||||||
MALLOC_CHECK;
|
MALLOC_CHECK;
|
||||||
|
assert (src);
|
||||||
char *p = strrchr (src, '/');
|
char *p = strrchr (src, '/');
|
||||||
if (p)
|
if (p)
|
||||||
{
|
{
|
||||||
|
@ -2163,6 +2165,7 @@ done:
|
||||||
static __inline char *
|
static __inline char *
|
||||||
has_suffix (const char *path, const suffix_info *suffixes)
|
has_suffix (const char *path, const suffix_info *suffixes)
|
||||||
{
|
{
|
||||||
|
assert (path);
|
||||||
char *ext = strrchr (path, '.');
|
char *ext = strrchr (path, '.');
|
||||||
if (ext)
|
if (ext)
|
||||||
for (const suffix_info *ex = suffixes; ex->name != NULL; ex++)
|
for (const suffix_info *ex = suffixes; ex->name != NULL; ex++)
|
||||||
|
|
|
@ -106,7 +106,7 @@ convert_string_sid_to_sid (PSID psid, const char *sid_str)
|
||||||
BOOL
|
BOOL
|
||||||
get_pw_sid (PSID sid, struct passwd *pw)
|
get_pw_sid (PSID sid, struct passwd *pw)
|
||||||
{
|
{
|
||||||
char *sp = strrchr (pw->pw_gecos, ',');
|
char *sp = pw->pw_gecos ? strrchr (pw->pw_gecos, ',') : NULL;
|
||||||
|
|
||||||
if (!sp)
|
if (!sp)
|
||||||
return FALSE;
|
return FALSE;
|
||||||
|
|
|
@ -305,7 +305,6 @@ proc_subproc (DWORD what, DWORD val)
|
||||||
pchildren[nchildren] = vchild;
|
pchildren[nchildren] = vchild;
|
||||||
hchildren[nchildren] = vchild->hProcess;
|
hchildren[nchildren] = vchild->hProcess;
|
||||||
ProtectHandle1 (vchild->hProcess, childhProc);
|
ProtectHandle1 (vchild->hProcess, childhProc);
|
||||||
nchildren++;
|
|
||||||
if (!DuplicateHandle (hMainProc, vchild->hProcess, hMainProc, &vchild->pid_handle,
|
if (!DuplicateHandle (hMainProc, vchild->hProcess, hMainProc, &vchild->pid_handle,
|
||||||
0, 0, DUPLICATE_SAME_ACCESS))
|
0, 0, DUPLICATE_SAME_ACCESS))
|
||||||
system_printf ("Couldn't duplicate child handle for pid %d, %E", vchild->pid);
|
system_printf ("Couldn't duplicate child handle for pid %d, %E", vchild->pid);
|
||||||
|
@ -313,6 +312,7 @@ proc_subproc (DWORD what, DWORD val)
|
||||||
sigproc_printf ("added pid %d to wait list, slot %d, winpid %p, handle %p",
|
sigproc_printf ("added pid %d to wait list, slot %d, winpid %p, handle %p",
|
||||||
vchild->pid, nchildren, vchild->dwProcessId,
|
vchild->pid, nchildren, vchild->dwProcessId,
|
||||||
vchild->hProcess);
|
vchild->hProcess);
|
||||||
|
nchildren++;
|
||||||
|
|
||||||
wake_wait_subproc ();
|
wake_wait_subproc ();
|
||||||
break;
|
break;
|
||||||
|
@ -1163,7 +1163,7 @@ wait_sig (VOID *)
|
||||||
sigcatch_main = CreateSemaphore (&sec_none_nih, 0, MAXLONG, NULL);
|
sigcatch_main = CreateSemaphore (&sec_none_nih, 0, MAXLONG, NULL);
|
||||||
sigcomplete_nonmain = CreateSemaphore (&sec_none_nih, 0, MAXLONG, NULL);
|
sigcomplete_nonmain = CreateSemaphore (&sec_none_nih, 0, MAXLONG, NULL);
|
||||||
sigcomplete_main = CreateEvent (&sec_none_nih, FALSE, FALSE, NULL);
|
sigcomplete_main = CreateEvent (&sec_none_nih, FALSE, FALSE, NULL);
|
||||||
sigproc_printf ("sigcatch_nonmain %p", sigcatch_nonmain);
|
sigproc_printf ("sigcatch_nonmain %p, sigcatch_main %p", sigcatch_nonmain, sigcatch_main);
|
||||||
|
|
||||||
/* Setting dwProcessId flags that this process is now capable of receiving
|
/* Setting dwProcessId flags that this process is now capable of receiving
|
||||||
* signals. Prior to this, dwProcessId was set to the windows pid of
|
* signals. Prior to this, dwProcessId was set to the windows pid of
|
||||||
|
|
|
@ -21,7 +21,7 @@ details. */
|
||||||
#define PROTECT(x) x[sizeof(x)-1] = 0
|
#define PROTECT(x) x[sizeof(x)-1] = 0
|
||||||
#define CHECK(x) if (x[sizeof(x)-1] != 0) { small_printf("array bound exceeded %d\n", __LINE__); ExitProcess(1); }
|
#define CHECK(x) if (x[sizeof(x)-1] != 0) { small_printf("array bound exceeded %d\n", __LINE__); ExitProcess(1); }
|
||||||
|
|
||||||
class strace NO_COPY strace;
|
class NO_COPY strace strace;
|
||||||
|
|
||||||
/* 'twould be nice to declare this in winsup.h but winsup.h doesn't require
|
/* 'twould be nice to declare this in winsup.h but winsup.h doesn't require
|
||||||
stdarg.h, so we declare it here instead. */
|
stdarg.h, so we declare it here instead. */
|
||||||
|
@ -31,9 +31,9 @@ class strace NO_COPY strace;
|
||||||
int
|
int
|
||||||
strace::microseconds()
|
strace::microseconds()
|
||||||
{
|
{
|
||||||
static int first_microsec = 0;
|
static NO_COPY int first_microsec = 0;
|
||||||
static long long hires_frequency = 0;
|
static NO_COPY long long hires_frequency = 0;
|
||||||
static int hires_initted = 0;
|
static NO_COPY int hires_initted = 0;
|
||||||
|
|
||||||
int microsec;
|
int microsec;
|
||||||
|
|
||||||
|
@ -104,7 +104,7 @@ strace::vsprntf (char *buf, const char *func, const char *infmt, va_list ap)
|
||||||
{
|
{
|
||||||
int count;
|
int count;
|
||||||
char fmt[80];
|
char fmt[80];
|
||||||
static int nonewline = FALSE;
|
static NO_COPY int nonewline = FALSE;
|
||||||
DWORD err = GetLastError ();
|
DWORD err = GetLastError ();
|
||||||
const char *tn = threadname (0);
|
const char *tn = threadname (0);
|
||||||
char *pn = __progname ?: myself->progname;
|
char *pn = __progname ?: myself->progname;
|
||||||
|
@ -121,7 +121,9 @@ strace::vsprntf (char *buf, const char *func, const char *infmt, va_list ap)
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
char *p, progname[MAX_PATH + 1];
|
char *p, progname[MAX_PATH + 1];
|
||||||
if ((p = strrchr (pn, '\\')) != NULL)
|
if (!pn)
|
||||||
|
p = (char *) "*** unknown ***";
|
||||||
|
else if ((p = strrchr (pn, '\\')) != NULL)
|
||||||
p++;
|
p++;
|
||||||
else if ((p = strrchr (pn, '/')) != NULL)
|
else if ((p = strrchr (pn, '/')) != NULL)
|
||||||
p++;
|
p++;
|
||||||
|
@ -206,7 +208,7 @@ strace::prntf (unsigned category, const char *func, const char *fmt, ...)
|
||||||
SetLastError (err);
|
SetLastError (err);
|
||||||
}
|
}
|
||||||
|
|
||||||
static const struct tab
|
static NO_COPY const struct tab
|
||||||
{
|
{
|
||||||
int v;
|
int v;
|
||||||
const char *n;
|
const char *n;
|
||||||
|
|
Loading…
Reference in New Issue