4
0
mirror of git://sourceware.org/git/newlib-cygwin.git synced 2025-01-20 05:19:21 +08:00

* cygheap.cc (cygheap_fixup_in_child): Don't page round cygheap copied from

parent.
* dcrt0.cc (do_exit): Don't cleanup pinfo on exit.  That happens automatically
now.
* exceptions.cc (signal_exit): Ditto.
* fork.cc (fork_parent): Use stack_here value passed in from fork().
(fork): Figure out top of stack here and pass it to fork_parent.
* pinfo.cc (_pinfo::record_death): Eliminate.
* pinfo.h (_pinfo): Ditto.
* sigproc.cc (proc_exists): Simplify.
(proc_terminate): Ditto.
(remove_zombie): Don't cleanup pinfo stuff.
(wait_sig): Send subproc_ready signal whether execed or spawned.
* spawn.cc (spawn_guts): Always create subproc_ready event.  Use it for both
exec and spawn.
(_spawnve): Send proper mode to spawn_guts when mode != _P_OVERLAY.
This commit is contained in:
Christopher Faylor 2000-10-14 05:52:38 +00:00
parent cbe4c8e234
commit aece55b982
9 changed files with 154 additions and 244 deletions

View File

@ -1,3 +1,22 @@
Sat Oct 14 01:45:25 2000 Christopher Faylor <cgf@cygnus.com>
* cygheap.cc (cygheap_fixup_in_child): Don't page round cygheap copied
from parent.
* dcrt0.cc (do_exit): Don't cleanup pinfo on exit. That happens
automatically now.
* exceptions.cc (signal_exit): Ditto.
* fork.cc (fork_parent): Use stack_here value passed in from fork().
(fork): Figure out top of stack here and pass it to fork_parent.
* pinfo.cc (_pinfo::record_death): Eliminate.
* pinfo.h (_pinfo): Ditto.
* sigproc.cc (proc_exists): Simplify.
(proc_terminate): Ditto.
(remove_zombie): Don't cleanup pinfo stuff.
(wait_sig): Send subproc_ready signal whether execed or spawned.
* spawn.cc (spawn_guts): Always create subproc_ready event. Use it for
both exec and spawn.
(_spawnve): Send proper mode to spawn_guts when mode != _P_OVERLAY.
Thu Oct 12 23:11:05 2000 Christopher Faylor <cgf@cygnus.com> Thu Oct 12 23:11:05 2000 Christopher Faylor <cgf@cygnus.com>
* dtable.cc (dtable::fixup_after_fork): Revert thinko below. * dtable.cc (dtable::fixup_after_fork): Revert thinko below.

View File

@ -207,9 +207,7 @@ cygheap_fixup_in_child (HANDLE parent, bool execed)
/* Copy memory from the parent */ /* Copy memory from the parent */
m = 0; m = 0;
n = (DWORD) pagetrunc (n + 4095); if (!ReadProcessMemory (parent, cygheap, cygheap, n, &m) || m != n)
if (!ReadProcessMemory (parent, cygheap, cygheap, n, &m) ||
m != n)
api_fatal ("Couldn't read parent's cygwin heap %d bytes != %d, %E", api_fatal ("Couldn't read parent's cygwin heap %d bytes != %d, %E",
n, m); n, m);

View File

@ -973,7 +973,6 @@ enum
extern "C" void __stdcall extern "C" void __stdcall
do_exit (int status) do_exit (int status)
{ {
BOOL cleanup_pinfo;
UINT n = (UINT) status; UINT n = (UINT) status;
static int NO_COPY exit_state = 0; static int NO_COPY exit_state = 0;
@ -1013,10 +1012,7 @@ do_exit (int status)
} }
if (n & EXIT_REPARENTING) if (n & EXIT_REPARENTING)
{
n &= ~EXIT_REPARENTING; n &= ~EXIT_REPARENTING;
cleanup_pinfo = FALSE;
}
else else
{ {
myself->stopsig = 0; myself->stopsig = 0;
@ -1045,7 +1041,6 @@ do_exit (int status)
} }
tty_terminate (); tty_terminate ();
cleanup_pinfo = TRUE;
} }
window_terminate (); window_terminate ();
@ -1060,11 +1055,6 @@ do_exit (int status)
ForceCloseHandle1 (hExeced, childhProc); ForceCloseHandle1 (hExeced, childhProc);
} }
if (cleanup_pinfo)
myself->record_death ();
else
sigproc_printf ("not cleanup_pinfo");
shared_terminate (); shared_terminate ();
sigproc_printf ("calling ExitProcess %d", n); sigproc_printf ("calling ExitProcess %d", n);
@ -1106,7 +1096,6 @@ __api_fatal (const char *fmt, ...)
/* We are going down without mercy. Make sure we reset /* We are going down without mercy. Make sure we reset
our process_state. */ our process_state. */
sigproc_terminate (); sigproc_terminate ();
myself->record_death ();
#ifdef DEBUGGING #ifdef DEBUGGING
(void) try_to_debug (); (void) try_to_debug ();
#endif #endif

