OSDN Git Service

* exceptions.cc (dump_exception): Use %W instead of %s for printing
[pf3gnuchains/pf3gnuchains4x.git] / winsup / cygwin / fork.cc
1 /* fork.cc
2
3    Copyright 1996, 1997, 1998, 1999, 2000, 2001, 2002, 2004, 2005, 2006,
4    2007, 2008, 2009 Red Hat, Inc.
5
6 This file is part of Cygwin.
7
8 This software is a copyrighted work licensed under the terms of the
9 Cygwin license.  Please consult the file "CYGWIN_LICENSE" for
10 details. */
11
12 #include "winsup.h"
13 #include <stdio.h>
14 #include <unistd.h>
15 #include <stdlib.h>
16 #include "cygerrno.h"
17 #include "path.h"
18 #include "fhandler.h"
19 #include "dtable.h"
20 #include "sigproc.h"
21 #include "pinfo.h"
22 #include "cygheap.h"
23 #include "child_info.h"
24 #include "cygtls.h"
25 #include "tls_pbuf.h"
26 #include "dll_init.h"
27 #include "cygmalloc.h"
28
29 #define NPIDS_HELD 4
30
31 /* Timeout to wait for child to start, parent to init child, etc.  */
32 /* FIXME: Once things stabilize, bump up to a few minutes.  */
33 #define FORK_WAIT_TIMEOUT (300 * 1000)     /* 300 seconds */
34
35 class frok
36 {
37   bool load_dlls;
38   child_info_fork ch;
39   const char *error;
40   int child_pid;
41   int this_errno;
42   int __stdcall parent (volatile char * volatile here);
43   int __stdcall child (volatile char * volatile here);
44   friend int fork ();
45 };
46
47 class lock_signals
48 {
49   bool worked;
50 public:
51   lock_signals ()
52   {
53     worked = sig_send (NULL, __SIGHOLD) == 0;
54   }
55   operator int () const
56   {
57     return worked;
58   }
59   void dont_bother ()
60   {
61     worked = false;
62   }
63   ~lock_signals ()
64   {
65     if (worked)
66       sig_send (NULL, __SIGNOHOLD);
67   }
68 };
69
70 class lock_pthread
71 {
72   bool bother;
73 public:
74   lock_pthread (): bother (1)
75   {
76     pthread::atforkprepare ();
77   }
78   void dont_bother ()
79   {
80     bother = false;
81   }
82   ~lock_pthread ()
83   {
84     if (bother)
85       pthread::atforkparent ();
86   }
87 };
88
89 class hold_everything
90 {
91 public: /* DELETEME*/
92   bool& ischild;
93   /* Note the order of the locks below.  It is important,
94      to avoid races, that the lock order be preserved.
95
96      pthread is first because it serves as a master lock
97      against other forks being attempted while this one is active.
98
99      signals is next to stop signal processing for the duration
100      of the fork.
101
102      process is last.  If it is put before signals, then a deadlock
103      could be introduced if the process attempts to exit due to a signal. */
104   lock_pthread pthread;
105   lock_signals signals;
106   lock_process process;
107
108 public:
109   hold_everything (bool& x): ischild (x) {}
110   operator int () const {return signals;}
111
112   ~hold_everything()
113   {
114     if (ischild)
115       {
116         pthread.dont_bother ();
117         process.dont_bother ();
118         signals.dont_bother ();
119       }
120   }
121
122 };
123
124 static void
125 resume_child (HANDLE forker_finished)
126 {
127   SetEvent (forker_finished);
128   debug_printf ("signalled child");
129   return;
130 }
131
132 /* Notify parent that it is time for the next step. */
133 static void __stdcall
134 sync_with_parent (const char *s, bool hang_self)
135 {
136   debug_printf ("signalling parent: %s", s);
137   fork_info->ready (false);
138   if (hang_self)
139     {
140       HANDLE h = fork_info->forker_finished;
141       /* Wait for the parent to fill in our stack and heap.
142          Don't wait forever here.  If our parent dies we don't want to clog
143          the system.  If the wait fails, we really can't continue so exit.  */
144       DWORD psync_rc = WaitForSingleObject (h, FORK_WAIT_TIMEOUT);
145       debug_printf ("awake");
146       switch (psync_rc)
147         {
148         case WAIT_TIMEOUT:
149           api_fatal ("WFSO timed out %s", s);
150           break;
151         case WAIT_FAILED:
152           if (GetLastError () == ERROR_INVALID_HANDLE &&
153               WaitForSingleObject (fork_info->forker_finished, 1) != WAIT_FAILED)
154             break;
155           api_fatal ("WFSO failed %s, fork_finished %p, %E", s,
156                      fork_info->forker_finished);
157           break;
158         default:
159           debug_printf ("no problems");
160           break;
161         }
162     }
163 }
164
165 int __stdcall
166 frok::child (volatile char * volatile here)
167 {
168   HANDLE& hParent = ch.parent;
169   extern void fixup_lockf_after_fork ();
170   extern void fixup_hooks_after_fork ();
171   extern void fixup_timers_after_fork ();
172   debug_printf ("child is running.  pid %d, ppid %d, stack here %p",
173                 myself->pid, myself->ppid, __builtin_frame_address (0));
174
175   sync_with_parent ("after longjmp", true);
176   sigproc_printf ("hParent %p, load_dlls %d", hParent, load_dlls);
177
178   /* If we've played with the stack, stacksize != 0.  That means that
179      fork() was invoked from other than the main thread.  Make sure that
180      the threadinfo information is properly set up.  */
181   if (fork_info->stacksize)
182     {
183       _main_tls = &_my_tls;
184       _main_tls->init_thread (NULL, NULL);
185       _main_tls->local_clib = *_impure_ptr;
186       _impure_ptr = &_main_tls->local_clib;
187     }
188
189   set_cygwin_privileges (hProcToken);
190   clear_procimptoken ();
191   cygheap->user.reimpersonate ();
192
193 #ifdef DEBUGGING
194   if (GetEnvironmentVariableA ("FORKDEBUG", NULL, 0))
195     try_to_debug ();
196   char buf[80];
197   /* This is useful for debugging fork problems.  Use gdb to attach to
198      the pid reported here. */
199   if (GetEnvironmentVariableA ("CYGWIN_FORK_SLEEP", buf, sizeof (buf)))
200     {
201       small_printf ("Sleeping %d after fork, pid %u\n", atoi (buf), GetCurrentProcessId ());
202       Sleep (atoi (buf));
203     }
204 #endif
205
206   MALLOC_CHECK;
207
208   /* Incredible but true:  If we use sockets and SYSV IPC shared memory,
209      there's a good chance that a duplicated socket in the child occupies
210      memory which is needed to duplicate shared memory from the parent
211      process, if the shared memory hasn't been duplicated already.
212      The same goes very likely for "normal" mmap shared memory, too, but
213      with SYSV IPC it was the first time observed.  So, *never* fixup
214      fdtab before fixing up shared memory. */
215   if (fixup_shms_after_fork ())
216     api_fatal ("recreate_shm areas after fork failed");
217
218   MALLOC_CHECK;
219
220   /* If we haven't dynamically loaded any dlls, just signal
221      the parent.  Otherwise, load all the dlls, tell the parent
222       that we're done, and wait for the parent to fill in the.
223       loaded dlls' data/bss. */
224   if (!load_dlls)
225     {
226       cygheap->fdtab.fixup_after_fork (hParent);
227       sync_with_parent ("performed fork fixup", false);
228     }
229   else
230     {
231       dlls.load_after_fork (hParent);
232       cygheap->fdtab.fixup_after_fork (hParent);
233       sync_with_parent ("loaded dlls", true);
234     }
235
236   init_console_handler (myself->ctty >= 0);
237   ForceCloseHandle1 (fork_info->forker_finished, forker_finished);
238
239   pthread::atforkchild ();
240   fixup_timers_after_fork ();
241   cygbench ("fork-child");
242   ld_preload ();
243   fixup_hooks_after_fork ();
244   _my_tls.fixup_after_fork ();
245   wait_for_sigthread ();
246   cygwin_finished_initializing = true;
247   return 0;
248 }
249
250 #define NO_SLOW_PID_REUSE
251 #ifndef NO_SLOW_PID_REUSE
252 static void
253 slow_pid_reuse (HANDLE h)
254 {
255   static NO_COPY HANDLE last_fork_procs[NPIDS_HELD];
256   static NO_COPY unsigned nfork_procs;
257
258   if (nfork_procs >= (sizeof (last_fork_procs) / sizeof (last_fork_procs [0])))
259     nfork_procs = 0;
260   /* Keep a list of handles to child processes sitting around to prevent
261      Windows from reusing the same pid n times in a row.  Having the same pids
262      close in succesion confuses bash.  Keeping a handle open will stop
263      windows from reusing the same pid.  */
264   if (last_fork_procs[nfork_procs])
265     ForceCloseHandle1 (last_fork_procs[nfork_procs], fork_stupidity);
266   if (DuplicateHandle (GetCurrentProcess (), h,
267                        GetCurrentProcess (), &last_fork_procs[nfork_procs],
268                        0, FALSE, DUPLICATE_SAME_ACCESS))
269     ProtectHandle1 (last_fork_procs[nfork_procs], fork_stupidity);
270   else
271     {
272       last_fork_procs[nfork_procs] = NULL;
273       system_printf ("couldn't create last_fork_proc, %E");
274     }
275   nfork_procs++;
276 }
277 #endif
278
279 int __stdcall
280 frok::parent (volatile char * volatile stack_here)
281 {
282   HANDLE forker_finished;
283   DWORD rc;
284   child_pid = -1;
285   error = NULL;
286   this_errno = 0;
287   bool fix_impersonation = false;
288   pinfo child;
289   static char errbuf[NT_MAX_PATH + 256];
290
291   int c_flags = GetPriorityClass (GetCurrentProcess ());
292   debug_printf ("priority class %d", c_flags);
293
294   /* If we don't have a console, then don't create a console for the
295      child either.  */
296   HANDLE console_handle = CreateFile ("CONOUT$", GENERIC_WRITE,
297                                       FILE_SHARE_WRITE, &sec_none_nih,
298                                       OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL,
299                                       NULL);
300
301   if (console_handle != INVALID_HANDLE_VALUE)
302     CloseHandle (console_handle);
303   else
304     c_flags |= DETACHED_PROCESS;
305
306   /* Some file types (currently only sockets) need extra effort in the
307      parent after CreateProcess and before copying the datastructures
308      to the child. So we have to start the child in suspend state,
309      unfortunately, to avoid a race condition. */
310   if (cygheap->fdtab.need_fixup_before ())
311     c_flags |= CREATE_SUSPENDED;
312
313   /* Remember if we need to load dynamically linked dlls.
314      We do this here so that this information will be available
315      in the parent and, when the stack is copied, in the child. */
316   load_dlls = dlls.reload_on_fork && dlls.loaded_dlls;
317
318   forker_finished = CreateEvent (&sec_all, FALSE, FALSE, NULL);
319   if (forker_finished == NULL)
320     {
321       this_errno = geterrno_from_win_error ();
322       error = "unable to allocate forker_finished event";
323       return -1;
324     }
325
326   ProtectHandleINH (forker_finished);
327
328   ch.forker_finished = forker_finished;
329
330   ch.stackbottom = _tlsbase;
331   ch.stacktop = (void *) stack_here;
332   ch.stacksize = (char *) ch.stackbottom - (char *) stack_here;
333   debug_printf ("stack - bottom %p, top %p, size %d",
334                 ch.stackbottom, ch.stacktop, ch.stacksize);
335
336   PROCESS_INFORMATION pi;
337   STARTUPINFOW si;
338
339   memset (&si, 0, sizeof (si));
340   si.cb = sizeof si;
341
342   si.lpReserved2 = (LPBYTE) &ch;
343   si.cbReserved2 = sizeof (ch);
344
345   syscall_printf ("CreateProcessW (%W, %W, 0, 0, 1, %p, 0, 0, %p, %p)",
346                   myself->progname, myself->progname, c_flags, &si, &pi);
347   bool locked = __malloc_lock ();
348   time_t start_time = time (NULL);
349
350   /* Remove impersonation */
351   cygheap->user.deimpersonate ();
352   fix_impersonation = true;
353
354   while (1)
355     {
356       rc = CreateProcessW (myself->progname, /* image to run */
357                            myself->progname, /* what we send in arg0 */
358                            &sec_none_nih,
359                            &sec_none_nih,
360                            TRUE,          /* inherit handles from parent */
361                            c_flags,
362                            NULL,          /* environment filled in later */
363                            0,     /* use current drive/directory */
364                            &si,
365                            &pi);
366
367       if (!rc)
368         {
369           this_errno = geterrno_from_win_error ();
370           __small_sprintf (errbuf, "CreateProcessW failed for '%W'", myself->progname);
371           error = errbuf;
372           memset (&pi, 0, sizeof (pi));
373           goto cleanup;
374         }
375
376       if (cygheap->fdtab.need_fixup_before ())
377         {
378           cygheap->fdtab.fixup_before_fork (pi.dwProcessId);
379           ResumeThread (pi.hThread);
380         }
381
382       CloseHandle (pi.hThread);
383
384       /* Protect the handle but name it similarly to the way it will
385          be called in subproc handling. */
386       ProtectHandle1 (pi.hProcess, childhProc);
387
388       strace.write_childpid (ch, pi.dwProcessId);
389
390       /* Wait for subproc to initialize itself. */
391       if (!ch.sync (pi.dwProcessId, pi.hProcess, FORK_WAIT_TIMEOUT))
392         {
393           DWORD exit_code = ch.proc_retry (pi.hProcess);
394           if (!exit_code)
395             continue;
396           this_errno = EAGAIN;
397           /* Not thread safe, but do we care? */
398           __small_sprintf (errbuf, "died waiting for longjmp before initialization, "
399                            "retry %d, exit code %p", ch.retry, exit_code);
400           error = errbuf;
401           goto cleanup;
402         }
403       break;
404     }
405
406   /* Restore impersonation */
407   cygheap->user.reimpersonate ();
408   fix_impersonation = false;
409
410   child_pid = cygwin_pid (pi.dwProcessId);
411   child.init (child_pid, 1, NULL);
412
413   if (!child)
414     {
415       this_errno = get_errno () == ENOMEM ? ENOMEM : EAGAIN;
416 #ifdef DEBUGGING
417       error = "pinfo failed";
418 #else
419       syscall_printf ("pinfo failed");
420 #endif
421       goto cleanup;
422     }
423
424   child->start_time = start_time; /* Register child's starting time. */
425   child->nice = myself->nice;
426
427   /* Initialize things that are done later in dll_crt0_1 that aren't done
428      for the forkee.  */
429   wcscpy (child->progname, myself->progname);
430
431   /* Fill in fields in the child's process table entry.  */
432   child->dwProcessId = pi.dwProcessId;
433   child.hProcess = pi.hProcess;
434
435   /* Hopefully, this will succeed.  The alternative to doing things this
436      way is to reserve space prior to calling CreateProcess and then fill
437      it in afterwards.  This requires more bookkeeping than I like, though,
438      so we'll just do it the easy way.  So, terminate any child process if
439      we can't actually record the pid in the internal table. */
440   if (!child.remember (false))
441     {
442       TerminateProcess (pi.hProcess, 1);
443       this_errno = EAGAIN;
444 #ifdef DEBUGGING0
445       error = "child.remember failed";
446 #endif
447       goto cleanup;
448     }
449
450 #ifndef NO_SLOW_PID_REUSE
451   slow_pid_reuse (pi.hProcess);
452 #endif
453
454   /* CHILD IS STOPPED */
455   debug_printf ("child is alive (but stopped)");
456
457   /* Initialize, in order: stack, dll data, dll bss.
458      data, bss, heap were done earlier (in dcrt0.cc)
459      Note: variables marked as NO_COPY will not be copied since they are
460      placed in a protected segment.  */
461
462   MALLOC_CHECK;
463   const void *impure_beg;
464   const void *impure_end;
465   const char *impure;
466   if (&_my_tls == _main_tls)
467     impure_beg = impure_end = impure = NULL;
468   else
469     {
470       impure = "impure";
471       impure_beg = _impure_ptr;
472       impure_end = _impure_ptr + 1;
473     }
474   rc = child_copy (pi.hProcess, true,
475                    "stack", stack_here, ch.stackbottom,
476                    impure, impure_beg, impure_end,
477                    NULL);
478
479   __malloc_unlock ();
480   locked = false;
481   MALLOC_CHECK;
482   if (!rc)
483     {
484       this_errno = get_errno ();
485       DWORD exit_code;
486       if (!GetExitCodeProcess (pi.hProcess, &exit_code))
487         exit_code = 0xdeadbeef;
488       __small_sprintf (errbuf, "pid %u, exitval %p", pi.dwProcessId, exit_code);
489       error = errbuf;
490       goto cleanup;
491     }
492
493   /* Now fill data/bss of any DLLs that were linked into the program. */
494   for (dll *d = dlls.istart (DLL_LINK); d; d = dlls.inext ())
495     {
496       debug_printf ("copying data/bss of a linked dll");
497       if (!child_copy (pi.hProcess, true,
498                        "linked dll data", d->p.data_start, d->p.data_end,
499                        "linked dll bss", d->p.bss_start, d->p.bss_end,
500                        NULL))
501         {
502           this_errno = get_errno ();
503 #ifdef DEBUGGING
504           DWORD exit_code;
505           if (!GetExitCodeProcess (pi.hProcess, &exit_code))
506             exit_code = 0xdeadbeef;
507           __small_sprintf (errbuf, "pid %u, exitval %p", pi.dwProcessId, exit_code);
508           error = errbuf;
509 #endif
510           goto cleanup;
511         }
512     }
513
514   /* Start thread, and then wait for it to reload dlls.  */
515   resume_child (forker_finished);
516   if (!ch.sync (child->pid, pi.hProcess, FORK_WAIT_TIMEOUT))
517     {
518       this_errno = EAGAIN;
519       error = "died waiting for dll loading";
520       goto cleanup;
521     }
522
523   /* If DLLs were loaded in the parent, then the child has reloaded all
524      of them and is now waiting to have all of the individual data and
525      bss sections filled in. */
526   if (load_dlls)
527     {
528       /* CHILD IS STOPPED */
529       /* write memory of reloaded dlls */
530       for (dll *d = dlls.istart (DLL_LOAD); d; d = dlls.inext ())
531         {
532           debug_printf ("copying data/bss for a loaded dll");
533           if (!child_copy (pi.hProcess, true,
534                            "loaded dll data", d->p.data_start, d->p.data_end,
535                            "loaded dll bss", d->p.bss_start, d->p.bss_end,
536                            NULL))
537             {
538               this_errno = get_errno ();
539 #ifdef DEBUGGING
540               error = "copying data/bss for a loaded dll";
541 #endif
542               goto cleanup;
543             }
544         }
545       /* Start the child up again. */
546       resume_child (forker_finished);
547     }
548
549   ForceCloseHandle (forker_finished);
550   forker_finished = NULL;
551
552   return child_pid;
553
554 /* Common cleanup code for failure cases */
555 cleanup:
556   if (fix_impersonation)
557     cygheap->user.reimpersonate ();
558   if (locked)
559     __malloc_unlock ();
560
561   /* Remember to de-allocate the fd table. */
562   if (pi.hProcess && !child.hProcess)
563     ForceCloseHandle1 (pi.hProcess, childhProc);
564   if (forker_finished)
565     ForceCloseHandle (forker_finished);
566   debug_printf ("returning -1");
567   return -1;
568 }
569
570 extern "C" int
571 fork ()
572 {
573   frok grouped;
574
575   debug_printf ("entering");
576   grouped.load_dlls = 0;
577
578   int res;
579   bool ischild = false;
580
581   myself->set_has_pgid_children ();
582
583   if (grouped.ch.parent == NULL)
584     return -1;
585   if (grouped.ch.subproc_ready == NULL)
586     {
587       system_printf ("unable to allocate subproc_ready event, %E");
588       return -1;
589     }
590
591   {
592     hold_everything held_everything (ischild);
593     /* This tmp_pathbuf constructor is required here because the below setjmp
594        magic will otherwise not restore the original buffer count values in
595        the thread-local storage.  A process forking too deeply will run into
596        the problem to be out of temporary TLS path buffers. */
597     tmp_pathbuf tp;
598
599     if (!held_everything)
600       {
601         if (exit_state)
602           Sleep (INFINITE);
603         set_errno (EAGAIN);
604         return -1;
605       }
606
607     ischild = !!setjmp (grouped.ch.jmp);
608
609     volatile char * volatile esp;
610     __asm__ volatile ("movl %%esp,%0": "=r" (esp));
611
612     if (!ischild)
613       res = grouped.parent (esp);
614     else
615       {
616         res = grouped.child (esp);
617         ischild = true; /* might have been reset by fork mem copy */
618       }
619   }
620
621   MALLOC_CHECK;
622   if (ischild || res > 0)
623     /* everything is ok */;
624   else
625     {
626       if (!grouped.error)
627         syscall_printf ("fork failed - child pid %d, errno %d", grouped.child_pid, grouped.this_errno);
628       else
629         {
630           char buf[strlen (grouped.error) + sizeof ("child %d - , errno 4294967295  ")];
631           strcpy (buf, "child %d - ");
632           strcat (buf, grouped.error);
633           strcat (buf, ", errno %d");
634           system_printf (buf, grouped.child_pid, grouped.this_errno);
635         }
636
637       set_errno (grouped.this_errno);
638     }
639   syscall_printf ("%d = fork()", res);
640   return res;
641 }
642 #ifdef DEBUGGING
643 void
644 fork_init ()
645 {
646 }
647 #endif /*DEBUGGING*/
648
649 #ifdef NEWVFORK
650 /* Dummy function to force second assignment below to actually be
651    carried out */
652 static vfork_save *
653 get_vfork_val ()
654 {
655   return vfork_storage.val ();
656 }
657 #endif
658
659 extern "C" int
660 vfork ()
661 {
662 #ifndef NEWVFORK
663   debug_printf ("stub called");
664   return fork ();
665 #else
666   vfork_save *vf = get_vfork_val ();
667   char **esp, **pp;
668
669   if (vf == NULL)
670     vf = vfork_storage.create ();
671   else if (vf->pid)
672     return fork ();
673
674   // FIXME the tls stuff could introduce a signal race if a child process
675   // exits quickly.
676   if (!setjmp (vf->j))
677     {
678       vf->pid = -1;
679       __asm__ volatile ("movl %%esp,%0": "=r" (vf->vfork_esp):);
680       __asm__ volatile ("movl %%ebp,%0": "=r" (vf->vfork_ebp):);
681       for (pp = (char **) vf->frame, esp = vf->vfork_esp;
682            esp <= vf->vfork_ebp + 2; pp++, esp++)
683         *pp = *esp;
684       vf->ctty = myself->ctty;
685       vf->sid = myself->sid;
686       vf->pgid = myself->pgid;
687       cygheap->ctty_on_hold = cygheap->ctty;
688       vf->console_count = cygheap->console_count;
689       debug_printf ("cygheap->ctty_on_hold %p, cygheap->console_count %d", cygheap->ctty_on_hold, cygheap->console_count);
690       int res = cygheap->fdtab.vfork_child_dup () ? 0 : -1;
691       debug_printf ("%d = vfork()", res);
692       _my_tls.call_signal_handler ();   // FIXME: racy
693       vf->tls = _my_tls;
694       return res;
695     }
696
697   vf = get_vfork_val ();
698
699   for (pp = (char **) vf->frame, esp = vf->vfork_esp;
700        esp <= vf->vfork_ebp + 2; pp++, esp++)
701     *esp = *pp;
702
703   cygheap->fdtab.vfork_parent_restore ();
704
705   myself->ctty = vf->ctty;
706   myself->sid = vf->sid;
707   myself->pgid = vf->pgid;
708   termios_printf ("cygheap->ctty %p, cygheap->ctty_on_hold %p", cygheap->ctty, cygheap->ctty_on_hold);
709   cygheap->console_count = vf->console_count;
710
711   if (vf->pid < 0)
712     {
713       int exitval = vf->exitval;
714       vf->pid = 0;
715       if ((vf->pid = fork ()) == 0)
716         exit (exitval);
717     }
718
719   int pid = vf->pid;
720   vf->pid = 0;
721   debug_printf ("exiting vfork, pid %d", pid);
722   sig_dispatch_pending ();
723
724   _my_tls.call_signal_handler ();       // FIXME: racy
725   _my_tls = vf->tls;
726   return pid;
727 #endif
728 }
729
730 /* Copy memory from one process to another. */
731
732 bool
733 child_copy (HANDLE hp, bool write, ...)
734 {
735   va_list args;
736   va_start (args, write);
737   static const char *huh[] = {"read", "write"};
738
739   char *what;
740   while ((what = va_arg (args, char *)))
741     {
742       char *low = va_arg (args, char *);
743       char *high = va_arg (args, char *);
744       DWORD todo = wincap.chunksize () ?: high - low;
745       char *here;
746
747       for (here = low; here < high; here += todo)
748         {
749           DWORD done = 0;
750           if (here + todo > high)
751             todo = high - here;
752           int res;
753           if (write)
754             res = WriteProcessMemory (hp, here, here, todo, &done);
755           else
756             res = ReadProcessMemory (hp, here, here, todo, &done);
757           debug_printf ("%s - hp %p low %p, high %p, res %d", what, hp, low, high, res);
758           if (!res || todo != done)
759             {
760               if (!res)
761                 __seterrno ();
762               /* If this happens then there is a bug in our fork
763                  implementation somewhere. */
764               system_printf ("%s %s copy failed, %p..%p, done %d, windows pid %u, %E",
765                             what, huh[write], low, high, done, myself->dwProcessId);
766               goto err;
767             }
768         }
769     }
770
771   va_end (args);
772   debug_printf ("done");
773   return true;
774
775  err:
776   va_end (args);
777   TerminateProcess (hp, 1);
778   set_errno (EAGAIN);
779   return false;
780 }