OSDN Git Service

* environ.cc (regopt): Change the first argument to wide char string.
[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[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 ("CreateProcess (%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           error = "CreateProcessW failed";
371           memset (&pi, 0, sizeof (pi));
372           goto cleanup;
373         }
374
375       if (cygheap->fdtab.need_fixup_before ())
376         {
377           cygheap->fdtab.fixup_before_fork (pi.dwProcessId);
378           ResumeThread (pi.hThread);
379         }
380
381       CloseHandle (pi.hThread);
382
383       /* Protect the handle but name it similarly to the way it will
384          be called in subproc handling. */
385       ProtectHandle1 (pi.hProcess, childhProc);
386
387       strace.write_childpid (ch, pi.dwProcessId);
388
389       /* Wait for subproc to initialize itself. */
390       if (!ch.sync (pi.dwProcessId, pi.hProcess, FORK_WAIT_TIMEOUT))
391         {
392           DWORD exit_code = ch.proc_retry (pi.hProcess);
393           if (!exit_code)
394             continue;
395           this_errno = EAGAIN;
396           /* Not thread safe, but do we care? */
397           __small_sprintf (errbuf, "died waiting for longjmp before initialization, "
398                            "retry %d, exit code %p", ch.retry, exit_code);
399           error = errbuf;
400           goto cleanup;
401         }
402       break;
403     }
404
405   /* Restore impersonation */
406   cygheap->user.reimpersonate ();
407   fix_impersonation = false;
408
409   child_pid = cygwin_pid (pi.dwProcessId);
410   child.init (child_pid, 1, NULL);
411
412   if (!child)
413     {
414       this_errno = get_errno () == ENOMEM ? ENOMEM : EAGAIN;
415 #ifdef DEBUGGING
416       error = "pinfo failed";
417 #else
418       syscall_printf ("pinfo failed");
419 #endif
420       goto cleanup;
421     }
422
423   child->start_time = start_time; /* Register child's starting time. */
424   child->nice = myself->nice;
425
426   /* Initialize things that are done later in dll_crt0_1 that aren't done
427      for the forkee.  */
428   wcscpy (child->progname, myself->progname);
429
430   /* Fill in fields in the child's process table entry.  */
431   child->dwProcessId = pi.dwProcessId;
432   child.hProcess = pi.hProcess;
433
434   /* Hopefully, this will succeed.  The alternative to doing things this
435      way is to reserve space prior to calling CreateProcess and then fill
436      it in afterwards.  This requires more bookkeeping than I like, though,
437      so we'll just do it the easy way.  So, terminate any child process if
438      we can't actually record the pid in the internal table. */
439   if (!child.remember (false))
440     {
441       TerminateProcess (pi.hProcess, 1);
442       this_errno = EAGAIN;
443 #ifdef DEBUGGING0
444       error = "child.remember failed";
445 #endif
446       goto cleanup;
447     }
448
449 #ifndef NO_SLOW_PID_REUSE
450   slow_pid_reuse (pi.hProcess);
451 #endif
452
453   /* CHILD IS STOPPED */
454   debug_printf ("child is alive (but stopped)");
455
456   /* Initialize, in order: stack, dll data, dll bss.
457      data, bss, heap were done earlier (in dcrt0.cc)
458      Note: variables marked as NO_COPY will not be copied since they are
459      placed in a protected segment.  */
460
461   MALLOC_CHECK;
462   const void *impure_beg;
463   const void *impure_end;
464   const char *impure;
465   if (&_my_tls == _main_tls)
466     impure_beg = impure_end = impure = NULL;
467   else
468     {
469       impure = "impure";
470       impure_beg = _impure_ptr;
471       impure_end = _impure_ptr + 1;
472     }
473   rc = child_copy (pi.hProcess, true,
474                    "stack", stack_here, ch.stackbottom,
475                    impure, impure_beg, impure_end,
476                    NULL);
477
478   __malloc_unlock ();
479   locked = false;
480   MALLOC_CHECK;
481   if (!rc)
482     {
483       this_errno = get_errno ();
484       DWORD exit_code;
485       if (!GetExitCodeProcess (pi.hProcess, &exit_code))
486         exit_code = 0xdeadbeef;
487       __small_sprintf (errbuf, "pid %u, exitval %p", pi.dwProcessId, exit_code);
488       error = errbuf;
489       goto cleanup;
490     }
491
492   /* Now fill data/bss of any DLLs that were linked into the program. */
493   for (dll *d = dlls.istart (DLL_LINK); d; d = dlls.inext ())
494     {
495       debug_printf ("copying data/bss of a linked dll");
496       if (!child_copy (pi.hProcess, true,
497                        "linked dll data", d->p.data_start, d->p.data_end,
498                        "linked dll bss", d->p.bss_start, d->p.bss_end,
499                        NULL))
500         {
501           this_errno = get_errno ();
502 #ifdef DEBUGGING
503           DWORD exit_code;
504           if (!GetExitCodeProcess (pi.hProcess, &exit_code))
505             exit_code = 0xdeadbeef;
506           __small_sprintf (errbuf, "pid %u, exitval %p", pi.dwProcessId, exit_code);
507           error = errbuf;
508 #endif
509           goto cleanup;
510         }
511     }
512
513   /* Start thread, and then wait for it to reload dlls.  */
514   resume_child (forker_finished);
515   if (!ch.sync (child->pid, pi.hProcess, FORK_WAIT_TIMEOUT))
516     {
517       this_errno = EAGAIN;
518       error = "died waiting for dll loading";
519       goto cleanup;
520     }
521
522   /* If DLLs were loaded in the parent, then the child has reloaded all
523      of them and is now waiting to have all of the individual data and
524      bss sections filled in. */
525   if (load_dlls)
526     {
527       /* CHILD IS STOPPED */
528       /* write memory of reloaded dlls */
529       for (dll *d = dlls.istart (DLL_LOAD); d; d = dlls.inext ())
530         {
531           debug_printf ("copying data/bss for a loaded dll");
532           if (!child_copy (pi.hProcess, true,
533                            "loaded dll data", d->p.data_start, d->p.data_end,
534                            "loaded dll bss", d->p.bss_start, d->p.bss_end,
535                            NULL))
536             {
537               this_errno = get_errno ();
538 #ifdef DEBUGGING
539               error = "copying data/bss for a loaded dll";
540 #endif
541               goto cleanup;
542             }
543         }
544       /* Start the child up again. */
545       resume_child (forker_finished);
546     }
547
548   ForceCloseHandle (forker_finished);
549   forker_finished = NULL;
550
551   return child_pid;
552
553 /* Common cleanup code for failure cases */
554 cleanup:
555   if (fix_impersonation)
556     cygheap->user.reimpersonate ();
557   if (locked)
558     __malloc_unlock ();
559
560   /* Remember to de-allocate the fd table. */
561   if (pi.hProcess && !child.hProcess)
562     ForceCloseHandle1 (pi.hProcess, childhProc);
563   if (forker_finished)
564     ForceCloseHandle (forker_finished);
565   debug_printf ("returning -1");
566   return -1;
567 }
568
569 extern "C" int
570 fork ()
571 {
572   frok grouped;
573
574   debug_printf ("entering");
575   grouped.load_dlls = 0;
576
577   int res;
578   bool ischild = false;
579
580   myself->set_has_pgid_children ();
581
582   if (grouped.ch.parent == NULL)
583     return -1;
584   if (grouped.ch.subproc_ready == NULL)
585     {
586       system_printf ("unable to allocate subproc_ready event, %E");
587       return -1;
588     }
589
590   {
591     hold_everything held_everything (ischild);
592     /* This tmp_pathbuf constructor is required here because the below setjmp
593        magic will otherwise not restore the original buffer count values in
594        the thread-local storage.  A process forking too deeply will run into
595        the problem to be out of temporary TLS path buffers. */
596     tmp_pathbuf tp;
597
598     if (!held_everything)
599       {
600         if (exit_state)
601           Sleep (INFINITE);
602         set_errno (EAGAIN);
603         return -1;
604       }
605
606     ischild = !!setjmp (grouped.ch.jmp);
607
608     volatile char * volatile esp;
609     __asm__ volatile ("movl %%esp,%0": "=r" (esp));
610
611     if (!ischild)
612       res = grouped.parent (esp);
613     else
614       {
615         res = grouped.child (esp);
616         ischild = true; /* might have been reset by fork mem copy */
617       }
618   }
619
620   MALLOC_CHECK;
621   if (ischild || res > 0)
622     /* everything is ok */;
623   else
624     {
625       if (!grouped.error)
626         syscall_printf ("fork failed - child pid %d, errno %d", grouped.child_pid, grouped.this_errno);
627       else
628         {
629           char buf[strlen (grouped.error) + sizeof ("child %d - , errno 4294967295  ")];
630           strcpy (buf, "child %d - ");
631           strcat (buf, grouped.error);
632           strcat (buf, ", errno %d");
633           system_printf (buf, grouped.child_pid, grouped.this_errno);
634         }
635
636       set_errno (grouped.this_errno);
637     }
638   syscall_printf ("%d = fork()", res);
639   return res;
640 }
641 #ifdef DEBUGGING
642 void
643 fork_init ()
644 {
645 }
646 #endif /*DEBUGGING*/
647
648 #ifdef NEWVFORK
649 /* Dummy function to force second assignment below to actually be
650    carried out */
651 static vfork_save *
652 get_vfork_val ()
653 {
654   return vfork_storage.val ();
655 }
656 #endif
657
658 extern "C" int
659 vfork ()
660 {
661 #ifndef NEWVFORK
662   debug_printf ("stub called");
663   return fork ();
664 #else
665   vfork_save *vf = get_vfork_val ();
666   char **esp, **pp;
667
668   if (vf == NULL)
669     vf = vfork_storage.create ();
670   else if (vf->pid)
671     return fork ();
672
673   // FIXME the tls stuff could introduce a signal race if a child process
674   // exits quickly.
675   if (!setjmp (vf->j))
676     {
677       vf->pid = -1;
678       __asm__ volatile ("movl %%esp,%0": "=r" (vf->vfork_esp):);
679       __asm__ volatile ("movl %%ebp,%0": "=r" (vf->vfork_ebp):);
680       for (pp = (char **) vf->frame, esp = vf->vfork_esp;
681            esp <= vf->vfork_ebp + 2; pp++, esp++)
682         *pp = *esp;
683       vf->ctty = myself->ctty;
684       vf->sid = myself->sid;
685       vf->pgid = myself->pgid;
686       cygheap->ctty_on_hold = cygheap->ctty;
687       vf->console_count = cygheap->console_count;
688       debug_printf ("cygheap->ctty_on_hold %p, cygheap->console_count %d", cygheap->ctty_on_hold, cygheap->console_count);
689       int res = cygheap->fdtab.vfork_child_dup () ? 0 : -1;
690       debug_printf ("%d = vfork()", res);
691       _my_tls.call_signal_handler ();   // FIXME: racy
692       vf->tls = _my_tls;
693       return res;
694     }
695
696   vf = get_vfork_val ();
697
698   for (pp = (char **) vf->frame, esp = vf->vfork_esp;
699        esp <= vf->vfork_ebp + 2; pp++, esp++)
700     *esp = *pp;
701
702   cygheap->fdtab.vfork_parent_restore ();
703
704   myself->ctty = vf->ctty;
705   myself->sid = vf->sid;
706   myself->pgid = vf->pgid;
707   termios_printf ("cygheap->ctty %p, cygheap->ctty_on_hold %p", cygheap->ctty, cygheap->ctty_on_hold);
708   cygheap->console_count = vf->console_count;
709
710   if (vf->pid < 0)
711     {
712       int exitval = vf->exitval;
713       vf->pid = 0;
714       if ((vf->pid = fork ()) == 0)
715         exit (exitval);
716     }
717
718   int pid = vf->pid;
719   vf->pid = 0;
720   debug_printf ("exiting vfork, pid %d", pid);
721   sig_dispatch_pending ();
722
723   _my_tls.call_signal_handler ();       // FIXME: racy
724   _my_tls = vf->tls;
725   return pid;
726 #endif
727 }
728
729 /* Copy memory from one process to another. */
730
731 bool
732 child_copy (HANDLE hp, bool write, ...)
733 {
734   va_list args;
735   va_start (args, write);
736   static const char *huh[] = {"read", "write"};
737
738   char *what;
739   while ((what = va_arg (args, char *)))
740     {
741       char *low = va_arg (args, char *);
742       char *high = va_arg (args, char *);
743       DWORD todo = wincap.chunksize () ?: high - low;
744       char *here;
745
746       for (here = low; here < high; here += todo)
747         {
748           DWORD done = 0;
749           if (here + todo > high)
750             todo = high - here;
751           int res;
752           if (write)
753             res = WriteProcessMemory (hp, here, here, todo, &done);
754           else
755             res = ReadProcessMemory (hp, here, here, todo, &done);
756           debug_printf ("%s - hp %p low %p, high %p, res %d", what, hp, low, high, res);
757           if (!res || todo != done)
758             {
759               if (!res)
760                 __seterrno ();
761               /* If this happens then there is a bug in our fork
762                  implementation somewhere. */
763               system_printf ("%s %s copy failed, %p..%p, done %d, windows pid %u, %E",
764                             what, huh[write], low, high, done, myself->dwProcessId);
765               goto err;
766             }
767         }
768     }
769
770   va_end (args);
771   debug_printf ("done");
772   return true;
773
774  err:
775   va_end (args);
776   TerminateProcess (hp, 1);
777   set_errno (EAGAIN);
778   return false;
779 }