⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 fork.cc

📁 cygwin, 著名的在win32下模拟unix操作系统的东东
💻 CC
📖 第 1 页 / 共 2 页
字号:
/* fork.cc   Copyright 1996, 1997, 1998, 1999, 2000, 2001, 2002 Red Hat, Inc.This file is part of Cygwin.This software is a copyrighted work licensed under the terms of theCygwin license.  Please consult the file "CYGWIN_LICENSE" fordetails. */#include "winsup.h"#include <stdio.h>#include <unistd.h>#include <stdlib.h>#include <stdarg.h>#include <errno.h>#include "security.h"#include "fhandler.h"#include "path.h"#include "dtable.h"#include "cygerrno.h"#include "sigproc.h"#include "pinfo.h"#include "cygheap.h"#include "child_info.h"#define NEED_VFORK#include "perthread.h"#include "perprocess.h"#include "dll_init.h"#include "sync.h"#include "shared_info.h"#include "cygmalloc.h"#include "cygthread.h"#ifdef DEBUGGINGstatic int npid;static int npid_max;static pid_t fork_pids[100];#endif/* Timeout to wait for child to start, parent to init child, etc.  *//* FIXME: Once things stabilize, bump up to a few minutes.  */#define FORK_WAIT_TIMEOUT (300 * 1000)     /* 300 seconds */#define dll_data_start &_data_start__#define dll_data_end &_data_end__#define dll_bss_start &_bss_start__#define dll_bss_end &_bss_end__voidper_thread::set (void *s){  if (s == PER_THREAD_FORK_CLEAR)    {      tls = TlsAlloc ();      s = NULL;    }  TlsSetValue (get_tls (), s);}static voidstack_base (child_info_fork &ch){  MEMORY_BASIC_INFORMATION m;  memset (&m, 0, sizeof m);  if (!VirtualQuery ((LPCVOID) &m, &m, sizeof m))    system_printf ("couldn't get memory info, %E");  ch.stacktop = m.AllocationBase;  ch.stackbottom = (LPBYTE) m.BaseAddress + m.RegionSize;  ch.stacksize = (DWORD) ch.stackbottom - (DWORD) &m;  debug_printf ("bottom %p, top %p, stack %p, size %d, reserve %d",		ch.stackbottom, ch.stacktop, &m, ch.stacksize,		(DWORD) ch.stackbottom - (DWORD) ch.stacktop);}/* Copy memory from parent to child.   The result is a boolean indicating success.  */static intfork_copy (PROCESS_INFORMATION &pi, const char *what, ...){  va_list args;  char *low;  int pass = 0;  va_start (args, what);  while ((low = va_arg (args, char *)))    {      char *high = va_arg (args, char *);      DWORD todo = wincap.chunksize () ?: high - low;      char *here;      for (here = low; here < high; here += todo)	{	  DWORD done = 0;	  if (here + todo > high)	    todo = high - here;	  int res = WriteProcessMemory (pi.hProcess, here, here, todo, &done);	  debug_printf ("child handle %p, low %p, high %p, res %d", pi.hProcess,			low, high, res);	  if (!res || todo != done)	    {	      if (!res)		__seterrno ();	      /* If this happens then there is a bug in our fork		 implementation somewhere. */	      system_printf ("%s pass %d failed, %p..%p, done %d, windows pid %u, %E",			    what, pass, low, high, done, pi.dwProcessId);	      goto err;	    }	}      pass++;    }  debug_printf ("done");  return 1; err:  TerminateProcess (pi.hProcess, 1);  set_errno (EAGAIN);  return 0;}/* Wait for child to finish what it's doing and signal us.   We don't want to wait forever here.If there's a problem somewhere   it'll hang the entire system (since all forks are mutex'd). If we   time out, set errno = EAGAIN and hope the app tries again.  */static intsync_with_child (PROCESS_INFORMATION &pi, HANDLE subproc_ready,		 BOOL hang_child, const char *s){  /* We also add the child process handle to the wait. If the child fails     to initialize (eg. because of a missing dll). Then this     handle will become signalled. This stops a *looong* timeout wait.  */  HANDLE w4[2];  debug_printf ("waiting for child.  reason: %s, hang_child %d", s,		hang_child);  w4[1] = pi.hProcess;  w4[0] = subproc_ready;  DWORD rc = WaitForMultipleObjects (2, w4, FALSE, FORK_WAIT_TIMEOUT);  if (rc == WAIT_OBJECT_0 ||      WaitForSingleObject (subproc_ready, 0) == WAIT_OBJECT_0)    /* That's ok */;  else if (rc == WAIT_FAILED || rc == WAIT_TIMEOUT)    {      if (rc != WAIT_FAILED)	system_printf ("WaitForMultipleObjects timed out");      else	system_printf ("WaitForMultipleObjects failed, %E");      set_errno (EAGAIN);      syscall_printf ("-1 = fork(), WaitForMultipleObjects failed");      TerminateProcess (pi.hProcess, 1);      return 0;    }  else    {      /* Child died. Clean up and exit. */      DWORD errcode;      GetExitCodeProcess (pi.hProcess, &errcode);      /* Fix me.  This is not enough.  The fork should not be considered       * to have failed if the process was essentially killed by a signal.       */      if (errcode != STATUS_CONTROL_C_EXIT)	{	    system_printf ("child %d(%p) died before initialization with status code %p",			  pi.dwProcessId, pi.hProcess, errcode);	    system_printf ("*** child state %s", s);#ifdef DEBUGGING	    abort ();#endif	}      set_errno (EAGAIN);      syscall_printf ("Child died before subproc_ready signalled");      return 0;    }  debug_printf ("child signalled me");  return 1;}static intresume_child (PROCESS_INFORMATION &pi, HANDLE forker_finished){  SetEvent (forker_finished);  debug_printf ("signalled child");  return 1;}/* 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   our stack. */static void __stdcallsync_with_parent (const char *s, bool hang_self){  debug_printf ("signalling parent: %s", s);  /* Tell our parent we're waiting. */  if (!SetEvent (fork_info->subproc_ready))    api_fatal ("fork child - SetEvent for %s failed, %E", s);  if (hang_self)    {      HANDLE h = fork_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 for %s", s);	  break;	case WAIT_FAILED:	  if (GetLastError () == ERROR_INVALID_HANDLE &&	      WaitForSingleObject (fork_info->forker_finished, 1) != WAIT_FAILED)	    break;	  api_fatal ("WFSO failed for %s, fork_finished %p, %E", s,		     fork_info->forker_finished);	  break;	default:	  debug_printf ("no problems");	  break;	}    }}static int __stdcallfork_child (HANDLE& hParent, dll *&first_dll, bool& load_dlls){  debug_printf ("child is running.  pid %d, ppid %d, stack here %p",		myself->pid, myself->ppid, __builtin_frame_address (0));  /* Restore the inheritance state as in parent     Don't call setuid here! The flags are already set. */  if (cygheap->user.impersonated)    {      debug_printf ("Impersonation of child, token: %d", cygheap->user.token);      if (cygheap->user.token == INVALID_HANDLE_VALUE)	RevertToSelf (); // probably not needed      else if (!ImpersonateLoggedOnUser (cygheap->user.token))	system_printf ("Impersonate for forked child failed: %E");    }  sync_with_parent ("after longjmp.", TRUE);  sigproc_printf ("hParent %p, child 1 first_dll %p, load_dlls %d", hParent,		  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 (fork_info->stacksize)    {      ((DWORD *)fork_info->stackbottom)[-17] = (DWORD)do_exit;      ((DWORD *)fork_info->stackbottom)[-15] = (DWORD)0;    }  set_file_api_mode (current_codepage);  MALLOC_CHECK;  if (fixup_mmaps_after_fork (hParent))    api_fatal ("recreate_mmaps_after_fork_failed");  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)    {      cygheap->fdtab.fixup_after_fork (hParent);      ProtectHandleINH (hParent);      sync_with_parent ("performed fork fixup.", FALSE);    }  else    {      dlls.load_after_fork (hParent, first_dll);      cygheap->fdtab.fixup_after_fork (hParent);      ProtectHandleINH (hParent);      sync_with_parent ("loaded dlls", TRUE);    }  ForceCloseHandle (hParent);  (void) ForceCloseHandle1 (fork_info->subproc_ready, subproc_ready);  (void) ForceCloseHandle1 (fork_info->forker_finished, forker_finished);  if (fixup_shms_after_fork ())    api_fatal ("recreate_shm areas after fork failed");  pinfo_fixup_after_fork ();  signal_fixup_after_fork ();  /* 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 ();  pthread::atforkchild ();  wait_for_sigthread ();  cygbench ("fork-child");  return 0;}static voidslow_pid_reuse (HANDLE h){  static NO_COPY HANDLE last_fork_procs[8] = {0};  static NO_COPY unsigned nfork_procs = 0;  if (nfork_procs >= (sizeof (last_fork_procs) / sizeof (last_fork_procs [0])))    nfork_procs = 0;  /* Keep a list of handles to forked processes sitting around to prevent     Windows from reusing the same pid n times in a row.  Having the same pids     close in succesion confuses bash.  Keeping a handle open will stop     windows from reusing the same pid.  */  if (last_fork_procs[nfork_procs])    ForceCloseHandle1 (last_fork_procs[nfork_procs], fork_stupidity);  if (DuplicateHandle (hMainProc, h, hMainProc, &last_fork_procs[nfork_procs],			0, FALSE, DUPLICATE_SAME_ACCESS))    ProtectHandle1 (last_fork_procs[nfork_procs], fork_stupidity);  else    {      last_fork_procs[nfork_procs] = NULL;      system_printf ("couldn't create last_fork_proc, %E");    }  nfork_procs++;}static int __stdcallfork_parent (HANDLE& hParent, dll *&first_dll,	     bool& load_dlls, void *stack_here, child_info_fork &ch){  HANDLE subproc_ready, forker_finished;  DWORD rc;  PROCESS_INFORMATION pi = {0, NULL, 0, 0};  pthread::atforkprepare ();  subproc_init ();  int c_flags = GetPriorityClass (hMainProc) /*|		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     child either.  */  HANDLE console_handle = CreateFile ("CONOUT$", GENERIC_WRITE,				      FILE_SHARE_WRITE, &sec_none_nih,				      OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL,				      NULL);  if (console_handle != INVALID_HANDLE_VALUE)

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -