Subject: RE: Bug with Fix: mmap(MAP_PRIVATE) region handling in fork()
From: [email-masked] (Gary Fuehrer)

30 Aug 1997 23:06:18 -0700
Approved: [email-masked]
Distribution: cygnus
Message-ID: <6CC63E2E4FC1D011A2A700609716117A266F16.cygnus.gnu-win32@seawolf>
Mime-Version: 1.0
Content-Type: multipart/mixed;
	boundary="---- =_NextPart_000_01BCB240.03307650"
Original-To: "[email-masked]'" <[email-masked]>
X-Priority: 3
X-Mailer: Internet Mail Service (5.0.1458.49)
Original-Sender: [email-masked]

This message is in MIME format. Since your mail reader does not understand
this format, some or all of this message may not be legible.

------ =_NextPart_000_01BCB240.03307650
Content-Type: text/plain

> Download cdk-src.tar.gz from /pub/gnu-win32/gnu-win32-b18/ at
> ftp.cygnus.com.  After expanding it out, you will have a "cdk"
> subdirectory.  The "winsup" directory is in there.
> 
> Attached are my copies of the files (except for "winsup.h" which was
> trivial).  My e-mail about the changes came out crappy because of all
> the gratuitous line wrapping.  So, maybe it would be easier to diff my
> version with the original.
> 
>   
>   
> 
> Gary
> 
> 
> ----------
> From: 	Martin Schrape[SMTP:[email-masked]]
> Sent: 	Tuesday, August 26, 1997 1:56 PM
> To: 	Gary Fuehrer
> Subject: 	RE: Bug with Fix: mmap(MAP_PRIVATE) region handling in
> fork()
> 
> 
> 
> -----Original Message-----
> From:	Gary Fuehrer [SMTP:[email-masked]]
> Sent:	Friday, August 22, 1997 10:42 PM
> To:	[email-masked]'
> Subject:	Bug with Fix: mmap(MAP_PRIVATE) region handling in
> fork()
> 
> 
> The following changes to three files (winsup.h, fork.cc, mmap.cc) will
> fix this bug.
> 
> ================
> winsup.h
> ================
> 
> [schrape]  Gary,
> sorry but where did you get the winsup files from. I can't find them
> on the cygnus ftp server.
> --martin
> 

------ =_NextPart_000_01BCB240.03307650
Content-Type: application/octet-stream;
	name="fork.cc"
Content-Transfer-Encoding: quoted-printable
Content-Disposition: attachment;
	filename="fork.cc"