View File

@ -1005,11 +1005,7 @@ signal_exit (int rc)
{ {
rc = EXIT_SIGNAL | (rc << 8); rc = EXIT_SIGNAL | (rc << 8);
if (exit_already++) if (exit_already++)
{
/* We are going down - reset our process_state without locking. */
myself->record_death ();
ExitProcess (rc); ExitProcess (rc);
}
/* We'd like to stop the main thread from executing but when we do that it /* We'd like to stop the main thread from executing but when we do that it
causes random, inexplicable hangs. So, instead, we set up the priority causes random, inexplicable hangs. So, instead, we set up the priority

View File

@ -308,10 +308,9 @@ debug_printf ("hParent %p", hParent);
} }
static int __stdcall static int __stdcall
fork_parent (HANDLE& hParent, dll *&first_dll, bool& load_dlls, child_info_fork &ch) fork_parent (void *stack_here, HANDLE& hParent, dll *&first_dll, bool& load_dlls, child_info_fork &ch)
{ {
HANDLE subproc_ready, forker_finished; HANDLE subproc_ready, forker_finished;
void *stack_here = &hParent;
DWORD rc; DWORD rc;
PROCESS_INFORMATION pi = {0, NULL, 0, 0}; PROCESS_INFORMATION pi = {0, NULL, 0, 0};
static NO_COPY HANDLE last_fork_proc = NULL; static NO_COPY HANDLE last_fork_proc = NULL;
@ -339,8 +338,6 @@ fork_parent (HANDLE& hParent, dll *&first_dll, bool& load_dlls, child_info_fork
OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL,
NULL); NULL);
syscall_printf ("CreateProcessA (%s, %s,0,0,1,%x, 0,0,%p,%p)",
myself->progname, myself->progname, c_flags, &si, &pi);
if (console_handle != INVALID_HANDLE_VALUE && console_handle != 0) if (console_handle != INVALID_HANDLE_VALUE && console_handle != 0)
CloseHandle (console_handle); CloseHandle (console_handle);
else else
@ -407,7 +404,9 @@ fork_parent (HANDLE& hParent, dll *&first_dll, bool& load_dlls, child_info_fork
ch.cygheap_max = cygheap_max; ch.cygheap_max = cygheap_max;
char sa_buf[1024]; char sa_buf[1024];
rc = CreateProcessA (myself->progname, /* image to run */ syscall_printf ("CreateProcess (%s, %s, 0, 0, 1, %x, 0, 0, %p, %p)",
myself->progname, myself->progname, c_flags, &si, &pi);
rc = CreateProcess (myself->progname, /* image to run */
myself->progname, /* what we send in arg0 */ myself->progname, /* what we send in arg0 */
allow_ntsec ? sec_user (sa_buf) : &sec_none_nih, allow_ntsec ? sec_user (sa_buf) : &sec_none_nih,
allow_ntsec ? sec_user (sa_buf) : &sec_none_nih, allow_ntsec ? sec_user (sa_buf) : &sec_none_nih,
@ -579,14 +578,11 @@ fork ()
bool load_dlls; bool load_dlls;
} grouped; } grouped;
int res;
int x;
MALLOC_CHECK; MALLOC_CHECK;
// grow_stack_slack ();
debug_printf ("entering"); debug_printf ("entering");
grouped.hParent = grouped.first_dll = NULL;
grouped.load_dlls = 0;
if (ISSTATE(myself, PID_SPLIT_HEAP)) if (ISSTATE(myself, PID_SPLIT_HEAP))
{ {
@ -597,13 +593,17 @@ fork ()
return -1; return -1;
} }
child_info_fork ch; void *esp;
x = setjmp (ch.jmp); __asm ("movl %%esp,%0": "=r" (esp));
if (x != 0) child_info_fork ch;
int res = setjmp (ch.jmp);
if (res)
res = fork_child (grouped.hParent, grouped.first_dll, grouped.load_dlls); res = fork_child (grouped.hParent, grouped.first_dll, grouped.load_dlls);
else else
res = fork_parent (grouped.hParent, grouped.first_dll, grouped.load_dlls, ch); res = fork_parent (esp, grouped.hParent, grouped.first_dll, grouped.load_dlls, ch);
MALLOC_CHECK; MALLOC_CHECK;
syscall_printf ("%d = fork()", res); syscall_printf ("%d = fork()", res);

View File

@ -174,17 +174,6 @@ _pinfo::copysigs(_pinfo *_other)
sigs = _other->sigs; sigs = _other->sigs;
} }
void
_pinfo::record_death ()
{
/* CGF FIXME - needed? */
if (dwProcessId == GetCurrentProcessId () && !my_parent_is_alive ())
{
process_state = PID_NOT_IN_USE;
hProcess = NULL;
}
}
void void
pinfo::init (pid_t n, DWORD create, HANDLE in_h) pinfo::init (pid_t n, DWORD create, HANDLE in_h)
{ {

View File

@ -119,8 +119,6 @@ private:
public: public:
/* Pointer to mmap'ed areas for this process. Set up by fork. */ /* Pointer to mmap'ed areas for this process. Set up by fork. */
void *mmap_ptr; void *mmap_ptr;
void record_death ();
}; };
class pinfo class pinfo

