OSDN Git Service

* fork.cc (fork_parent): Use sec_user_nih to control process/thread
[pf3gnuchains/pf3gnuchains3x.git] / winsup / cygwin / fork.cc
1 /* fork.cc
2
3    Copyright 1996, 1997, 1998, 1999, 2000, 2001 Red Hat, Inc.
4
5 This file is part of Cygwin.
6
7 This software is a copyrighted work licensed under the terms of the
8 Cygwin license.  Please consult the file "CYGWIN_LICENSE" for
9 details. */
10
11 #include "winsup.h"
12 #include <stdio.h>
13 #include <unistd.h>
14 #include <stdlib.h>
15 #include <fcntl.h>
16 #include <stdarg.h>
17 #include <errno.h>
18 #include "security.h"
19 #include "fhandler.h"
20 #include "path.h"
21 #include "dtable.h"
22 #include "cygerrno.h"
23 #include "sync.h"
24 #include "sigproc.h"
25 #include "pinfo.h"
26 #include "cygheap.h"
27 #include "child_info.h"
28 #define NEED_VFORK
29 #include "perthread.h"
30 #include "perprocess.h"
31 #include "dll_init.h"
32
33 #ifdef DEBUGGING
34 static int npid;
35 static int npid_max;
36 static pid_t fork_pids[100];
37 #endif
38
39 /* Timeout to wait for child to start, parent to init child, etc.  */
40 /* FIXME: Once things stabilize, bump up to a few minutes.  */
41 #define FORK_WAIT_TIMEOUT (300 * 1000)     /* 300 seconds */
42
43 #define dll_data_start &_data_start__
44 #define dll_data_end &_data_end__
45 #define dll_bss_start &_bss_start__
46 #define dll_bss_end &_bss_end__
47
48 void
49 per_thread::set (void *s)
50 {
51   if (s == PER_THREAD_FORK_CLEAR)
52     {
53       tls = TlsAlloc ();
54       s = NULL;
55     }
56   TlsSetValue (get_tls (), s);
57 }
58
59 static void
60 stack_base (child_info_fork &ch)
61 {
62   MEMORY_BASIC_INFORMATION m;
63   memset (&m, 0, sizeof m);
64   if (!VirtualQuery ((LPCVOID) &m, &m, sizeof m))
65     system_printf ("couldn't get memory info, %E");
66
67   ch.stacktop = m.AllocationBase;
68   ch.stackbottom = (LPBYTE) m.BaseAddress + m.RegionSize;
69   ch.stacksize = (DWORD) ch.stackbottom - (DWORD) &m;
70   debug_printf ("bottom %p, top %p, stack %p, size %d, reserve %d",
71                 ch.stackbottom, ch.stacktop, &m, ch.stacksize,
72                 (DWORD) ch.stackbottom - (DWORD) ch.stacktop);
73 }
74
75 /* Copy memory from parent to child.
76    The result is a boolean indicating success.  */
77
78 static int
79 fork_copy (PROCESS_INFORMATION &pi, const char *what, ...)
80 {
81   va_list args;
82   char *low;
83   int pass = 0;
84
85   va_start (args, what);
86
87   while ((low = va_arg (args, char *)))
88     {
89       char *high = va_arg (args, char *);
90       DWORD todo = wincap.chunksize () ?: high - low;
91       char *here;
92
93       for (here = low; here < high; here += todo)
94         {
95           DWORD done = 0;
96           if (here + todo > high)
97             todo = high - here;
98           int res = WriteProcessMemory (pi.hProcess, here, here, todo, &done);
99           debug_printf ("child handle %p, low %p, high %p, res %d", pi.hProcess,
100                         low, high, res);
101           if (!res || todo != done)
102             {
103               if (!res)
104                 __seterrno ();
105               /* If this happens then there is a bug in our fork
106                  implementation somewhere. */
107               system_printf ("%s pass %d failed, %p..%p, done %d, windows pid %u, %E",
108                             what, pass, low, high, done, pi.dwProcessId);
109               goto err;
110             }
111         }
112
113       pass++;
114     }
115
116   debug_printf ("done");
117   return 1;
118
119  err:
120   TerminateProcess (pi.hProcess, 1);
121   set_errno (EAGAIN);
122   return 0;
123 }
124
125 /* Wait for child to finish what it's doing and signal us.
126    We don't want to wait forever here.If there's a problem somewhere
127    it'll hang the entire system (since all forks are mutex'd). If we
128    time out, set errno = EAGAIN and hope the app tries again.  */
129 static int
130 sync_with_child (PROCESS_INFORMATION &pi, HANDLE subproc_ready,
131                  BOOL hang_child, const char *s)
132 {
133   /* We also add the child process handle to the wait. If the child fails
134      to initialize (eg. because of a missing dll). Then this
135      handle will become signalled. This stops a *looong* timeout wait.
136   */
137   HANDLE w4[2];
138
139   debug_printf ("waiting for child.  reason: %s, hang_child %d", s,
140                 hang_child);
141   w4[1] = pi.hProcess;
142   w4[0] = subproc_ready;
143   DWORD rc = WaitForMultipleObjects (2, w4, FALSE, FORK_WAIT_TIMEOUT);
144
145   if (rc == WAIT_OBJECT_0 ||
146       WaitForSingleObject (subproc_ready, 0) == WAIT_OBJECT_0)
147     /* That's ok */;
148   else if (rc == WAIT_FAILED || rc == WAIT_TIMEOUT)
149     {
150       if (rc != WAIT_FAILED)
151         system_printf ("WaitForMultipleObjects timed out");
152       else
153         system_printf ("WaitForMultipleObjects failed, %E");
154       set_errno (EAGAIN);
155       syscall_printf ("-1 = fork(), WaitForMultipleObjects failed");
156       TerminateProcess (pi.hProcess, 1);
157       return 0;
158     }
159   else
160     {
161       /* Child died. Clean up and exit. */
162       DWORD errcode;
163       GetExitCodeProcess (pi.hProcess, &errcode);
164       /* Fix me.  This is not enough.  The fork should not be considered
165        * to have failed if the process was essentially killed by a signal.
166        */
167       if (errcode != STATUS_CONTROL_C_EXIT)
168         {
169             system_printf ("child %d(%p) died before initialization with status code %p",
170                           pi.dwProcessId, pi.hProcess, errcode);
171             system_printf ("*** child state %s", s);
172 #ifdef DEBUGGING
173             abort ();
174 #endif
175         }
176       set_errno (EAGAIN);
177       syscall_printf ("Child died before subproc_ready signalled");
178       return 0;
179     }
180
181   debug_printf ("child signalled me");
182   return 1;
183 }
184
185 static int
186 resume_child (PROCESS_INFORMATION &pi, HANDLE forker_finished)
187 {
188   SetEvent (forker_finished);
189   debug_printf ("signalled child");
190   return 1;
191 }
192
193 /* Notify parent that it is time for the next step.
194    Note that this has to be a macro since the parent may be messing with
195    our stack. */
196 static void __stdcall
197 sync_with_parent(const char *s, bool hang_self)
198 {
199   debug_printf ("signalling parent: %s", s);
200   /* Tell our parent we're waiting. */
201   if (!SetEvent (child_proc_info->subproc_ready))
202     api_fatal ("fork child - SetEvent for %s failed, %E", s);
203   if (hang_self)
204     {
205       HANDLE h = child_proc_info->forker_finished;
206       /* Wait for the parent to fill in our stack and heap.
207          Don't wait forever here.  If our parent dies we don't want to clog
208          the system.  If the wait fails, we really can't continue so exit.  */
209       DWORD psync_rc = WaitForSingleObject (h, FORK_WAIT_TIMEOUT);
210       debug_printf ("awake");
211       switch (psync_rc)
212         {
213         case WAIT_TIMEOUT:
214           api_fatal ("WFSO timed out for %s", s);
215           break;
216         case WAIT_FAILED:
217           if (GetLastError () == ERROR_INVALID_HANDLE &&
218               WaitForSingleObject (child_proc_info->forker_finished, 1) != WAIT_FAILED)
219             break;
220           api_fatal ("WFSO failed for %s, fork_finished %p, %E", s,
221                      child_proc_info->forker_finished);
222           break;
223         default:
224           debug_printf ("no problems");
225           break;
226         }
227     }
228 }
229
230 static int __stdcall
231 fork_child (HANDLE& hParent, dll *&first_dll, bool& load_dlls)
232 {
233   debug_printf ("child is running.  pid %d, ppid %d, stack here %p",
234                 myself->pid, myself->ppid, __builtin_frame_address (0));
235
236   /* Restore the inheritance state as in parent
237      Don't call setuid here! The flags are already set. */
238   if (cygheap->user.impersonated)
239     {
240       debug_printf ("Impersonation of child, token: %d", cygheap->user.token);
241       if (cygheap->user.token == INVALID_HANDLE_VALUE)
242         RevertToSelf (); // probably not needed
243       else if (!ImpersonateLoggedOnUser (cygheap->user.token))
244         system_printf ("Impersonate for forked child failed: %E");
245     }
246
247   sync_with_parent ("after longjmp.", TRUE);
248   ProtectHandle (hParent);
249   sigproc_printf ("hParent %p, child 1 first_dll %p, load_dlls %d\n", hParent,
250                   first_dll, load_dlls);
251
252 #ifdef DEBUGGING
253   char c;
254   if (GetEnvironmentVariable ("FORKDEBUG", &c, 1))
255     try_to_debug ();
256   char buf[80];
257   /* This is useful for debugging fork problems.  Use gdb to attach to
258      the pid reported here. */
259   if (GetEnvironmentVariable ("CYGWIN_FORK_SLEEP", buf, sizeof (buf)))
260     {
261       small_printf ("Sleeping %d after fork, pid %u\n", atoi (buf), GetCurrentProcessId ());
262       Sleep (atoi(buf));
263     }
264 #endif
265
266   /* If we've played with the stack, stacksize != 0.  That means that
267      fork() was invoked from other than the main thread.  Make sure that
268      when the "main" thread exits it calls do_exit, like a normal process.
269      Exit with a status code of 0. */
270   if (child_proc_info->stacksize)
271     {
272       ((DWORD *)child_proc_info->stackbottom)[-17] = (DWORD)do_exit;
273       ((DWORD *)child_proc_info->stackbottom)[-15] = (DWORD)0;
274     }
275
276   set_file_api_mode (current_codepage);
277
278   MALLOC_CHECK;
279
280   debug_fixup_after_fork ();
281   pinfo_fixup_after_fork ();
282   cygheap->fdtab.fixup_after_fork (hParent);
283   signal_fixup_after_fork ();
284
285   MALLOC_CHECK;
286
287   /* If we haven't dynamically loaded any dlls, just signal
288      the parent.  Otherwise, load all the dlls, tell the parent
289       that we're done, and wait for the parent to fill in the.
290       loaded dlls' data/bss. */
291   if (!load_dlls)
292     sync_with_parent ("performed fork fixup.", FALSE);
293   else
294     {
295       dlls.load_after_fork (hParent, first_dll);
296       sync_with_parent ("loaded dlls", TRUE);
297     }
298
299   ForceCloseHandle (hParent);
300   (void) ForceCloseHandle (child_proc_info->subproc_ready);
301   (void) ForceCloseHandle (child_proc_info->forker_finished);
302
303   if (fixup_mmaps_after_fork ())
304     api_fatal ("recreate_mmaps_after_fork_failed");
305
306   /* Set thread local stuff to zero.  Under Windows 95/98 this is sometimes
307      non-zero, for some reason.
308      FIXME:  There is a memory leak here after a fork. */
309   for (per_thread **t = threadstuff; *t; t++)
310     if ((*t)->clear_on_fork ())
311       (*t)->set ();
312
313   user_data->threadinterface->fixup_after_fork ();
314
315   /* Initialize signal/process handling */
316   sigproc_init ();
317   __pthread_atforkchild ();
318   cygbench ("fork-child");
319   return 0;
320 }
321
322 static void
323 slow_pid_reuse (HANDLE h)
324 {
325   static NO_COPY HANDLE last_fork_procs[8] = {0};
326   static NO_COPY unsigned nfork_procs = 0;
327
328   if (nfork_procs >= (sizeof (last_fork_procs) / sizeof (last_fork_procs [0])))
329     nfork_procs = 0;
330   /* Keep a list of handles to forked processes sitting around to prevent
331      Windows from reusing the same pid n times in a row.  Having the same pids
332      close in succesion confuses bash.  Keeping a handle open will stop
333      windows from reusing the same pid.  */
334   if (last_fork_procs[nfork_procs])
335     ForceCloseHandle1 (last_fork_procs[nfork_procs], fork_stupidity);
336   if (DuplicateHandle (hMainProc, h, hMainProc, &last_fork_procs[nfork_procs],
337                         0, FALSE, DUPLICATE_SAME_ACCESS))
338     ProtectHandle1 (last_fork_procs[nfork_procs], fork_stupidity);
339   else
340     {
341       last_fork_procs[nfork_procs] = NULL;
342       system_printf ("couldn't create last_fork_proc, %E");
343     }
344   nfork_procs++;
345 }
346
347 static int __stdcall
348 fork_parent (HANDLE& hParent, dll *&first_dll,
349              bool& load_dlls, void *stack_here, child_info_fork &ch)
350 {
351   HANDLE subproc_ready, forker_finished;
352   DWORD rc;
353   PROCESS_INFORMATION pi = {0, NULL, 0, 0};
354
355   /* call the pthread_atfork prepare functions */
356   __pthread_atforkprepare ();
357
358   subproc_init ();
359
360 #ifdef DEBUGGING_NOTNEEDED
361   /* The ProtectHandle call allocates memory so we need to make sure
362      that enough is set aside here so that the sbrk pointer does not
363      move when ProtectHandle is called after the child is started.
364      Otherwise the sbrk pointers in the parent will not agree with
365      the child and when user_data is (regrettably) copied over,
366      the user_data->ptr field will not be accurate. */
367   free (malloc (4096));
368 #endif
369
370   int c_flags = GetPriorityClass (hMainProc) /*|
371                 CREATE_NEW_PROCESS_GROUP*/;
372   STARTUPINFO si = {0, NULL, NULL, NULL, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, NULL, NULL, NULL, NULL};
373
374   /* If we don't have a console, then don't create a console for the
375      child either.  */
376   HANDLE console_handle = CreateFileA ("CONOUT$", GENERIC_WRITE,
377                                        FILE_SHARE_WRITE, &sec_none_nih,
378                                        OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL,
379                                        NULL);
380
381   if (console_handle != INVALID_HANDLE_VALUE && console_handle != 0)
382     CloseHandle (console_handle);
383   else
384     c_flags |= DETACHED_PROCESS;
385
386   /* Some file types (currently only sockets) need extra effort in the
387      parent after CreateProcess and before copying the datastructures
388      to the child. So we have to start the child in suspend state,
389      unfortunately, to avoid a race condition. */
390   if (cygheap->fdtab.need_fixup_before ())
391     c_flags |= CREATE_SUSPENDED;
392
393   /* Create an inheritable handle to pass to the child process.  This will
394      allow the child to duplicate handles from the parent to itself. */
395   hParent = NULL;
396   if (!DuplicateHandle (hMainProc, hMainProc, hMainProc, &hParent, 0, 1,
397                         DUPLICATE_SAME_ACCESS))
398     {
399       system_printf ("couldn't create handle to myself for child, %E");
400       return -1;
401     }
402
403   /* Remember the address of the first loaded dll and decide
404      if we need to load dlls.  We do this here so that this
405      information will be available in the parent and, when
406      the stack is copied, in the child. */
407   first_dll = dlls.start.next;
408   load_dlls = dlls.reload_on_fork && dlls.loaded_dlls;
409
410   /* This will help some of the confusion.  */
411   fflush (stdout);
412
413   subproc_ready = CreateEvent (&sec_all, FALSE, FALSE, NULL);
414   if (subproc_ready == NULL)
415     {
416       CloseHandle (hParent);
417       system_printf ("unable to allocate subproc_ready event, %E");
418       return -1;
419     }
420   forker_finished = CreateEvent (&sec_all, FALSE, FALSE, NULL);
421   if (forker_finished == NULL)
422     {
423       CloseHandle (hParent);
424       CloseHandle (subproc_ready);
425       system_printf ("unable to allocate forker_finished event, %E");
426       return -1;
427     }
428
429   ProtectHandle (subproc_ready);
430   ProtectHandle (forker_finished);
431
432   init_child_info (PROC_FORK, &ch, 1, subproc_ready);
433
434   ch.forker_finished = forker_finished;
435
436   stack_base (ch);
437
438   si.cb = sizeof (STARTUPINFO);
439   si.lpReserved2 = (LPBYTE)&ch;
440   si.cbReserved2 = sizeof(ch);
441
442   /* Remove impersonation */
443   if (cygheap->user.impersonated && cygheap->user.token != INVALID_HANDLE_VALUE)
444     RevertToSelf ();
445
446   ch.parent = hParent;
447 #ifdef DEBUGGING
448   if (npid_max)
449     {
450       for (int pass = 0; pass < 2; pass++)
451         {
452           pid_t pid;
453           while ((pid = fork_pids[npid++]))
454             if (!pinfo (pid))
455               {
456                 ch.cygpid = pid;
457                 goto out;
458               }
459           npid = 0;
460         }
461     }
462  out:
463 #endif
464
465   char sa_buf[1024];
466   syscall_printf ("CreateProcess (%s, %s, 0, 0, 1, %x, 0, 0, %p, %p)",
467                   myself->progname, myself->progname, c_flags, &si, &pi);
468   __malloc_lock (_reent_clib ());
469   void *newheap;
470   newheap = cygheap_setup_for_child (&ch,cygheap->fdtab.need_fixup_before ());
471   rc = CreateProcess (myself->progname, /* image to run */
472                       myself->progname, /* what we send in arg0 */
473                       sec_user_nih (sa_buf),
474                       sec_user_nih (sa_buf),
475                       TRUE,       /* inherit handles from parent */
476                       c_flags,
477                       NULL,       /* environment filled in later */
478                       0,          /* use current drive/directory */
479                       &si,
480                       &pi);
481
482   CloseHandle (hParent);
483
484   if (!rc)
485     {
486       __seterrno ();
487       syscall_printf ("CreateProcessA failed, %E");
488       ForceCloseHandle(subproc_ready);
489       ForceCloseHandle(forker_finished);
490       /* Restore impersonation */
491       if (cygheap->user.impersonated
492           && cygheap->user.token != INVALID_HANDLE_VALUE)
493         ImpersonateLoggedOnUser (cygheap->user.token);
494       cygheap_setup_for_child_cleanup (newheap, &ch, 0);
495       return -1;
496     }
497
498   /* Fixup the parent datastructure if needed and resume the child's
499      main thread. */
500   if (!cygheap->fdtab.need_fixup_before ())
501     cygheap_setup_for_child_cleanup (newheap, &ch, 0);
502   else
503     {
504       cygheap->fdtab.fixup_before_fork (pi.dwProcessId);
505       cygheap_setup_for_child_cleanup (newheap, &ch, 1);
506       ResumeThread (pi.hThread);
507     }
508
509 #ifdef DEBUGGING
510   pinfo forked ((ch.cygpid != 1 ? ch.cygpid : cygwin_pid (pi.dwProcessId)), 1);
511 #else
512   pinfo forked (cygwin_pid (pi.dwProcessId), 1);
513 #endif
514
515   /* Initialize things that are done later in dll_crt0_1 that aren't done
516      for the forkee.  */
517   strcpy(forked->progname, myself->progname);
518
519   /* Restore impersonation */
520   if (cygheap->user.impersonated && cygheap->user.token != INVALID_HANDLE_VALUE)
521     ImpersonateLoggedOnUser (cygheap->user.token);
522
523   ProtectHandle (pi.hThread);
524   /* Protect the handle but name it similarly to the way it will
525      be called in subproc handling. */
526   ProtectHandle1 (pi.hProcess, childhProc);
527
528   /* Fill in fields in the child's process table entry.  */
529   forked->hProcess = pi.hProcess;
530   forked->dwProcessId = pi.dwProcessId;
531   forked->copysigs(myself);
532
533   /* Hopefully, this will succeed.  The alternative to doing things this
534      way is to reserve space prior to calling CreateProcess and then fill
535      it in afterwards.  This requires more bookkeeping than I like, though,
536      so we'll just do it the easy way.  So, terminate any child process if
537      we can't actually record the pid in the internal table. */
538   if (!forked.remember ())
539     {
540       TerminateProcess (pi.hProcess, 1);
541       set_errno (EAGAIN);
542       goto cleanup;
543     }
544
545   slow_pid_reuse (pi.hProcess);
546
547   /* Wait for subproc to initialize itself. */
548   if (!sync_with_child (pi, subproc_ready, TRUE, "waiting for longjmp"))
549     goto cleanup;
550
551   /* CHILD IS STOPPED */
552   debug_printf ("child is alive (but stopped)");
553
554   /* Initialize, in order: data, bss, heap, stack, dll data, dll bss
555      Note: variables marked as NO_COPY will not be copied
556      since they are placed in a protected segment. */
557
558
559   MALLOC_CHECK;
560   rc = fork_copy (pi, "user/cygwin data",
561                   user_data->data_start, user_data->data_end,
562                   user_data->bss_start, user_data->bss_end,
563                   cygheap->heapbase, cygheap->heapptr,
564                   stack_here, ch.stackbottom,
565                   dll_data_start, dll_data_end,
566                   dll_bss_start, dll_bss_end, NULL);
567
568   __malloc_unlock (_reent_clib ());
569   MALLOC_CHECK;
570   if (!rc)
571     goto cleanup;
572
573   /* Now fill data/bss of any DLLs that were linked into the program. */
574   for (dll *d = dlls.istart (DLL_LINK); d; d = dlls.inext ())
575     {
576       debug_printf ("copying data/bss of a linked dll");
577       if (!fork_copy (pi, "linked dll data/bss", d->p.data_start, d->p.data_end,
578                                                  d->p.bss_start, d->p.bss_end,
579                                                  NULL))
580         goto cleanup;
581     }
582
583   /* Start thread, and wait for it to reload dlls.  */
584   if (!resume_child (pi, forker_finished) ||
585       !sync_with_child (pi, subproc_ready, load_dlls, "child loading dlls"))
586     goto cleanup;
587
588   /* If DLLs were loaded in the parent, then the child has reloaded all
589      of them and is now waiting to have all of the individual data and
590      bss sections filled in. */
591   if (load_dlls)
592     {
593       /* CHILD IS STOPPED */
594       /* write memory of reloaded dlls */
595       for (dll *d = dlls.istart (DLL_LOAD); d; d = dlls.inext ())
596         {
597           debug_printf ("copying data/bss for a loaded dll");
598           if (!fork_copy (pi, "loaded dll data/bss", d->p.data_start, d->p.data_end,
599                                                      d->p.bss_start, d->p.bss_end,
600                                                      NULL))
601             goto cleanup;
602         }
603       /* Start the child up again. */
604       (void) resume_child (pi, forker_finished);
605     }
606
607   ForceCloseHandle (subproc_ready);
608   ForceCloseHandle (pi.hThread);
609   ForceCloseHandle (forker_finished);
610   forker_finished = NULL;
611   pi.hThread = NULL;
612   __pthread_atforkparent ();
613
614   return forked->pid;
615
616 /* Common cleanup code for failure cases */
617  cleanup:
618   /* Remember to de-allocate the fd table. */
619   if (pi.hProcess)
620     ForceCloseHandle1 (pi.hProcess, childhProc);
621   if (pi.hThread)
622     ForceCloseHandle (pi.hThread);
623   if (subproc_ready)
624     ForceCloseHandle (subproc_ready);
625   if (forker_finished)
626     ForceCloseHandle (forker_finished);
627   return -1;
628 }
629
630 extern "C" int
631 fork ()
632 {
633   struct
634   {
635     HANDLE hParent;
636     dll *first_dll;
637     bool load_dlls;
638   } grouped;
639
640   MALLOC_CHECK;
641   sigframe thisframe (mainthread);
642
643   debug_printf ("entering");
644   grouped.hParent = grouped.first_dll = NULL;
645   grouped.load_dlls = 0;
646
647   if (ISSTATE(myself, PID_SPLIT_HEAP))
648     {
649       system_printf ("The heap has been split, CYGWIN can't fork this process.");
650       system_printf ("Increase the heap_chunk_size in the registry and try again.");
651       set_errno (ENOMEM);
652       syscall_printf ("-1 = fork (), split heap");
653       return -1;
654     }
655
656   void *esp;
657   __asm__ volatile ("movl %%esp,%0": "=r" (esp));
658
659   myself->set_has_pgid_children ();
660
661   child_info_fork ch;
662
663   int res = setjmp (ch.jmp);
664
665   if (res)
666     res = fork_child (grouped.hParent, grouped.first_dll, grouped.load_dlls);
667   else
668     res = fork_parent (grouped.hParent, grouped.first_dll, grouped.load_dlls, esp, ch);
669
670   MALLOC_CHECK;
671   syscall_printf ("%d = fork()", res);
672   return res;
673 }
674 #ifdef DEBUGGING
675 void
676 fork_init ()
677 {
678   char buf[1024];
679   if (!GetEnvironmentVariable ("CYGWIN_FORK_PIDS", buf, 1024))
680     return;
681   pid_t pid;
682   char *p, *pe;
683   for (p = buf; (pid = strtol (p, &pe, 10)); p = pe)
684     fork_pids[npid_max++] = pid;
685 }
686 #endif /*DEBUGGING*/
687
688 #ifdef NEWVFORK
689 /* Dummy function to force second assignment below to actually be
690    carried out */
691 static vfork_save *
692 get_vfork_val ()
693 {
694   return vfork_storage.val ();
695 }
696 #endif
697
698 extern "C"
699 int
700 vfork ()
701 {
702 #ifndef NEWVFORK
703   return fork ();
704 #else
705   sigframe thisframe;
706   vfork_save *vf = get_vfork_val ();
707   char **esp, **pp;
708
709   if (vf == NULL)
710     vf = vfork_storage.create ();
711   else if (vf->pid)
712     return fork ();
713
714   if (!setjmp (vf->j))
715     {
716       vf->pid = -1;
717       __asm__ volatile ("movl %%esp,%0": "=r" (vf->vfork_esp):);
718       __asm__ volatile ("movl %%ebp,%0": "=r" (vf->vfork_ebp):);
719       for (pp = (char **)vf->frame, esp = vf->vfork_esp;
720            esp <= vf->vfork_ebp + 2; pp++, esp++)
721         *pp = *esp;
722       int res = cygheap->fdtab.vfork_child_dup () ? 0 : -1;
723       debug_printf ("%d = vfork()", res);
724       debug_printf ("exiting vfork, res %d", res);
725       return res;
726     }
727
728   vf = get_vfork_val ();
729
730   for (pp = (char **)vf->frame, esp = vf->vfork_esp;
731        esp <= vf->vfork_ebp + 2; pp++, esp++)
732     *esp = *pp;
733
734   thisframe.init (mainthread);
735   cygheap->fdtab.vfork_parent_restore ();
736
737   if (vf->pid < 0)
738     {
739       int exitval = -vf->pid;
740       vf->pid = 0;
741       if ((vf->pid = fork ()) == 0)
742         exit (exitval);
743     }
744
745   int pid = vf->pid;
746   vf->pid = 0;
747   debug_printf ("exiting vfork, pid %d", pid);
748   sig_dispatch_pending ();
749   return pid;
750 #endif
751 }