/* fork.cc: fork for WIN32.=0A=
=0A=
   Copyright 1996, 1997 Cygnus Solutions=0A=
=0A=
This program is free software; you can redistribute it and/or modify=0A=
it under the terms of the GNU General Public License as published by=0A=
the Free Software Foundation; either version 2 of the License, or=0A=
(at your option) any later version.=0A=
=0A=
This program is distributed in the hope that it will be useful,=0A=
but WITHOUT ANY WARRANTY; without even the implied warranty of=0A=
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the=0A=
GNU General Public License for more details.=0A=
=0A=
You should have received a copy of the GNU General Public License=0A=
along with this program; if not, write to the Free Software=0A=
Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, =
USA.  */=0A=
=0A=
#include <stdio.h>=0A=
#include <unistd.h>=0A=
#include "winsup.h"=0A=
=0A=
extern "C" struct _reent reent_data;=0A=
=0A=
/* Timeout to wait for child to start, parent to init child, etc.  =
*/=0A=
/* FIXME: Once things stabilize, bump up to a few minutes.  */=0A=
#define FORK_WAIT_TIMEOUT (120 * 1000 /* 120 seconds */)=0A=
=0A=
/* Error return code from WaitForSingleObject.  */=0A=
#define WAIT_ERROR_RC 0xffffffff=0A=
=0A=
/* Mutexes and events necessary for child startup.  */=0A=
static HANDLE forkee_stopped, forker_stopped;=0A=
=0A=
/* Initialize the fork mechanism.  */=0A=
=0A=
void=0A=
fork_init ()=0A=
{=0A=
  SECURITY_ATTRIBUTES sa;=0A=
  sa.nLength =3D sizeof (sa);=0A=
  sa.lpSecurityDescriptor =3D get_null_sd();=0A=
  sa.bInheritHandle =3D 0;=0A=
=0A=
  forker_stopped =3D CreateEventA (&sa, TRUE, TRUE, =
"cygwin.forker-stopped");=0A=
  forkee_stopped =3D CreateEventA (&sa, TRUE, TRUE, =
"cygwin.forkee-stopped");=0A=
=0A=
  /* If we didn't obtain all the resources we need to fork, allow the =
program=0A=
     to continue, but record the fact that fork won't work.  */=0A=
  if (forker_stopped =3D=3D NULL=0A=
      || forkee_stopped =3D=3D NULL)=0A=
    {=0A=
      system_printf ("fork_init: unable to allocate fork() =
resources.\n");=0A=
      system_printf ("fork_init: fork() disabled.\n");=0A=
    }=0A=
}=0A=
=0A=
/* Undo what fork_init does.=0A=
=0A=
   If a task is shutting down, this isn't really necessary, but maybe =
one day=0A=
   we'll want to allow cygwin.dll to be attached to and detached from, =
so we=0A=
   should provide a clean interface to release all resources we obtain. =
 */=0A=
=0A=
void=0A=
fork_terminate ()=0A=
{=0A=
  CloseHandle (forker_stopped);=0A=
  CloseHandle (forkee_stopped);=0A=
}=0A=
=0A=
#if 0=0A=
void=0A=
print_checksum (int idx, register void *low, register void *high)=0A=
{=0A=
  int pi;=0A=
  register  int sum =3D 0;=0A=
  small_printf ("CK %d %x %x ", idx, low, high);=0A=
=0A=
  for (int *pi =3D (int *)low; pi < (int *)high; pi++)=0A=
    {=0A=
      sum +=3D *pi;=0A=
    }=0A=
  small_printf ("%x\n", sum);=0A=
}=0A=
#endif=0A=
=0A=
/* Copy memory from parent to child.=0A=
   The result is a boolean indicating success.  */=0A=
=0A=
int=0A=
copy_memory_to_forkee (HANDLE child, void *low, void *high, int)=0A=
{=0A=
  DWORD done;=0A=
  int res;=0A=
=0A=
  debug_printf ("fork copy: child handle %d, low %p, high %p\n",=0A=
		child, low, high);=0A=
=0A=
  int lump =3D 1024*64;=0A=
  for (char *p =3D (char *) low; p < (char *) high; p +=3D lump)=0A=
    {=0A=
      int todo =3D MIN ((char *)high - p, lump);=0A=
=0A=
      res =3D WriteProcessMemory (child, p, p, todo, &done);=0A=
      if (!res || todo !=3D done)=0A=
	{=0A=
	  if (!res)=0A=
	    __seterrno ();=0A=
	  /* This happens when it shouldn't so there's a bug in our fork=0A=
	     implementation somewhere.  Print a message on the console to=0A=
	     call people's attention to the failure until we get it=0A=
	     straightened out.  */=0A=
	  small_printf ("fork copy: failed, %p..%p, res is %d, done is =
%d\n",=0A=
			low, high, res, done);=0A=
	  /* Call debug_printf as well to make sure message gets in log=0A=
	     file if there is one.  */=0A=
	  debug_printf ("fork copy: failed\n");=0A=
	  return 0;=0A=
	}=0A=
    }=0A=
=0A=
#if 0=0A=
  print_checksum (idx, low, high);=0A=
#endif=0A=
  debug_printf ("fork copy: done\n");=0A=
  return 1;=0A=
}=0A=
=0A=
int copy_mmap_records_to_forkee(pinfo *child);=0A=
int recreate_mmaps_after_fork(void *);=0A=
int copy_copyonwrite_mmaps_to_forkee(HANDLE hChild);=0A=
=0A=
/* Main guts of fork implementation.=0A=
   The result is the standard result of fork.  */=0A=
=0A=
static int=0A=
cygwin_fork_helper1 (void *proc_data_start,=0A=
		     void *proc_data_end,=0A=
		     void *proc_bss_start,=0A=
		     void *proc_bss_end)=0A=
{=0A=
  int res;=0A=
  int x, rc;=0A=
  hinfo *child_hinfo =3D 0;=0A=
=0A=
  if (u->self->split_heap_p)=0A=
    {=0A=
      small_printf ("The heap has been split, CYGWIN can't fork this =
process.\n");=0A=
      small_printf ("Increase the heap_chunk_size in the registry and =
try again.\n");=0A=
      set_errno (ENOMEM);=0A=
      syscall_printf ("-1 =3D fork (), split heap\n");=0A=
      return -1;=0A=
    }=0A=
=0A=
  /* Don't start the fork until we have the lock.  */=0A=
  rc =3D lock_pinfo_for_update(FORK_WAIT_TIMEOUT);=0A=
  switch (rc)=0A=
    {=0A=
    case WAIT_ERROR_RC:=0A=
      small_printf ("fork parent: WaitForSingleObject (mutex) failed, =
win32 error %d\n",=0A=
		    GetLastError ());=0A=
      set_errno (EAGAIN);=0A=
      syscall_printf ("-1 =3D fork (), wait failed\n");=0A=
      return -1;=0A=
    case WAIT_TIMEOUT:=0A=
      small_printf ("fork parent: WaitForSingleObject (mutex) timed =
out\n");=0A=
      set_errno (EAGAIN);=0A=
      syscall_printf ("-1 =3D fork (), wait timed out\n");=0A=
      return -1;=0A=
    default:=0A=
      debug_printf ("fork_helper: %d =3D WaitForSingleObject (...)\n", =
rc);=0A=
      break;=0A=
    }=0A=
=0A=
  pinfo *child =3D s->p.allocate_pid ();=0A=
=0A=
  if (!child)=0A=
    {=0A=
      set_errno (EAGAIN);=0A=
      syscall_printf ("-1 =3D fork (), process table full\n");=0A=
      unlock_pinfo();=0A=
      return -1;=0A=
    }=0A=
=0A=
  /*=0A=
   * We need to save this allocated pointer as the child=0A=
   * will be changing it, plus we need to delete [] it later.=0A=
   */=0A=
  child_hinfo =3D child->hmap.vec;=0A=
=0A=
  /* This will help some of the confusion.  */=0A=
  fflush (stdout);=0A=
=0A=
  debug_printf ("fork_helper: parent pid is %d, child pid is %d\n",=0A=
		u->self->get_pid (),=0A=
		child->get_pid ());=0A=
=0A=
  /* Initialize things that are done later in dll_crt0_1 that aren't =
done=0A=
     for the forkee.  */=0A=
  child->reent_save =3D  reent_data;=0A=
  child->progname =3D u->self->progname;=0A=
=0A=
  /* Copy all the handles we need in the child.  */=0A=
  u->self->hmap.dup_for_fork (&child->hmap);=0A=
=0A=
  PROCESS_INFORMATION pi =3D {0};=0A=
=0A=
  STARTUPINFO si =3D {0};=0A=
  si.cb =3D sizeof (STARTUPINFO);=0A=
=0A=
  int c_flags =3D GetPriorityClass (GetCurrentProcess ()) | =
CREATE_SUSPENDED; =0A=
=0A=
  syscall_printf ("CreateProcessA (%s, %s,0,0,1,%x, 0,0,%p,%p)\n",=0A=
		  u->self->progname, u->self->progname, c_flags, &si, &pi);=0A=
=0A=
  rc =3D CreateProcessA (u->self->progname, /* image to run */=0A=
		       u->self->progname, /* what we send in arg0 */=0A=
		       0,		  /* process security attrs */=0A=
		       0,		  /* thread security attrs */=0A=
		       TRUE,		  /* inherit handles from parent */=0A=
		       c_flags,=0A=
		       0,	/* use parent's environment */=0A=
		       0,	/* use current drive/directory */=0A=
		       &si,=0A=
		       &pi);=0A=
=0A=
  if (!rc)=0A=
    {=0A=
      __seterrno ();=0A=
      syscall_printf ("-1 =3D fork(), CreateProcessA failed\n");=0A=
      child->inuse_p =3D PID_NOT_IN_USE;=0A=
      delete [] child_hinfo;=0A=
      unlock_pinfo();=0A=
      return -1;=0A=
    }=0A=
=0A=
  ResetEvent (forker_stopped);=0A=
  ResetEvent (forkee_stopped);=0A=
  =0A=
  debug_printf ("fork_helper: about to call setjmp\n");=0A=
  x =3D setjmp (u->self->restore);=0A=
  debug_printf ("fork_helper: setjmp returned %d\n", x);=0A=
=0A=
#if 0=0A=
  if (0)=0A=
    {=0A=
      int k;=0A=
      unsigned char *p =3D (unsigned char *)(u->restore[32/4]);=0A=
      for (k =3D 0; k < 11; k++)=0A=
	small_printf ("set reg %d %x\n", k *4 , u->restore[k]);=0A=
      for (k =3D 0; k < 11; k++)=0A=
	small_printf ("[%02x]", p[k]);=0A=
      small_printf ("the res was %d\n", x);=0A=
    }=0A=
#endif=0A=
  =0A=
  if (x =3D=3D 0)=0A=
    {=0A=
      /* Parent.  */=0A=
=0A=
      dump_jmp_buf (u->self->restore);=0A=
=0A=
#if 0 /* for debugging */=0A=
      s->base[0][0] =3D proc_data_start;=0A=
      s->base[0][1] =3D proc_data_end;=0A=
      s->base[1][0] =3D proc_bss_start;=0A=
      s->base[1][1] =3D proc_bss_end;=0A=
      s->base[2][0] =3D u->base;=0A=
      s->base[2][1] =3D u->ptr;=0A=
      s->base[3][0] =3D &x;=0A=
      s->base[3][1] =3D u->initial_sp; =0A=
#endif =0A=
=0A=
      /* Tell the child it's being forked and its pid.=0A=
	 Remember, *u gets copied to the child's address space.  */=0A=
      u->forkee =3D child->get_pid ();=0A=
=0A=
      /* Fill in fields in the child's process table entry.  */=0A=
      child->ppid =3D u->self->get_pid ();=0A=
      child->hThread =3D pi.hThread;      =0A=
      child->hProcess =3D pi.hProcess;=0A=
      child->dwProcessId =3D pi.dwProcessId;=0A=
      child->uid =3D u->self->uid;=0A=
      child->gid =3D u->self->gid;=0A=
      child->sigs =3D u->self->sigs;=0A=
      child->sig_mask =3D u->self->sig_mask;=0A=
      if (copy_mmap_records_to_forkee(child))=0A=
	{=0A=
	  small_printf ("fork_helper: copy of mmap_records failed\n");=0A=
	  set_errno (EAGAIN);=0A=
	  syscall_printf ("-1 =3D fork(), copy of mmap_records failed\n");=0A=
	  TerminateProcess (child->hProcess, 1);=0A=
	  u->forkee =3D 0;=0A=
          goto cleanup;=0A=
	}=0A=
=0A=
      /* Initialize the child's .data and .bss.  */=0A=
      rc =3D copy_memory_to_forkee (pi.hProcess, (char =
*)proc_data_start, (char *)proc_data_end, 0);=0A=
      if (rc)=0A=
	rc =3D copy_memory_to_forkee (pi.hProcess, (char *)proc_bss_start, =
(char *)proc_bss_end, 1);=0A=
      if (! rc)=0A=
	{=0A=
	  small_printf ("fork_helper: copy of data/bss failed\n");=0A=
	  set_errno (EAGAIN);=0A=
	  syscall_printf ("-1 =3D fork(), data/bss copy failed\n");=0A=
	  TerminateProcess (child->hProcess, 1);=0A=
	  u->forkee =3D 0;=0A=
          goto cleanup;=0A=
	}=0A=
=0A=
      u->forkee =3D 0;=0A=
=0A=
      /* Need to record that task was started by cygwin32 task.=0A=
	 This info will then used by the exit() handling code to know =
whether=0A=
	 to reset inuse_p.  Normally inuse_p isn't reset until wait() is =
called=0A=
	 but if the task wasn't started by a cygwin32 task, wait() will =
never=0A=
	 be called and the process table will fill up.  We remove this=0A=
         flag if the parent exits. */=0A=
=0A=
      child->inuse_p |=3D PID_TO_BE_WAITED_FOR;=0A=
=0A=
      /* FIXME: Exit handling code also needs to record that the task =
ended=0A=
	 so the ps command will know about zombies.  */=0A=
=0A=
      /* Start thread, and wait for it to initialize itself.  */=0A=
      rc =3D ResumeThread (child->hThread);=0A=
      if (rc !=3D 1)=0A=
	{=0A=
	  /* Can't resume the thread.  Not sure why this would happen =
unless=0A=
	     there's a bug in the system.  Things seem to be working OK now=0A=
	     though, so flag this with EAGAIN, but print a message on the=0A=
	     console.  */=0A=
	  small_printf ("fork_helper: ResumeThread failed, rc =3D %d\n", =
rc);=0A=
	  set_errno (EAGAIN);=0A=
	  syscall_printf ("-1 =3D fork(), ResumeThread failed\n");=0A=
	  TerminateProcess (child->hProcess, 1);=0A=
          goto cleanup;=0A=
	}=0A=
      debug_printf ("fork_helper: child started\n");=0A=
=0A=
      /* We don't want to wait forever here.  If there's a problem =
somewhere=0A=
	 it'll hang the entire system (since all forks are mutex'd).  If we=0A=
	 time out, set errno =3D EAGAIN and hope the app tries again.  */=0A=
=0A=
      /* We also add child->hProcess to the wait. If the child fails=0A=
         to initialize (eg. because of a missing dll). Then this=0A=
         handle will become signalled. This stops a *looong* timeout =
wait.=0A=
      */=0A=
      HANDLE wait_array[2];=0A=
      wait_array[0] =3D child->hProcess;=0A=
      wait_array[1] =3D forkee_stopped;=0A=
      rc =3D WaitForMultipleObjects (2, wait_array, FALSE, =
FORK_WAIT_TIMEOUT);=0A=
      if (rc =3D=3D WAIT_ERROR_RC || rc =3D=3D WAIT_TIMEOUT)=0A=
	{=0A=
	  if (rc =3D=3D WAIT_ERROR_RC)=0A=
	    small_printf ("fork_helper: WaitForMultipleObjects failed, win32 =
error %d\n",=0A=
			  GetLastError ());=0A=
	  else=0A=
	    small_printf ("fork_helper: WaitForMultipleObjects timed =
out\n");=0A=
	  set_errno (EAGAIN);=0A=
	  syscall_printf ("-1 =3D fork(), WaitForMultipleObjects =
failed\n");=0A=
	  TerminateProcess (child->hProcess, 1);=0A=
          goto cleanup;=0A=
	}=0A=
      else if(rc =3D=3D WAIT_OBJECT_0)=0A=
        {=0A=
          /* Child died. Clean up and exit. */=0A=
          DWORD errcode;=0A=
          GetExitCodeProcess(child->hProcess, &errcode);=0A=
	  small_printf ("fork_helper: child died before initialization with =
win32 error %d\n", errcode);=0A=
	  set_errno (EAGAIN);=0A=
          syscall_printf ("fork_helper: Child died before =
forkee_stopped signalled\n");=0A=
          goto cleanup;=0A=
	}=0A=
      SuspendThread (child->hThread);=0A=
=0A=
      /* Now fill in the stack and heap - this has to be done after =0A=
	 the child is started.  */=0A=
      rc =3D copy_memory_to_forkee (child->hProcess, u->base, u->ptr, =
2);=0A=
      if (rc)=0A=
	rc =3D copy_memory_to_forkee (child->hProcess, &x, u->initial_sp, =
3);=0A=
      if (! rc)=0A=
	{=0A=
	  small_printf ("fork_helper: copy of stack/heap failed\n");=0A=
	  set_errno (EAGAIN);=0A=
	  syscall_printf ("-1 =3D fork(), stack/heap copy failed\n");=0A=
	  TerminateProcess (child->hProcess, 1);=0A=
          goto cleanup;=0A=
	}=0A=
=0A=
      if(copy_copyonwrite_mmaps_to_forkee(child->hProcess))=0A=
        {=0A=
          small_printf("fork_helper: copy_copyonwrite_mmaps_to_forkee =
failed\n");=0A=
	      set_errno (EAGAIN);=0A=
	      syscall_printf ("-1 =3D fork(), copy of copyonwrite memory =
failed\n");=0A=
	      TerminateProcess (child->hProcess, 1);=0A=
              goto cleanup;=0A=
        }=0A=
=0A=
      /*=0A=
       * Now we have started the child we can get rid of the=0A=
       * childs fd table from our address space.=0A=
       */=0A=
      delete [] child_hinfo;=0A=
      /* Start the child up again.  */=0A=
      SetEvent (forker_stopped);=0A=
      ResumeThread (child->hThread);=0A=
=0A=
      res =3D child->get_pid ();=0A=
=0A=
      unlock_pinfo();=0A=
    }=0A=
  else=0A=
    {=0A=
      /* We arrive here via a longjmp from "crt0".  */=0A=
      debug_printf ("fork_helper: child is running\n");=0A=
=0A=
      u->self =3D s->p[x];=0A=
      reent_data =3D u->self->reent_save;=0A=
      debug_printf ("fork child: self %p, pid %d, ppid %d\n",=0A=
		    u->self, x, u->self->ppid);=0A=
=0A=
      if(recreate_mmaps_after_fork(u->self->mmap_ptr))=0A=
        {=0A=
          small_printf("fork child: =
recreate_mmaps_after_fork_failed\n");=0A=
          ExitProcess (1);=0A=
        }=0A=
=0A=
      /* Tell our parent we've started.  */=0A=
      SetEvent (forkee_stopped);=0A=
=0A=
      /* Wait for the parent to fill in our stack and heap.=0A=
	 Don't wait forever here.  If our parent dies we don't want to clog=0A=
	 the system.  If the wait fails, we really can't continue so exit.  =
*/=0A=
      int rc =3D WaitForSingleObject (forker_stopped, =
FORK_WAIT_TIMEOUT);=0A=
      switch (rc)=0A=
	{=0A=
	case WAIT_ERROR_RC:=0A=
	  small_printf ("fork child: WaitForSingleObject failed, win32 error =
%d\n",=0A=
			GetLastError ());=0A=
	  ExitProcess (1);=0A=
	case WAIT_TIMEOUT:=0A=
	  small_printf ("fork child: WaitForSingleObject timed out\n");=0A=
	  ExitProcess (1);=0A=
	default:=0A=
	  break;=0A=
	}=0A=
=0A=
      /* Ensure winsock is enabled for the child. */=0A=
      socket_checkinit();=0A=
#if 0=0A=
      print_checksum (4,   s->base[0][0], s->base[0][1]);=0A=
      print_checksum (5,   s->base[1][0], s->base[1][1]);=0A=
      print_checksum (6,   s->base[2][0], s->base[2][1]);=0A=
      print_checksum (7,   s->base[3][0], s->base[3][1]);=0A=
#endif=0A=
=0A=
      res =3D 0;=0A=
    }=0A=
=0A=
  syscall_printf ("%d =3D fork()\n", res);=0A=
  return res;=0A=
=0A=
/* Common cleanup code for failure cases */=0A=
cleanup:=0A=
  /* Remember to de-allocate the fd table. */=0A=
  delete [] child_hinfo;=0A=
  child->inuse_p =3D PID_NOT_IN_USE;=0A=
  unlock_pinfo();=0A=
  CloseHandle(child->hProcess);=0A=
  CloseHandle(child->hThread);=0A=
  return -1;=0A=
}=0A=
=0A=
/* This hack uses setjmp/longjmp to ensure that the parent's=0A=
   registers are all available in the child. We could use=0A=
   GetThreadContext/SetThreadContext instead, but I'm sure this=0A=
   is much faster. */=0A=
=0A=
static int=0A=
__fork ()=0A=
{=0A=
  jmp_buf b;=0A=
  int r;=0A=
=0A=
  if ((r =3D setjmp (b)) !=3D 0)=0A=
    {=0A=
      r =3D r =3D=3D -2 ? -1 : r =3D=3D -1 ? 0 : r;=0A=
      return r;=0A=
    }=0A=
=0A=
  r =3D cygwin_fork_helper1 (u->data_start,=0A=
			   u->data_end,=0A=
			   u->bss_start,=0A=
			   u->bss_end);=0A=
=0A=
  /* Must convert result to get it through setjmp ok.  */=0A=
  longjmp (b, r =3D=3D -1 ? -2 : r =3D=3D 0 ? -1 : r);=0A=
}=0A=
=0A=
/* Utility to dump a setjmp buf.  */=0A=
=0A=
void=0A=
dump_jmp_buf (jmp_buf buf)=0A=
{=0A=
#ifdef __i386__=0A=
  debug_printf ("jmp_buf: eax 0x%x, ebx 0x%x, ecx 0x%x, edx 0x%x\n",=0A=
		buf[0], buf[1], buf[2], buf[3]);=0A=
  debug_printf ("jmp_buf: esi 0x%x, edi 0x%x, ebp 0x%x, esp 0x%x\n",=0A=
		buf[4], buf[5], buf[6], buf[7]);=0A=
  short *s =3D (short *) &buf[9];=0A=
  debug_printf ("jmp_buf: es 0x%x, fs 0x%x, gs 0x%x, ss 0x%x\n",=0A=
		s[0], s[1], s[2], s[3]);=0A=
  debug_printf ("jmp_buf: eip: 0x%x\n", buf[8]);=0A=
#endif=0A=
}=0A=
=0A=
extern "C"=0A=
int=0A=
vfork () =0A=
{=0A=
  return fork ();=0A=
}=0A=
=0A=
extern "C"=0A=
int=0A=
fork ()=0A=
{=0A=
  /* FIXME: Was there a real reason for this?  */=0A=
  alloca (100);=0A=
=0A=
  int r =3D __fork ();=0A=
  return r;=0A=
}=0A=

------ =_NextPart_000_01BCB240.03307650
Content-Type: application/octet-stream;
	name="mmap.cc"
Content-Transfer-Encoding: quoted-printable
Content-Disposition: attachment;
	filename="mmap.cc"

/* mmap.cc=0A=
=0A=
   Copyright 1996, 1997 Cygnus Solutions=0A=
=0A=
This program is free software; you can redistribute it and/or modify=0A=
it under the terms of the GNU General Public License as published by=0A=
the Free Software Foundation; either version 2 of the License, or=0A=
(at your option) any later version.=0A=
=0A=
This program is distributed in the hope that it will be useful,=0A=
but WITHOUT ANY WARRANTY; without even the implied warranty of=0A=
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the=0A=
GNU General Public License for more details.=0A=
=0A=
You should have received a copy of the GNU General Public License=0A=
along with this program; if not, write to the Free Software=0A=
Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, =
USA.  */=0A=
=0A=
#include <stdlib.h>=0A=
#include <stddef.h>=0A=
#include <sys/types.h>=0A=
#include <sys/mman.h>=0A=
#include <errno.h>=0A=
/* STD defines/includes */=0A=
#define times __hide_times=0A=
#define __THROW_BAD_ALLOC return 0=0A=
#include <list.h>=0A=
#include <map.h>=0A=
#undef times=0A=
=0A=
#include "winsup.h"=0A=
#include "fhandler.h"=0A=
=0A=
/* STL includes */=0A=
/*=0A=
 * Simple class used to keep a record of all current=0A=
 * mmap areas in a process. Needed so that=0A=
 * they can be duplicated after a fork().=0A=
 */=0A=
=0A=
class mmap_record {=0A=
=0A=
private:=0A=
=0A=
  HANDLE mapping_handle_;=0A=
  DWORD access_mode_;=0A=
  DWORD offset_;=0A=
  DWORD size_to_map_;=0A=
  void *base_address_;=0A=
=0A=
public:=0A=
=0A=
  mmap_record(HANDLE h, DWORD ac, DWORD o, DWORD s, void *b)=0A=
       : mapping_handle_(h), access_mode_(ac), offset_(o),=0A=
         size_to_map_(s), base_address_(b) { ; }=0A=
=0A=
  /* Default Copy constructor/operator=3D/destructor are ok */=0A=
=0A=
  /* Simple accessors */=0A=
  HANDLE get_handle() const { return mapping_handle_; }=0A=
  DWORD get_access() const { return access_mode_; }=0A=
  DWORD get_offset() const { return offset_; }=0A=
  DWORD get_size() const { return size_to_map_; }=0A=
  void *get_address() const { return base_address_; }=0A=
};=0A=
=0A=
/*=0A=
 * Code to keep a record of all mmap'ed area's in a process.=0A=
 * Needed to duplicate tham in a child of fork().=0A=
 * mmap_record classes are kept in an STL list in an STL map, keyed=0A=
 * by file descriptor. This is *NOT* duplicated accross a fork(), it=0A=
 * needs to be specially handled by the fork code.=0A=
 */=0A=
=0A=
static map< int, list<mmap_record> * > *mmapped_areas;=0A=
=0A=
extern "C" {=0A=
=0A=
caddr_t mmap(caddr_t addr, size_t len, int prot, int flags, int fd, =
off_t off)=0A=
{=0A=
  syscall_printf ("mmap: addr =3D %x, len =3D %d, prot =3D %x, flags =
=3D %x, fd =3D %d, off =3D %d\n",=0A=
                   addr, len, prot, flags, fd, off);=0A=
=0A=
  BOOL is_win95 =3D windows_95();=0A=
=0A=
  /* No fixed addresses on windows 95 - loser OS */=0A=
  if(is_win95 && (flags & MAP_FIXED)) {=0A=
    set_errno(EINVAL);=0A=
    syscall_printf ("-1 =3D mmap(): win95 and MAP_FIXED\n");=0A=
    return (caddr_t)-1;=0A=
  }=0A=
=0A=
  if(mmapped_areas =3D=3D 0) {=0A=
    /* First mmap call, create STL map */=0A=
    mmapped_areas =3D new map< int, list<mmap_record> * >;=0A=
    if(mmapped_areas =3D=3D 0) {=0A=
      set_errno(ENOMEM);=0A=
      syscall_printf ("-1 =3D mmap(): ENOMEM\n");=0A=
      return (caddr_t)-1;=0A=
    }=0A=
  }=0A=
=0A=
  DWORD access =3D (prot & PROT_WRITE) ? FILE_MAP_WRITE : =
FILE_MAP_READ;=0A=
  if (flags & MAP_PRIVATE) access =3D FILE_MAP_COPY;=0A=
  DWORD protect;=0A=
  =0A=
  if( access & FILE_MAP_COPY )=0A=
    protect =3D PAGE_WRITECOPY;=0A=
  else if( access & FILE_MAP_WRITE)=0A=
    protect =3D PAGE_READWRITE;=0A=
  else=0A=
    protect =3D PAGE_READONLY;=0A=
=0A=
  SECURITY_ATTRIBUTES sa;=0A=
  sa.nLength =3D sizeof (SECURITY_ATTRIBUTES);=0A=
  sa.bInheritHandle =3D TRUE;=0A=
  sa.lpSecurityDescriptor =3D 0;=0A=
=0A=
  HANDLE hFile;=0A=
  if(fd =3D=3D -1)=0A=
    hFile =3D (HANDLE)0xFFFFFFFF;=0A=
  else {=0A=
    /* Ensure that fd is open */=0A=
    if(NOT_OPEN_FD (fd)) {=0A=
      set_errno(EBADF);=0A=
      syscall_printf ("-1 =3D mmap(): EBADF\n");=0A=
      return (caddr_t)-1;=0A=
    }=0A=
    hinfo_vec *hvec =3D &u->self->hmap;=0A=
    hFile =3D (*hvec)[fd].h->get_handle();=0A=
  }=0A=
  HANDLE h =3D CreateFileMapping( hFile, &sa, protect, 0, len, =
NULL);=0A=
  if(h =3D=3D 0) {=0A=
    __seterrno();=0A=
    syscall_printf ("-1 =3D mmap(): CreateFileMapping failed with =
%d\n", GetLastError());=0A=
    return (caddr_t)-1;=0A=
  }=0A=
=0A=
  void *base;=0A=
=0A=
  if(flags & MAP_FIXED) {=0A=
    base =3D MapViewOfFileEx( h, access, 0, off, len, addr);=0A=
    if(base !=3D addr) {=0A=
      __seterrno();=0A=
      syscall_printf ("-1 =3D mmap(): MapViewOfFileEx failed with =
%d\n", GetLastError());=0A=
      CloseHandle(h);=0A=
      return (caddr_t)-1;=0A=
    }=0A=
  } else {=0A=
    base =3D MapViewOfFile( h, access, 0, off, len);=0A=
    if(base =3D=3D 0) {=0A=
      __seterrno();=0A=
      syscall_printf ("-1 =3D mmap(): MapViewOfFile failed with %d\n", =
GetLastError());=0A=
      CloseHandle(h);=0A=
      return (caddr_t)-1;=0A=
    }=0A=
  }=0A=
=0A=
  /* Ok, so we have a successfully mmap'ed area.=0A=
     Now save it so that a fork'ed child can reproduce it.=0A=
  */=0A=
=0A=
  mmap_record mmap_rec(h, access, off, len, base);=0A=
=0A=
  /* Get the list of mmapped areas for this fd, create a new=0A=
     one if one doesn't exist yet. =0A=
  */=0A=
=0A=
  list<mmap_record> *l =3D (*mmapped_areas)[fd];=0A=
  if(l =3D=3D 0) {=0A=
    /* Create a new one */=0A=
    l =3D new list<mmap_record>;=0A=
    if(l =3D=3D 0) {=0A=
      UnmapViewOfFile(base);=0A=
      CloseHandle(h);=0A=
      set_errno(ENOMEM);=0A=
      syscall_printf ("-1 =3D mmap(): ENOMEM\n");=0A=
      return (caddr_t)-1;=0A=
    }=0A=
    (*mmapped_areas)[fd] =3D l;=0A=
  }=0A=
=0A=
  /* Insert into the list */=0A=
  l->push_front(mmap_rec);=0A=
=0A=
  syscall_printf ("%x =3D mmap() succeeded\n", base);=0A=
  return (caddr_t)base;=0A=
}=0A=
=0A=
/*=0A=
 * Call to remove an mmap'ed area. Insists that base requested=0A=
 * is the same as that mmap'ed, error if not.=0A=
 */=0A=
=0A=
int munmap( caddr_t addr, size_t len)=0A=
{=0A=
  syscall_printf ("munmap(addr =3D %x, len =3D %d)\n", addr, len);=0A=
=0A=
  /*=0A=
   * Check if a mmap'ed area was ever created.=0A=
   */=0A=
  if(mmapped_areas =3D=3D 0) {=0A=
    syscall_printf ("-1 =3D munmap(): mmapped_areas =3D=3D 0\n");=0A=
    set_errno(EINVAL);=0A=
    return -1;=0A=
  }=0A=
=0A=
  /*=0A=
   * Iterate through the map, looking for the mmap'ed area.=0A=
   * Error if not found.=0A=
   */=0A=
=0A=
  map< int, list<mmap_record> * >::iterator it;=0A=
=0A=
  for( it =3D mmapped_areas->begin(); it !=3D mmapped_areas->end(); =
++it)=0A=
    {=0A=
      list<mmap_record> *l =3D (*it).second;=0A=
      if(l !=3D 0)=0A=
        {=0A=
          list<mmap_record>::iterator li;=0A=
          for( li =3D l->begin(); li !=3D l->end(); ++li)=0A=
            {=0A=
              mmap_record rec =3D *li;=0A=
              if(rec.get_address() =3D=3D addr)=0A=
                {=0A=
                  /* Unmap the area */=0A=
                  UnmapViewOfFile(addr);=0A=
                  CloseHandle(rec.get_handle());=0A=
                  /* Delete the entry. */=0A=
                  l->erase(li);=0A=
                  syscall_printf ("0 =3D munmap(): %x\n", addr);=0A=
                  return 0;=0A=
                }=0A=
             }=0A=
         }=0A=
     }=0A=
  set_errno(EINVAL);=0A=
=0A=
  syscall_printf ("-1 =3D munmap(): EINVAL\n");=0A=
=0A=
  return -1;=0A=
}                =0A=
=0A=
/*=0A=
 * Sync file with memory. Ignore flags for now.=0A=
 */=0A=
=0A=
int msync( caddr_t addr, size_t len, int flags)=0A=
{=0A=
  syscall_printf("msync: addr =3D %x, len =3D %d, flags =3D %x\n",=0A=
                  addr, len, flags);=0A=
=0A=
  if(FlushViewOfFile(addr, len) =3D=3D 0)=0A=
    {=0A=
      syscall_printf("-1 =3D msync: LastError =3D %x\n", =
GetLastError());=0A=
      __seterrno();=0A=
      return -1;=0A=
    }=0A=
  syscall_printf("0 =3D msync\n");=0A=
  return 0;=0A=
}=0A=
=0A=
/*=0A=
 * Set memory protection.=0A=
 */=0A=
=0A=
int mprotect(caddr_t addr, size_t len, int prot)=0A=
{=0A=
  DWORD old_prot;=0A=
  DWORD new_prot =3D 0;=0A=
=0A=
  syscall_printf("mprotect(addr =3D %x, len =3D %d, prot =3D %x)\n",=0A=
                  addr, len, prot);=0A=
=0A=
  if(prot & PROT_NONE)=0A=
    new_prot =3D PAGE_NOACCESS;=0A=
  else =0A=
    {=0A=
      switch(prot)=0A=
        {=0A=
          case PROT_READ|PROT_WRITE|PROT_EXEC:=0A=
            new_prot =3D PAGE_EXECUTE_READWRITE;=0A=
            break;=0A=
          case PROT_READ|PROT_WRITE:=0A=
            new_prot =3D PAGE_READWRITE;=0A=
            break;=0A=
          case PROT_READ|PROT_EXEC:=0A=
            new_prot =3D PAGE_EXECUTE_READ;=0A=
            break;=0A=
          case PROT_READ:=0A=
            new_prot =3D PAGE_READONLY;=0A=
            break;=0A=
          default:=0A=
            syscall_printf("-1 =3D mprotect(): invalid prot =
value\n");=0A=
            set_errno(EINVAL);=0A=
            return -1;=0A=
         }=0A=
     }=0A=
  if(VirtualProtect(addr, len, prot, &old_prot)=3D=3D 0)=0A=
    {=0A=
      __seterrno();=0A=
      syscall_printf("-1 =3D mprotect(): lasterror =3D %x\n", =
GetLastError());=0A=
      return -1;=0A=
    }=0A=
  syscall_printf("0 =3D mprotect()\n");=0A=
  return 0;=0A=
}=0A=
=0A=
};=0A=
=0A=
=0A=
/*=0A=
 * Called by the parent process durring a fork.  At this point, the =
child has=0A=
 * not yet run.  When it does run and initialize, we want it to =
re-establish=0A=
 * the same mmap regions that we have.  Because our heap, where our=0A=
 * mmap_records are stored, will not have been copied to the child at =
the time=0A=
 * it initializes, we can't simply pass it the "mmapped_areas" =
pointer.=0A=
 * Instead, we must copy the contents of our "mmapped_areas" into an =
array of=0A=
 * mmap_records where the child process can read them.  The =
"child->mmap_ptr"=0A=
 * is set to a handle for the memory where the the child will find the =
array.=0A=
 * After we return, we will suspend and the child will initialize and =
call=0A=
 * "recreate_mmaps_after_fork" below.=0A=
 */=0A=
=0A=
int copy_mmap_records_to_forkee(pinfo *child)=0A=
{=0A=
  /*=0A=
   * Count the number of mmap_record entries are in the "mmapped_areas" =
map.=0A=
   */=0A=
  unsigned count =3D 0;=0A=
  map< int, list<mmap_record> * >::iterator it;=0A=
  if (mmapped_areas !=3D NULL)=0A=
  {=0A=
    for( it =3D mmapped_areas->begin(); it !=3D mmapped_areas->end(); =
++it)=0A=
    {=0A=
      list<mmap_record> *l =3D (*it).second;=0A=
      if(l !=3D 0)=0A=
      {=0A=
        list<mmap_record>::iterator li;=0A=
        for( li =3D l->begin(); li !=3D l->end(); ++li)=0A=
            count++;=0A=
      }=0A=
    }=0A=
  }=0A=
=0A=
  /*=0A=
   * Return with "child->mmap_ptr =3D=3D NULL"; there are no mmap =
regions.=0A=
   */=0A=
  if (count =3D=3D 0)=0A=
  {=0A=
    child->mmap_ptr =3D NULL;=0A=
    debug_printf("copy_mmap_records_to_forkee: succeeded\n");=0A=
    return 0;=0A=
  }=0A=
=0A=
  /*=0A=
   * Create a file mapping that will be made available to the child =
process=0A=
   * and will hold an array of all the mmap_records in =
"mmapped_areas".=0A=
   */=0A=
  HANDLE h =3D CreateFileMapping((HANDLE)-1, NULL, PAGE_READWRITE, =
0,=0A=
                               (count+1)*sizeof(mmap_record), NULL);=0A=
  if (h =3D=3D NULL)=0A=
  {=0A=
    syscall_printf("copy_mmap_records_to_forkee: CreateFileMapping =
failed\n");=0A=
    return -1;=0A=
  }=0A=
=0A=
  mmap_record* pRec =3D (mmap_record*)MapViewOfFile(h, FILE_MAP_WRITE, =
0, 0, 0);=0A=
  if (pRec =3D=3D NULL)=0A=
  {=0A=
    CloseHandle(h);=0A=
    syscall_printf("copy_mmap_records_to_forkee: MapViewOfFile =
failed\n");=0A=
    return -1;=0A=
  }=0A=
=0A=
  /*=0A=
   * Now copy all the mmap_records into the mapped memory array.=0A=
   * The count of elements in this array are in the first record=0A=
   * along with some other useful info.=0A=
   */=0A=
  *pRec =3D mmap_record(0, 0, (DWORD)mmapped_areas, count, pRec);=0A=
  if (mmapped_areas !=3D NULL)=0A=
  {=0A=
    for( it =3D mmapped_areas->begin(); it !=3D mmapped_areas->end(); =
++it)=0A=
    {=0A=
      list<mmap_record> *l =3D (*it).second;=0A=
      if(l !=3D 0)=0A=
      {=0A=
        list<mmap_record>::iterator li;=0A=
        for( li =3D l->begin(); li !=3D l->end(); ++li)=0A=
          *(++pRec) =3D *li;=0A=
      }=0A=
    }=0A=
  }=0A=
=0A=
  /*=0A=
   * Duplicate the handle for use by the child process. The child =
process=0A=
   * will use the duplicate handle in recreate_mmaps_after_fork.=0A=
   * We also unmap our view and close our handle, since we're done with =
it.=0A=
   */=0A=
  UnmapViewOfFile(pRec - count);=0A=
  DuplicateHandle(GetCurrentProcess(), h, child->hProcess,=0A=
                  (LPHANDLE)&child->mmap_ptr, FILE_MAP_READ,=0A=
                  FALSE, DUPLICATE_CLOSE_SOURCE);=0A=
=0A=
  debug_printf("copy_mmap_records_to_forkee: succeeded\n");=0A=
  return 0;=0A=
}=0A=
=0A=
=0A=
/*=0A=
 * Call to re-create all the file mappings in a fork()'ed child.  =
Called from=0A=
 * "cygwin_fork_helper1" by the child durring initialization.  At this =
point,=0A=
 * the parent has duplicated its .data and .bss, but not its stack or =
heap.=0A=
 * We are passed a handle to memory via "u->self->mmap_ptr" where an =
array of=0A=
 * mmap_records can be found.  This was put there by our parent in its =
call=0A=
 * to "copy_mmap_records_to_forkee".  The first record in the array =
contains=0A=
 * information like the count of records.  All the HANDLE's in those =
records=0A=
 * are valid for us (we inherited them), but none of the mapped =
areas=0A=
 * are in our address space.  We need to iterate through the array and =
do the=0A=
 * MapViewOfFileEx calls.  Initially, the "mmapped_areas" pointer is =
assumed to=0A=
 * be NULL, since this process was just created.  Before returning, =
both=0A=
 * "mmapped_areas" and "u->self->mmap_ptr" are set to point to the mmap =
data=0A=
 * structure in the heap.  This pointer is also passed to us in the =
first=0A=
 * mmap_record.  Remember, that pointer refers to heap memory which the =
parent=0A=
 * process hasn't yet copied to us.  After we return, we will suspend =
while we=0A=
 * wait for our parent to copy our heap (so that "mmaped_areas" is =
valid).=0A=
 * All of our mmap regions, except the ones that the parent created =
with=0A=
 * FILE_MAP_COPY, will refer to the same physical memory that the =
cooresponding=0A=
 * region in our parent refers to.  In the case of FILE_MAP_COPY =
regions, we=0A=
 * will see the contents of the original file at the time the parent =
mmapped it.=0A=
 * Any changes made by the parent to these regions will not be seen by =
us.  So,=0A=
 * the parent will also need to call "copy_copyonwrite_mmaps_to_forkee" =
below so=0A=
 * that we are in sync with the parent immediately after the fork.=0A=
 */=0A=
=0A=
int recreate_mmaps_after_fork(void *param)=0A=
{=0A=
  if (param !=3D NULL)=0A=
{=0A=
=0A=
  HANDLE h =3D (HANDLE)param;=0A=
  mmap_record* pRec =3D (mmap_record*)MapViewOfFile(h, FILE_MAP_READ, =
0, 0,=0A=
                       sizeof(mmap_record));=0A=
  if (pRec =3D=3D NULL)=0A=
  {=0A=
    small_printf("-1 =3D recreate_mmaps_after_fork(): MapViewOfFile =
failed "=0A=
                 "with GetLastError =3D %x\n", GetLastError());=0A=
    return -1;=0A=
  }=0A=
=0A=
  /*=0A=
   * Copy the information that was put in the first record=0A=
   * (see set_child_mmap_ptr).=0A=
   */=0A=
  void* pRecDesired =3D pRec->get_address();=0A=
  unsigned count =3D pRec->get_size();=0A=
  mmapped_areas =3D (map< int, list<mmap_record> * > =
*)pRec->get_offset();=0A=
=0A=
  /*=0A=
   * We need to have the array of mmap_records at the address =
"pRecDesired".=0A=
   * Otherwise, this array may be overlapping one of the mapped =
regions=0A=
   * in the parent that we are trying to duplicate.  It is unlikely =
that=0A=
   * we are so lucky as to have "pRec" mapped correctly the first time, =
so=0A=
   * unmap this view and re-map it using MapViewOfFileEx.=0A=
   */=0A=
  UnmapViewOfFile(pRec);=0A=
=0A=
  if (count > 0)=0A=
  {=0A=
    pRec =3D (mmap_record*)MapViewOfFileEx(h, FILE_MAP_READ, 0, 0, 0, =
pRecDesired);=0A=
    if (pRec =3D=3D NULL)=0A=
    {=0A=
      small_printf("-1 =3D recreate_mmaps_after_fork(): MapViewOfFileEx =
failed "=0A=
                   "with GetLastError =3D %x\n", GetLastError());=0A=
      return -1;=0A=
    }=0A=
=0A=
    if (pRec !=3D pRecDesired)=0A=
    {=0A=
      small_printf("-1 =3D recreate_mmaps_after_fork(): MapViewOfFileEx =
wrong address\n");=0A=
      return -1;=0A=
    }=0A=
=0A=
    /*=0A=
     * Copy the "pRec" mmap_record array into the=0A=
     * "mmaped_areas" map of mmap_record lists.=0A=
     */=0A=
    while (count-- > 0)=0A=
    {=0A=
      ++pRec;=0A=
=0A=
      /* Now re-create the MapViewOfFileEx call */=0A=
      void* base =3D MapViewOfFileEx(pRec->get_handle(), =
pRec->get_access(),=0A=
                                   0, pRec->get_offset(),=0A=
                                   pRec->get_size(), =
pRec->get_address());=0A=
      if(base !=3D pRec->get_address())=0A=
      {=0A=
        small_printf("recreate_mmaps_after_fork: base address %x\=0A=
            fails to match requested address %x\n", base, =
pRec->get_address());=0A=
        return -1;=0A=
      }=0A=
=0A=
      debug_printf("recreate_mmaps_after_fork: h =3D %x, access =3D %x, =
offset =3D %d, \=0A=
          size =3D %d, address =3D %x\n", pRec->get_handle(), =
pRec->get_access(),=0A=
          pRec->get_offset(), pRec->get_size(), =
pRec->get_address());=0A=
    }=0A=
=0A=
    UnmapViewOfFile(pRecDesired);=0A=
  }=0A=
  CloseHandle(h);=0A=
=0A=
}=0A=
=0A=
  /* Now set our mmap record in case the child forks. */=0A=
  u->self->mmap_ptr =3D mmapped_areas;=0A=
=0A=
  debug_printf("recreate_mmaps_after_fork: succeeded\n");=0A=
  return 0;=0A=
}=0A=
=0A=
=0A=
/*=0A=
 * Called by the parent process durring a fork.  At this point,=0A=
 * the address space of the child process has been established;=0A=
 * that is, the child has already called =
"recreate_mmaps_after_fork".=0A=
 * Any mmap region created with "FILE_MAP_COPY" will need to be=0A=
 * copied to the cooresponding memory addresses in the child =
process,=0A=
 * or else the parent and child may not see the same contents at =
those=0A=
 * addresses.  They will be different for those FILE_MAP_COPY =
regions=0A=
 * that the parent has written to (unless the parent wrote what was=0A=
 * there originally).=0A=
 */=0A=
=0A=
extern int copy_memory_to_forkee (HANDLE child, void *low, void *high, =
int);=0A=
=0A=
int copy_copyonwrite_mmaps_to_forkee(HANDLE hChild)=0A=
{=0A=
  /*=0A=
   * Iterate through the array if mmap_records and copy those =
entries=0A=
   * that have FILE_MAP_COPY set.=0A=
   */=0A=
  map< int, list<mmap_record> * >::iterator it;=0A=
  if (mmapped_areas !=3D NULL)=0A=
  {=0A=
    for( it =3D mmapped_areas->begin(); it !=3D mmapped_areas->end(); =
++it)=0A=
    {=0A=
      list<mmap_record> *l =3D (*it).second;=0A=
      if(l !=3D 0)=0A=
      {=0A=
          list<mmap_record>::iterator li;=0A=
          for( li =3D l->begin(); li !=3D l->end(); ++li)=0A=
          {=0A=
            mmap_record& rec =3D *li;=0A=
            char* start =3D (char*)rec.get_address() + =
rec.get_offset();=0A=
=0A=
            if ((rec.get_access() & FILE_MAP_COPY) &&=0A=
                !copy_memory_to_forkee(hChild, start, start + =
rec.get_size(), 0))=0A=
            {=0A=
              syscall_printf("copy_copyonwrite_mmaps_to_forkee: =
copy_memory_to_forkee failed\n");=0A=
              return -1;=0A=
            }=0A=
=0A=
	        debug_printf("copy_copyonwrite_mmaps_to_forkee: h =3D %x, "=0A=
                "access =3D %x, offset =3D %d, size =3D %d, address =3D =
%x\n",=0A=
                rec.get_handle(), rec.get_access(), =
rec.get_offset(),=0A=
                rec.get_size(), rec.get_address());=0A=
          }=0A=
      }=0A=
    }=0A=
  }=0A=
=0A=
  debug_printf("copy_copyonwrite_mmaps_to_forkee: succeeded\n");=0A=
  return 0;=0A=
}=0A=

------ =_NextPart_000_01BCB240.03307650--
-
For help on using this list (especially unsubscribing), send a message to
"[email-masked]" with one line of text: "help".