View File

@ -205,48 +205,8 @@ proc_exists (_pinfo *p)
if (p == NULL) if (p == NULL)
return FALSE; return FALSE;
else
if (p == myself || p == myself_nowait_nonmain || p == myself_nowait)
return TRUE; return TRUE;
if (p->process_state == PID_NOT_IN_USE || !p->dwProcessId)
return FALSE;
sigproc_printf ("checking for existence of pid %d, window pid %d", p->pid,
p->dwProcessId);
if (p->ppid == myself->pid && p->hProcess != NULL)
{
sigproc_printf ("it's mine, process_state %x", p->process_state);
return proc_can_be_signalled (p);
}
/* Note: Process is alive if OpenProcess() call fails due to permissions */
if (((h = OpenProcess (STANDARD_RIGHTS_REQUIRED, FALSE, p->dwProcessId))
!= NULL) || (GetLastError () == ERROR_ACCESS_DENIED))
{
sigproc_printf ("it exists, %p", h);
if (h)
{
DWORD rc = WaitForSingleObject (h, 0);
CloseHandle (h);
if (rc == WAIT_OBJECT_0)
return 0;
}
return proc_can_be_signalled (p);
}
sigproc_printf ("it doesn't exist");
#if 0
/* If the parent pid does not exist, clean this process out of the pinfo
* table. It must have died abnormally.
*/
if ((p->pid == p->ppid) || (p->ppid == 1) || !pid_exists (p->ppid))
{
p->hProcess = NULL;
p->process_state = PID_NOT_IN_USE;
}
#endif
return FALSE;
} }
/* Return 1 if this is one of our children, zero otherwise. /* Return 1 if this is one of our children, zero otherwise.
@ -500,22 +460,13 @@ proc_terminate (void)
else else
{ {
ForceCloseHandle1 (pchildren[i]->hProcess, childhProc); ForceCloseHandle1 (pchildren[i]->hProcess, childhProc);
if (!proc_exists (pchildren[i])) sigproc_printf ("%d(%d) closed child handle", pchildren[i]->pid,
{
sigproc_printf ("%d(%d) doesn't exist", pchildren[i]->pid,
pchildren[i]->dwProcessId);
pchildren[i]->process_state = PID_NOT_IN_USE; /* a reaped child CGF FIXME -- still needed? */
}
else
{
sigproc_printf ("%d(%d) closing active child handle", pchildren[i]->pid,
pchildren[i]->dwProcessId); pchildren[i]->dwProcessId);
pchildren[i]->ppid = 1; pchildren[i]->ppid = 1;
if (pchildren[i]->pgid == myself->pid) if (pchildren[i]->pgid == myself->pid)
pchildren[i]->process_state |= PID_ORPHANED; pchildren[i]->process_state |= PID_ORPHANED;
} }
} pchildren[i].release ();
pchildren[i].release (); // FIXME: this breaks older gccs for some reason
} }
nchildren = nzombies = 0; nchildren = nzombies = 0;
@ -601,6 +552,7 @@ sigproc_init ()
/* local event signaled when main thread has been dispatched /* local event signaled when main thread has been dispatched
to a signal handler function. */ to a signal handler function. */
signal_arrived = CreateEvent(&sec_none_nih, TRUE, FALSE, NULL); signal_arrived = CreateEvent(&sec_none_nih, TRUE, FALSE, NULL);
ProtectHandle (signal_arrived);
if (!(hwait_sig = makethread (wait_sig, NULL, 0, "sig"))) if (!(hwait_sig = makethread (wait_sig, NULL, 0, "sig")))
{ {
@ -669,14 +621,6 @@ sigproc_terminate (void)
WaitForSingleObject (h, 10000); WaitForSingleObject (h, 10000);
ForceCloseHandle1 (h, hwait_sig); ForceCloseHandle1 (h, hwait_sig);
/* Exiting thread. Cleanup. Don't set to inactive if a child has been
execed with the same pid. */
if (!myself->dwProcessId || myself->dwProcessId == GetCurrentProcessId ())
myself->process_state &= ~PID_ACTIVE;
else
sigproc_printf ("Did not clear PID_ACTIVE since %d != %d",
myself->dwProcessId, GetCurrentProcessId ());
/* In case of a sigsuspend */ /* In case of a sigsuspend */
SetEvent (signal_arrived); SetEvent (signal_arrived);
@ -1052,7 +996,6 @@ remove_zombie (int ci)
{ {
ForceCloseHandle1 (zombies[ci]->hProcess, childhProc); ForceCloseHandle1 (zombies[ci]->hProcess, childhProc);
ForceCloseHandle1 (zombies[ci]->pid_handle, pid_handle); ForceCloseHandle1 (zombies[ci]->pid_handle, pid_handle);
zombies[ci]->process_state = PID_NOT_IN_USE; /* a reaped child */
zombies[ci].release (); zombies[ci].release ();
} }
@ -1184,7 +1127,8 @@ wait_sig (VOID *)
* windows process waiting to see if it's started a cygwin process or not. * windows process waiting to see if it's started a cygwin process or not.
* Signalling subproc_ready indicates that we are a cygwin process. * Signalling subproc_ready indicates that we are a cygwin process.
*/ */
if (child_proc_info && child_proc_info->type == PROC_EXEC) if (child_proc_info &&
(child_proc_info->type == PROC_FORK || child_proc_info->type == PROC_SPAWN))
{ {
debug_printf ("subproc_ready %p", child_proc_info->subproc_ready); debug_printf ("subproc_ready %p", child_proc_info->subproc_ready);
if (!SetEvent (child_proc_info->subproc_ready)) if (!SetEvent (child_proc_info->subproc_ready))
@ -1383,6 +1327,7 @@ WFSO (HANDLE hHandle, DWORD dwMilliseconds)
DWORD ret; DWORD ret;
sigframe thisframe (mainthread); sigframe thisframe (mainthread);
ret = WaitForSingleObject (hHandle, dwMilliseconds); ret = WaitForSingleObject (hHandle, dwMilliseconds);
if (dwMilliseconds > 10 && ret == WAIT_TIMEOUT) system_printf ("TIMED OUT %d\n", dwMilliseconds);
return ret; return ret;
} }
@ -1394,6 +1339,7 @@ WFMO (DWORD nCount, CONST HANDLE *lpHandles, BOOL fWaitAll, DWORD dwMilliseconds
DWORD ret; DWORD ret;
sigframe thisframe (mainthread); sigframe thisframe (mainthread);
ret = WaitForMultipleObjects (nCount, lpHandles, fWaitAll, dwMilliseconds); ret = WaitForMultipleObjects (nCount, lpHandles, fWaitAll, dwMilliseconds);
if (dwMilliseconds > 10 && ret == WAIT_TIMEOUT) system_printf ("TIMED OUT %d\n", dwMilliseconds);
return ret; return ret;
} }
} }

