G:/ScriptBasic/source/tools/fork.c

Go to the documentation of this file.
00001 /* fork.cc
00002 
00003    Copyright 1996, 1997, 1998, 1999, 2000 Cygnus Solutions.
00004 
00005 This file is part of Cygwin.
00006 
00007 This software is a copyrighted work licensed under the terms of the
00008 Cygwin license.  Please consult the file "CYGWIN_LICENSE" for
00009 details. */
00010 
00011 #include <stdio.h>
00012 #include <unistd.h>
00013 #include <stdlib.h>
00014 #include <fcntl.h>
00015 #include <stdarg.h>
00016 #include <errno.h>
00017 #include "winsup.h"
00018 #include "dll_init.h"
00019 
00020 DWORD NO_COPY chunksize = 0;
00021 /* Timeout to wait for child to start, parent to init child, etc.  */
00022 /* FIXME: Once things stabilize, bump up to a few minutes.  */
00023 #define FORK_WAIT_TIMEOUT (300 * 1000)     /* 300 seconds */
00024 
00025 #define dll_data_start &_data_start__
00026 #define dll_data_end &_data_end__
00027 #define dll_bss_start &_bss_start__
00028 #define dll_bss_end &_bss_end__
00029 
00030 void
00031 per_thread::set (void *s)
00032   {
00033     if (s == PER_THREAD_FORK_CLEAR)
00034       {
00035         tls = TlsAlloc ();
00036         s = NULL;
00037       }
00038     TlsSetValue (get_tls (), s);
00039   }
00040 
00041 static void
00042 stack_base (child_info_fork &ch)
00043 {
00044   MEMORY_BASIC_INFORMATION m;
00045   memset (&m, 0, sizeof m);
00046   if (!VirtualQuery ((LPCVOID) &m, &m, sizeof m))
00047     system_printf ("couldn't get memory info, %E");
00048 
00049   ch.stacktop = m.AllocationBase;
00050   ch.stackbottom = (LPBYTE) m.BaseAddress + m.RegionSize;
00051   ch.stacksize = (DWORD) ch.stackbottom - (DWORD) &m;
00052   debug_printf ("bottom %p, top %p, stack %p, size %d, reserve %d",
00053                 ch.stackbottom, ch.stacktop, &m, ch.stacksize,
00054                 (DWORD) ch.stackbottom - (DWORD) ch.stacktop);
00055 }
00056 
00057 /* Copy memory from parent to child.
00058    The result is a boolean indicating success.  */
00059 
00060 static int
00061 fork_copy (PROCESS_INFORMATION &pi, const char *what, ...)
00062 {
00063   va_list args;
00064   char *low;
00065   int pass = 0;
00066 
00067   va_start (args, what);
00068 
00069   while ((low = va_arg (args, char *)))
00070     {
00071       char *high = va_arg (args, char *);
00072       DWORD todo = chunksize ?: high - low;
00073       char *here;
00074 
00075       for (here = low; here < high; here += todo)
00076         {
00077           DWORD done = 0;
00078           if (here + todo > high)
00079             todo = high - here;
00080           int res = WriteProcessMemory (pi.hProcess, here, here, todo, &done);
00081           debug_printf ("child handle %p, low %p, high %p, res %d", pi.hProcess,
00082                         low, high, res);
00083           if (!res || todo != done)
00084             {
00085               if (!res)
00086                 __seterrno ();
00087               /* If this happens then there is a bug in our fork
00088                  implementation somewhere. */
00089               system_printf ("%s pass %d failed, %p..%p, done %d, %E",
00090                             what, pass, low, high, done);
00091               goto err;
00092             }
00093         }
00094 
00095       pass++;
00096     }
00097 
00098   debug_printf ("done");
00099   return 1;
00100 
00101 err:
00102   TerminateProcess (pi.hProcess, 1);
00103   set_errno (EAGAIN);
00104   return 0;
00105 }
00106 
00107 /* Wait for child to finish what it's doing and signal us.
00108    We don't want to wait forever here.If there's a problem somewhere
00109    it'll hang the entire system (since all forks are mutex'd). If we
00110    time out, set errno = EAGAIN and hope the app tries again.  */
00111 static int
00112 sync_with_child (PROCESS_INFORMATION &pi, HANDLE subproc_ready,
00113                  BOOL hang_child, const char *s)
00114 {
00115   /* We also add the child process handle to the wait. If the child fails
00116      to initialize (eg. because of a missing dll). Then this
00117      handle will become signalled. This stops a *looong* timeout wait.
00118   */
00119   HANDLE w4[2];
00120 
00121   debug_printf ("waiting for child.  reason: %s", s);
00122   w4[1] = pi.hProcess;
00123   w4[0] = subproc_ready;
00124   DWORD rc = WaitForMultipleObjects (2, w4, FALSE, FORK_WAIT_TIMEOUT);
00125 
00126   if (rc == WAIT_OBJECT_0 ||
00127       WaitForSingleObject (subproc_ready, 0) == WAIT_OBJECT_0)
00128     /* That's ok */;
00129   else if (rc == WAIT_FAILED || rc == WAIT_TIMEOUT)
00130     {
00131       if (rc != WAIT_FAILED)
00132         system_printf ("WaitForMultipleObjects timed out");
00133       else
00134         system_printf ("WaitForMultipleObjects failed, %E");
00135       set_errno (EAGAIN);
00136       syscall_printf ("-1 = fork(), WaitForMultipleObjects failed");
00137       TerminateProcess (pi.hProcess, 1);
00138       return 0;
00139     }
00140   else
00141     {
00142       /* Child died. Clean up and exit. */
00143       DWORD errcode;
00144       GetExitCodeProcess (pi.hProcess, &errcode);
00145       /* Fix me.  This is not enough.  The fork should not be considered
00146        * to have failed if the process was essentially killed by a signal.
00147        */
00148       if (errcode != STATUS_CONTROL_C_EXIT)
00149         {
00150             system_printf ("child %d(%p) died before initialization with status code %p",
00151                           pi.dwProcessId, pi.hProcess, errcode);
00152             system_printf ("*** child state %s", s);
00153 #ifdef DEBUGGING
00154             abort ();
00155 #endif
00156         }
00157       set_errno (EAGAIN);
00158       syscall_printf ("Child died before subproc_ready signalled");
00159       return 0;
00160     }
00161 
00162   debug_printf ("child signalled me");
00163   if (hang_child)
00164     {
00165       int n = SuspendThread (pi.hThread);
00166       debug_printf ("suspend count %d", n); \
00167     }
00168   return 1;
00169 }
00170 
00171 static int
00172 resume_child (PROCESS_INFORMATION &pi, HANDLE forker_finished)
00173 {
00174   int rc;
00175 
00176   debug_printf ("here");
00177   SetEvent (forker_finished);
00178 
00179   rc = ResumeThread (pi.hThread);
00180 
00181   debug_printf ("rc %d", rc);
00182   if (rc == 1)
00183     return 1;           // Successful resumption
00184 
00185   /* Can't resume the thread.  Not sure why this would happen unless
00186      there's a bug in the system.  Things seem to be working OK now
00187      though, so flag this with EAGAIN, but print a message on the
00188      console.  */
00189   small_printf ("fork: ResumeThread failed, rc = %d, %E\n", rc);
00190   set_errno (EAGAIN);
00191   syscall_printf ("-1 = fork(), ResumeThread failed");
00192   TerminateProcess (pi.hProcess, 1);
00193   return 0;
00194 }
00195 
00196 /* Notify parent that it is time for the next step.
00197    Note that this has to be a macro since the parent may be messing with
00198    our stack. */
00199 #define sync_with_parent(s, hang_self) \
00200 ((void) ({ \
00201   debug_printf ("signalling parent: %s", s); \
00202   /* Tell our parent we're waiting. */ \
00203   if (!SetEvent (child_proc_info->subproc_ready)) \
00204     api_fatal ("fork child - SetEvent failed, %E"); \
00205   if (hang_self) \
00206     { \
00207       /* Wait for the parent to fill in our stack and heap. \
00208          Don't wait forever here.  If our parent dies we don't want to clog \
00209          the system.  If the wait fails, we really can't continue so exit.  */ \
00210       DWORD psync_rc = WaitForSingleObject (child_proc_info->forker_finished, FORK_WAIT_TIMEOUT); \
00211       switch (psync_rc) \
00212         { \
00213         case WAIT_TIMEOUT: \
00214           api_fatal ("sync_with_parent - WFSO timed out"); \
00215           break; \
00216         case WAIT_FAILED: \
00217           if (GetLastError () == ERROR_INVALID_HANDLE && \
00218               WaitForSingleObject (child_proc_info->forker_finished, 1) != WAIT_FAILED) \
00219             break; \
00220           api_fatal ("sync_with_parent - WFSO failed, fork_finished %p, %E", child_proc_info->forker_finished); \
00221           break; \
00222         default: \
00223           break; \
00224         } \
00225       debug_printf ("awake"); \
00226     } \
00227   0; \
00228 }))
00229 
00230 static volatile void grow_stack_slack();
00231 
00232 static void *
00233 stack_dummy (int here)
00234 {
00235   return &here;
00236 }
00237 
00238 extern "C" int
00239 fork ()
00240 {
00241   int res;
00242   DWORD rc;
00243   HANDLE hParent;
00244   pinfo *child;
00245   HANDLE subproc_ready, forker_finished;
00246   void *stack_here;
00247   int x;
00248   PROCESS_INFORMATION pi = {0, NULL, 0, 0};
00249 
00250   MALLOC_CHECK;
00251 
00252   /* FIXME: something is broken when copying the stack from the parent
00253      to the child; we try various tricks here to make sure that the
00254      stack is good enough to prevent page faults, but the true cause
00255      is still unknown.  DJ */
00256   volatile char dummy[4096];
00257   dummy[0] = dummy[4095] = 0;   // Just to leave some slack in the stack
00258 
00259   grow_stack_slack ();
00260 
00261   debug_printf ("entering");
00262   /* Calculate how much of stack to copy to child */
00263   stack_here = stack_dummy (0);
00264 
00265   if (ISSTATE(myself, PID_SPLIT_HEAP))
00266     {
00267       system_printf ("The heap has been split, CYGWIN can't fork this process.");
00268       system_printf ("Increase the heap_chunk_size in the registry and try again.");
00269       set_errno (ENOMEM);
00270       syscall_printf ("-1 = fork (), split heap");
00271       return -1;
00272     }
00273 
00274   /* Don't start the fork until we have the lock.  */
00275   child = cygwin_shared->p.allocate_pid ();
00276   if (!child)
00277     {
00278       set_errno (EAGAIN);
00279       syscall_printf ("-1 = fork (), process table full");
00280       return -1;
00281     }
00282 
00283   /* Remember the address of the first loaded dll and decide
00284      if we need to load dlls.  We do this here so that this
00285      information will be available in the parent and, when
00286      the stack is copied, in the child. */
00287   dll *first_dll = dlls.start.next;
00288   int load_dlls = dlls.reload_on_fork && dlls.loaded_dlls;
00289 
00290   static child_info_fork ch;
00291   x = setjmp (ch.jmp);
00292 
00293   if (x == 0)
00294     {
00295 
00296       /* This will help some of the confusion.  */
00297       fflush (stdout);
00298 
00299       debug_printf ("parent pid %d, child pid %d", myself->pid, child->pid);
00300 
00301       subproc_ready = CreateEvent (&sec_all, FALSE, FALSE, NULL);
00302       forker_finished = CreateEvent (&sec_all, FALSE, FALSE, NULL);
00303       ProtectHandle (subproc_ready);
00304       ProtectHandle (forker_finished);
00305 
00306       /* If we didn't obtain all the resources we need to fork, allow the program
00307          to continue, but record the fact that fork won't work.  */
00308       if (forker_finished == NULL || subproc_ready == NULL)
00309         {
00310           system_printf ("unable to allocate fork() resources.");
00311           system_printf ("fork() disabled.");
00312           return -1;
00313         }
00314 
00315       subproc_init ();
00316 
00317       debug_printf ("about to call setjmp");
00318       /* Parent.  */
00319 #ifdef DEBUGGING
00320       /* The ProtectHandle call allocates memory so we need to make sure
00321          that enough is set aside here so that the sbrk pointer does not
00322          move when ProtectHandle is called after the child is started.
00323          Otherwise the sbrk pointers in the parent will not agree with
00324          the child and when user_data is (regrettably) copied over,
00325          the user_data->ptr field will not be accurate. */
00326       free (malloc (4096));
00327 #endif
00328 
00329       init_child_info (PROC_FORK1, &ch, child->pid, subproc_ready);
00330 
00331       ch.forker_finished = forker_finished;
00332       ch.heaptop = user_data->heaptop;
00333       ch.heapbase = user_data->heapbase;
00334       ch.heapptr = user_data->heapptr;
00335 
00336       stack_base (ch);
00337 
00338       /* Initialize things that are done later in dll_crt0_1 that aren't done
00339          for the forkee.  */
00340       strcpy(child->progname, myself->progname);
00341 
00342       STARTUPINFO si = {0, NULL, NULL, NULL, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, NULL, NULL, NULL, NULL};
00343 
00344       si.cb = sizeof (STARTUPINFO);
00345       si.lpReserved2 = (LPBYTE)&ch;
00346       si.cbReserved2 = sizeof(ch);
00347 
00348       int c_flags = GetPriorityClass (hMainProc) /*|
00349                     CREATE_NEW_PROCESS_GROUP*/;
00350 
00351       /* If we don't have a console, then don't create a console for the
00352          child either.  */
00353       HANDLE console_handle = CreateFileA ("CONOUT$", GENERIC_WRITE,
00354                                            FILE_SHARE_WRITE, &sec_none_nih,
00355                                            OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL,
00356                                            NULL);
00357 
00358       syscall_printf ("CreateProcessA (%s, %s,0,0,1,%x, 0,0,%p,%p)",
00359                       myself->progname, myself->progname, c_flags, &si, &pi);
00360       if (console_handle != INVALID_HANDLE_VALUE && console_handle != 0)
00361         CloseHandle (console_handle);
00362       else
00363         c_flags |= DETACHED_PROCESS;
00364 
00365       hParent = NULL;
00366       if (!DuplicateHandle (hMainProc, hMainProc, hMainProc, &hParent, 0, 1,
00367                            DUPLICATE_SAME_ACCESS))
00368         {
00369           system_printf ("couldn't create handle to myself for child, %E");
00370           goto cleanup;
00371         }
00372 
00373       /* Remove impersonation */
00374       uid_t uid = geteuid();
00375       if (myself->impersonated && myself->token != INVALID_HANDLE_VALUE)
00376         seteuid (myself->orig_uid);
00377 
00378       char sa_buf[1024];
00379       rc = CreateProcessA (myself->progname, /* image to run */
00380                            myself->progname, /* what we send in arg0 */
00381                            allow_ntsec ? sec_user (sa_buf) : &sec_none_nih,
00382                            allow_ntsec ? sec_user (sa_buf) : &sec_none_nih,
00383                            TRUE,          /* inherit handles from parent */
00384                            c_flags,
00385                            NULL,          /* environment filled in later */
00386                            0,             /* use current drive/directory */
00387                            &si,
00388                            &pi);
00389 
00390       CloseHandle (hParent);
00391 
00392       if (!rc)
00393         {
00394           __seterrno ();
00395           syscall_printf ("-1 = fork(), CreateProcessA failed");
00396           child->process_state = PID_NOT_IN_USE;
00397           ForceCloseHandle(subproc_ready);
00398           ForceCloseHandle(forker_finished);
00399           subproc_ready = forker_finished = NULL;
00400           /* Restore impersonation */
00401           if (myself->impersonated && myself->token != INVALID_HANDLE_VALUE)
00402             seteuid (uid);
00403           return -1;
00404         }
00405 
00406       /* Restore impersonation */
00407       if (myself->impersonated && myself->token != INVALID_HANDLE_VALUE)
00408         seteuid (uid);
00409 
00410       ProtectHandle (pi.hThread);
00411       /* Protect the handle but name it similarly to the way it will
00412          be called in subproc handling. */
00413       ProtectHandle1 (pi.hProcess, childhProc);
00414 
00415       /* Fill in fields in the child's process table entry.  */
00416       child->ppid = myself->pid;
00417       child->hProcess = pi.hProcess;
00418       child->dwProcessId = pi.dwProcessId;
00419       child->uid = myself->uid;
00420       child->gid = myself->gid;
00421       child->pgid = myself->pgid;
00422       child->sid = myself->sid;
00423       child->ctty = myself->ctty;
00424       child->umask = myself->umask;
00425       child->copysigs(myself);
00426       child->process_state |= PID_INITIALIZING |
00427                               (myself->process_state & PID_USETTY);
00428       memcpy (child->username, myself->username, MAX_USER_NAME);
00429       memcpy (child->sidbuf, myself->sidbuf, MAX_SID_LEN);
00430       if (myself->psid)
00431         child->psid = child->sidbuf;
00432       memcpy (child->logsrv, myself->logsrv, MAX_HOST_NAME);
00433       memcpy (child->domain, myself->domain, MAX_COMPUTERNAME_LENGTH+1);
00434       child->token = myself->token;
00435       child->impersonated = myself->impersonated;
00436       child->orig_uid = myself->orig_uid;
00437       child->orig_gid = myself->orig_gid;
00438       child->real_uid = myself->real_uid;
00439       child->real_gid = myself->real_gid;
00440       memcpy (child->root, myself->root, MAX_PATH+1);
00441       child->rootlen = myself->rootlen;
00442       set_child_mmap_ptr (child);
00443 
00444       /* Wait for subproc to initialize itself. */
00445       if (!sync_with_child(pi, subproc_ready, TRUE, "waiting for longjmp"))
00446         goto cleanup;
00447 
00448       /* CHILD IS STOPPED */
00449       debug_printf ("child is alive (but stopped)");
00450 
00451       /* Initialize, in order: data, bss, heap, stack, dll data, dll bss
00452          Note: variables marked as NO_COPY will not be copied
00453          since they are placed in a protected segment. */
00454 
00455 
00456       MALLOC_CHECK;
00457       rc = fork_copy (pi, "user/cygwin data",
00458                       user_data->data_start, user_data->data_end,
00459                       user_data->bss_start, user_data->bss_end,
00460                       ch.heapbase, ch.heapptr,
00461                       stack_here, ch.stackbottom,
00462                       dll_data_start, dll_data_end,
00463                       dll_bss_start, dll_bss_end, NULL);
00464 
00465       MALLOC_CHECK;
00466       if (!rc)
00467         goto cleanup;
00468 
00469       /* Now fill data/bss of any DLLs that were linked into the program. */
00470       for (dll *d = dlls.istart (DLL_LINK); d; d = dlls.inext ())
00471         {
00472           debug_printf ("copying data/bss of a linked dll");
00473           if (!fork_copy (pi, "linked dll data/bss", d->p.data_start, d->p.data_end,
00474                                                      d->p.bss_start, d->p.bss_end,
00475                                                      NULL))
00476             goto cleanup;
00477         }
00478 
00479       proc_register (child);
00480 
00481       /* Start thread, and wait for it to reload dlls.  */
00482       if (!resume_child (pi, forker_finished) ||
00483           !sync_with_child (pi, subproc_ready, load_dlls, "child loading dlls"))
00484         goto cleanup;
00485 
00486       /* If DLLs were loaded in the parent, then the child has reloaded all
00487          of them and is now waiting to have all of the individual data and
00488          bss sections filled in. */
00489       if (load_dlls)
00490         {
00491           /* CHILD IS STOPPED */
00492           /* write memory of reloaded dlls */
00493           for (dll *d = dlls.istart (DLL_LOAD); d; d = dlls.inext ())
00494             {
00495               debug_printf ("copying data/bss for a loaded dll");
00496               if (!fork_copy (pi, "loaded dll data/bss", d->p.data_start, d->p.data_end,
00497                                                          d->p.bss_start, d->p.bss_end,
00498                                                          NULL))
00499                 goto cleanup;
00500             }
00501           /* Start the child up again. */
00502           (void) resume_child (pi, forker_finished);
00503         }
00504 
00505       ForceCloseHandle (subproc_ready);
00506       ForceCloseHandle (pi.hThread);
00507       ForceCloseHandle (forker_finished);
00508       forker_finished = NULL;
00509       pi.hThread = NULL;
00510 
00511       res = child->pid;
00512     }
00513   else
00514     {
00515       /**** Child *****/
00516 
00517       /* We arrive here via a longjmp from "crt0".  */
00518       (void) stack_dummy (0);           // Just to make sure
00519       debug_printf ("child is running %d", x);
00520 
00521       debug_printf ("self %p, pid %d, ppid %d",
00522                     myself, x, myself ? myself->ppid : -1);
00523 
00524       /* Restore the inheritance state as in parent
00525          Don't call setuid here! The flags are already set. */
00526       if (myself->impersonated)
00527         {
00528           debug_printf ("Impersonation of child, token: %d", myself->token);
00529           if (myself->token == INVALID_HANDLE_VALUE)
00530             RevertToSelf (); // probably not needed
00531           else if (!ImpersonateLoggedOnUser (myself->token))
00532             system_printf ("Impersonate for forked child failed: %E");
00533         }
00534 
00535       sync_with_parent ("after longjmp.", TRUE);
00536       ProtectHandle (hParent);
00537 
00538 #ifdef DEBUGGING
00539       char c;
00540       if (GetEnvironmentVariable ("FORKDEBUG", &c, 1))
00541         try_to_debug ();
00542       char buf[80];
00543       /* This is useful for debugging fork problems.  Use gdb to attach to
00544          the pid reported here. */
00545       if (GetEnvironmentVariable ("CYGWIN_FORK_SLEEP", buf, sizeof (buf)))
00546         {
00547           small_printf ("Sleeping %d after fork, pid %u\n", atoi (buf), GetCurrentProcessId ());
00548           Sleep (atoi(buf));
00549         }
00550 #endif
00551 
00552       /* If we've played with the stack, stacksize != 0.  That means that
00553          fork() was invoked from other than the main thread.  Make sure that
00554          when the "main" thread exits it calls do_exit, like a normal process.
00555          Exit with a status code of 0. */
00556       if (child_proc_info->stacksize)
00557         {
00558           ((DWORD *)child_proc_info->stackbottom)[-17] = (DWORD)do_exit;
00559           ((DWORD *)child_proc_info->stackbottom)[-15] = (DWORD)0;
00560         }
00561 
00562       MALLOC_CHECK;
00563 
00564       dtable.fixup_after_fork (hParent);
00565       signal_fixup_after_fork ();
00566 
00567       MALLOC_CHECK;
00568 
00569       /* If we haven't dynamically loaded any dlls, just signal
00570          the parent.  Otherwise, load all the dlls, tell the parent
00571           that we're done, and wait for the parent to fill in the.
00572           loaded dlls' data/bss. */
00573       if (!load_dlls)
00574         sync_with_parent ("performed fork fixup.", FALSE);
00575       else
00576         {
00577           dlls.load_after_fork (hParent, first_dll);
00578           sync_with_parent ("loaded dlls", TRUE);
00579         }
00580 
00581       ForceCloseHandle (hParent);
00582       (void) ForceCloseHandle (child_proc_info->subproc_ready);
00583       (void) ForceCloseHandle (child_proc_info->forker_finished);
00584 
00585       if (recreate_mmaps_after_fork (myself->mmap_ptr))
00586         api_fatal ("recreate_mmaps_after_fork_failed");
00587 
00588       res = 0;
00589       /* Set thread local stuff to zero.  Under Windows 95/98 this is sometimes
00590          non-zero, for some reason.
00591          FIXME:  There is a memory leak here after a fork. */
00592       for (per_thread **t = threadstuff; *t; t++)
00593         if ((*t)->clear_on_fork ())
00594           (*t)->set ();
00595 
00596       /* Initialize signal/process handling */
00597       sigproc_init ();
00598     }
00599 
00600 
00601   MALLOC_CHECK;
00602   syscall_printf ("%d = fork()", res);
00603   return res;
00604 
00605 /* Common cleanup code for failure cases */
00606 cleanup:
00607   /* Remember to de-allocate the fd table. */
00608   child->process_state = PID_NOT_IN_USE;
00609   if (pi.hProcess)
00610     ForceCloseHandle1 (pi.hProcess, childhProc);
00611   if (pi.hThread)
00612     ForceCloseHandle (pi.hThread);
00613   if (subproc_ready)
00614     ForceCloseHandle (subproc_ready);
00615   if (forker_finished)
00616     ForceCloseHandle (forker_finished);
00617   forker_finished = subproc_ready = child->hProcess = NULL;
00618   return -1;
00619 }
00620 
00621 static volatile void
00622 grow_stack_slack ()
00623 {
00624   volatile char dummy[16384];
00625   dummy[0] = dummy[16383] = 0;  // Just to make some slack in the stack
00626 }
00627 
00628 #ifdef NEWVFORK
00629 /* Dummy function to force second assignment below to actually be
00630    carried out */
00631 static vfork_save *
00632 get_vfork_val ()
00633 {
00634   return vfork_storage.val ();
00635 }
00636 #endif
00637 
00638 extern "C"
00639 int
00640 vfork ()
00641 {
00642 #ifndef NEWVFORK
00643   return fork ();
00644 #else
00645   vfork_save *vf = get_vfork_val ();
00646 
00647   if (vf == NULL)
00648     vf = vfork_storage.create ();
00649 
00650   if (!setjmp (vf->j))
00651     {
00652       vf->pid = -1;
00653       __asm__ volatile ("movl %%ebp,%0": "=r" (vf->vfork_ebp):);
00654       __asm__ volatile ("movl (%%ebp),%0": "=r" (vf->caller_ebp):);
00655       __asm__ volatile ("movl 4(%%ebp),%0": "=r" (vf->retaddr):);
00656       return dtable.vfork_child_dup () ? 0 : -1;
00657     }
00658 
00659   dtable.vfork_parent_restore ();
00660 
00661   vf = get_vfork_val ();
00662   if (vf->pid < 0)
00663     {
00664       int exitval = -vf->pid;
00665       if ((vf->pid = fork ()) == 0)
00666         exit (exitval);
00667     }
00668 
00669   vf->vfork_ebp[0] = vf->caller_ebp;
00670   vf->vfork_ebp[1] = vf->retaddr;
00671   return vf->pid;
00672 #endif
00673 }

Generated on Sun Mar 12 23:56:31 2006 for ScriptBasic by  doxygen 1.4.6-NO