View File

@ -158,21 +158,6 @@ handle (int n, int direction)
return fh->get_output_handle (); return fh->get_output_handle ();
} }
/* Cover function for CreateProcess.
This function is used by both the routines that search $PATH and those
that do not. This should work out ok as according to the documentation,
CreateProcess only searches $PATH if PROG has no directory elements.
Spawning doesn't fit well with Posix's fork/exec (one can argue the merits
of either but that's beside the point). If we're exec'ing we want to
record the child pid for fork. If we're spawn'ing we don't want to do
this. It is up to the caller to handle both cases.
The result is the process id. The handle of the created process is
stored in H.
*/
HANDLE NO_COPY hExeced = NULL; HANDLE NO_COPY hExeced = NULL;
int int
@ -252,7 +237,7 @@ public:
int argc; int argc;
av (int ac, const char * const *av) : calloced (0), argc (ac) av (int ac, const char * const *av) : calloced (0), argc (ac)
{ {
argv = (char **) cmalloc (HEAP_1_ARGV, (argc + 1) * sizeof (char *)); argv = (char **) cmalloc (HEAP_1_ARGV, (argc + 5) * sizeof (char *));
memcpy (argv, av, (argc + 1) * sizeof (char *)); memcpy (argv, av, (argc + 1) * sizeof (char *));
} }
~av () ~av ()
@ -348,16 +333,14 @@ spawn_guts (HANDLE hToken, const char * prog_arg, const char *const *argv,
si.lpReserved2 = (LPBYTE) &ciresrv; si.lpReserved2 = (LPBYTE) &ciresrv;
si.cbReserved2 = sizeof (ciresrv); si.cbReserved2 = sizeof (ciresrv);
HANDLE spr = NULL;
DWORD chtype; DWORD chtype;
if (mode != _P_OVERLAY && mode != _P_VFORK) if (mode != _P_OVERLAY && mode != _P_VFORK)
chtype = PROC_SPAWN; chtype = PROC_SPAWN;
else else
{
spr = CreateEvent(&sec_all, TRUE, FALSE, NULL);
ProtectHandle (spr);
chtype = PROC_EXEC; chtype = PROC_EXEC;
}
HANDLE spr = CreateEvent(&sec_all, TRUE, FALSE, NULL);
ProtectHandle (spr);
init_child_info (chtype, &ciresrv, (mode == _P_OVERLAY) ? myself->pid : 1, spr); init_child_info (chtype, &ciresrv, (mode == _P_OVERLAY) ? myself->pid : 1, spr);
if (!DuplicateHandle (hMainProc, hMainProc, hMainProc, &ciresrv.parent, 0, 1, if (!DuplicateHandle (hMainProc, hMainProc, hMainProc, &ciresrv.parent, 0, 1,
@ -555,8 +538,6 @@ skip_arg_parsing:
si.hStdError = handle (2, 1); /* Get output handle */ si.hStdError = handle (2, 1); /* Get output handle */
si.cb = sizeof (si); si.cb = sizeof (si);
/* Pass fd table to a child */
syscall_printf ("spawn_guts (%s, %.132s)", (char *) real_path, one_line.buf); syscall_printf ("spawn_guts (%s, %.132s)", (char *) real_path, one_line.buf);
int flags = CREATE_DEFAULT_ERROR_MODE | CREATE_SUSPENDED | int flags = CREATE_DEFAULT_ERROR_MODE | CREATE_SUSPENDED |
@ -696,8 +677,6 @@ skip_arg_parsing:
if (mode == _P_OVERLAY) if (mode == _P_OVERLAY)
{ {
strcpy (myself->progname, real_path); strcpy (myself->progname, real_path);
// close_all_files ();
proc_terminate ();
hExeced = pi.hProcess; hExeced = pi.hProcess;
myself->dwProcessId = pi.dwProcessId; myself->dwProcessId = pi.dwProcessId;
@ -765,15 +744,11 @@ skip_arg_parsing:
CloseHandle (hToken); CloseHandle (hToken);
DWORD res; DWORD res;
if (mode == _P_OVERLAY || mode == _P_VFORK)
{
BOOL exited; BOOL exited;
HANDLE waitbuf[3] = {pi.hProcess, signal_arrived, spr}; HANDLE waitbuf[3] = {pi.hProcess, signal_arrived, spr};
int nwait = 3; int nwait = 3;
SetThreadPriority (GetCurrentThread (), THREAD_PRIORITY_HIGHEST);
res = 0; res = 0;
exited = FALSE; exited = FALSE;
MALLOC_CHECK; MALLOC_CHECK;
@ -789,10 +764,9 @@ skip_arg_parsing:
res |= exitcode; res |= exitcode;
exited = TRUE; exited = TRUE;
if (nwait <= 2 || (res & EXIT_REPARENTING) || (mode != _P_OVERLAY && mode != _P_VFORK)) if (nwait > 2 && !(res & EXIT_REPARENTING) &&
/* nothing to do */; (mode == _P_OVERLAY || mode == _P_VFORK))
else if (WaitForSingleObject (spr, 1) == WAIT_OBJECT_0) res |= EXIT_REPARENTING;
goto reparent;
break; break;
case WAIT_OBJECT_0 + 1: case WAIT_OBJECT_0 + 1:
sigproc_printf ("signal arrived"); sigproc_printf ("signal arrived");
@ -801,7 +775,6 @@ skip_arg_parsing:
case WAIT_OBJECT_0 + 2: case WAIT_OBJECT_0 + 2:
if (mode == _P_OVERLAY) if (mode == _P_OVERLAY)
{ {
reparent:
res |= EXIT_REPARENTING; res |= EXIT_REPARENTING;
if (!parent_alive) if (!parent_alive)
{ {
@ -812,14 +785,16 @@ skip_arg_parsing:
} }
break; break;
case WAIT_FAILED: case WAIT_FAILED:
DWORD r;
system_printf ("wait failed: nwait %d, pid %d, winpid %d, %E", system_printf ("wait failed: nwait %d, pid %d, winpid %d, %E",
nwait, myself->pid, myself->dwProcessId); nwait, myself->pid, myself->dwProcessId);
system_printf ("waitbuf[0] %p %d", waitbuf[0], system_printf ("waitbuf[0] %p %d", waitbuf[0],
GetHandleInformation (waitbuf[0], &r)); WaitForSingleObject (waitbuf[0], 0));
system_printf ("waitbuf[1] %p = %d", waitbuf[1], system_printf ("waitbuf[1] %p = %d", waitbuf[1],
GetHandleInformation (waitbuf[1], &r)); WaitForSingleObject (waitbuf[1], 0));
system_printf ("waitbuf[w] %p = %d", waitbuf[2],
WaitForSingleObject (waitbuf[2], 0));
set_errno (ECHILD); set_errno (ECHILD);
try_to_debug ();
return -1; return -1;
} }
break; break;
@ -829,7 +804,7 @@ skip_arg_parsing:
sigproc_printf ("res = %x", res); sigproc_printf ("res = %x", res);
if (res & EXIT_REPARENTING) if (mode == _P_OVERLAY && (res & EXIT_REPARENTING))
{ {
/* Try to reparent child process. /* Try to reparent child process.
* Make handles to child available to parent process and exit with * Make handles to child available to parent process and exit with
@ -870,7 +845,6 @@ skip_arg_parsing:
{ {
ForceCloseHandle1 (hExeced, childhProc); ForceCloseHandle1 (hExeced, childhProc);
hExeced = INVALID_HANDLE_VALUE; hExeced = INVALID_HANDLE_VALUE;
close_all_files ();
} }
} }
else if (exited) else if (exited)
@ -880,12 +854,13 @@ skip_arg_parsing:
} }
MALLOC_CHECK; MALLOC_CHECK;
if (mode == _P_OVERLAY)
ExitProcess (res);
}
switch (mode) switch (mode)
{ {
case _P_OVERLAY:
proc_terminate ();
ExitProcess (0);
break;
case _P_WAIT: case _P_WAIT:
waitpid (cygpid, (int *) &res, 0); waitpid (cygpid, (int *) &res, 0);
break; break;
@ -945,7 +920,7 @@ _spawnve (HANDLE hToken, int mode, const char *path, const char *const *argv,
case _P_WAIT: case _P_WAIT:
case _P_DETACH: case _P_DETACH:
subproc_init (); subproc_init ();
ret = spawn_guts (hToken, path, argv, envp, 0); ret = spawn_guts (hToken, path, argv, envp, mode);
if (vf && ret > 0) if (vf && ret > 0)
{ {
vf->pid = ret; vf->pid = ret;