]> sourceware.org Git - newlib-cygwin.git/blob - winsup/cygwin/fork.cc
43a92738c47943afb0d72c08ed6c1fe3619802a3
[newlib-cygwin.git] / winsup / cygwin / fork.cc
1 /* fork.cc
2
3 This file is part of Cygwin.
4
5 This software is a copyrighted work licensed under the terms of the
6 Cygwin license. Please consult the file "CYGWIN_LICENSE" for
7 details. */
8
9 #include "winsup.h"
10 #include <stdio.h>
11 #include <unistd.h>
12 #include <stdlib.h>
13 #include "cygerrno.h"
14 #include "sigproc.h"
15 #include "pinfo.h"
16 #include "path.h"
17 #include "fhandler.h"
18 #include "dtable.h"
19 #include "cygheap.h"
20 #include "child_info.h"
21 #include "cygtls.h"
22 #include "tls_pbuf.h"
23 #include "shared_info.h"
24 #include "dll_init.h"
25 #include "cygmalloc.h"
26 #include "ntdll.h"
27
28 #define NPIDS_HELD 4
29
30 /* Timeout to wait for child to start, parent to init child, etc. */
31 /* FIXME: Once things stabilize, bump up to a few minutes. */
32 #define FORK_WAIT_TIMEOUT (300 * 1000) /* 300 seconds */
33
34 static int dofork (void **proc, bool *with_forkables);
35 class frok
36 {
37 frok (bool *forkables)
38 : with_forkables (forkables)
39 {}
40 bool *with_forkables;
41 bool load_dlls;
42 child_info_fork ch;
43 const char *errmsg;
44 int child_pid;
45 int this_errno;
46 HANDLE hchild;
47 int __stdcall parent (volatile char * volatile here);
48 int __stdcall child (volatile char * volatile here);
49 bool error (const char *fmt, ...);
50 friend int dofork (void **proc, bool *with_forkables);
51 };
52
53 static void
54 resume_child (HANDLE forker_finished)
55 {
56 SetEvent (forker_finished);
57 debug_printf ("signalled child");
58 return;
59 }
60
61 /* Notify parent that it is time for the next step. */
62 static void __stdcall
63 sync_with_parent (const char *s, bool hang_self)
64 {
65 debug_printf ("signalling parent: %s", s);
66 fork_info->ready (false);
67 if (hang_self)
68 {
69 HANDLE h = fork_info->forker_finished;
70 /* Wait for the parent to fill in our stack and heap.
71 Don't wait forever here. If our parent dies we don't want to clog
72 the system. If the wait fails, we really can't continue so exit. */
73 DWORD psync_rc = WaitForSingleObject (h, FORK_WAIT_TIMEOUT);
74 debug_printf ("awake");
75 switch (psync_rc)
76 {
77 case WAIT_TIMEOUT:
78 api_fatal ("WFSO timed out %s", s);
79 break;
80 case WAIT_FAILED:
81 if (GetLastError () == ERROR_INVALID_HANDLE &&
82 WaitForSingleObject (fork_info->forker_finished, 1) != WAIT_FAILED)
83 break;
84 api_fatal ("WFSO failed %s, fork_finished %p, %E", s,
85 fork_info->forker_finished);
86 break;
87 default:
88 debug_printf ("no problems");
89 break;
90 }
91 }
92 }
93
94 bool
95 frok::error (const char *fmt, ...)
96 {
97 DWORD exit_code = ch.exit_code;
98 if (!exit_code && hchild)
99 {
100 exit_code = ch.proc_retry (hchild);
101 if (!exit_code)
102 return false;
103 }
104 if (exit_code != EXITCODE_FORK_FAILED)
105 {
106 va_list ap;
107 static char buf[NT_MAX_PATH + 256];
108 va_start (ap, fmt);
109 __small_vsprintf (buf, fmt, ap);
110 errmsg = buf;
111 }
112 return true;
113 }
114
115 /* Set up a pipe which will track the life of a "pid" through
116 even after we've exec'ed. */
117 void
118 child_info::prefork (bool detached)
119 {
120 if (!detached)
121 {
122 if (!CreatePipe (&rd_proc_pipe, &wr_proc_pipe, &sec_none_nih, 16))
123 api_fatal ("prefork: couldn't create pipe process tracker, %E");
124
125 if (!SetHandleInformation (wr_proc_pipe, HANDLE_FLAG_INHERIT,
126 HANDLE_FLAG_INHERIT))
127 api_fatal ("prefork: couldn't set process pipe(%p) inherit state, %E",
128 wr_proc_pipe);
129 ProtectHandle1 (rd_proc_pipe, rd_proc_pipe);
130 ProtectHandle1 (wr_proc_pipe, wr_proc_pipe);
131 }
132 }
133
134 int __stdcall
135 frok::child (volatile char * volatile here)
136 {
137 HANDLE& hParent = ch.parent;
138
139 sync_with_parent ("after longjmp", true);
140 debug_printf ("child is running. pid %d, ppid %d, stack here %p",
141 myself->pid, myself->ppid, __builtin_frame_address (0));
142 sigproc_printf ("hParent %p, load_dlls %d", hParent, load_dlls);
143
144 /* Make sure threadinfo information is properly set up. */
145 if (&_my_tls != _main_tls)
146 {
147 _main_tls = &_my_tls;
148 _main_tls->init_thread (NULL, NULL);
149 }
150
151 set_cygwin_privileges (hProcToken);
152 clear_procimptoken ();
153 cygheap->user.reimpersonate ();
154
155 #ifdef DEBUGGING
156 if (GetEnvironmentVariableA ("FORKDEBUG", NULL, 0))
157 try_to_debug ();
158 char buf[80];
159 /* This is useful for debugging fork problems. Use gdb to attach to
160 the pid reported here. */
161 if (GetEnvironmentVariableA ("CYGWIN_FORK_SLEEP", buf, sizeof (buf)))
162 {
163 small_printf ("Sleeping %d after fork, pid %u\n", atoi (buf), GetCurrentProcessId ());
164 Sleep (atoi (buf));
165 }
166 #endif
167
168 /* Incredible but true: If we use sockets and SYSV IPC shared memory,
169 there's a good chance that a duplicated socket in the child occupies
170 memory which is needed to duplicate shared memory from the parent
171 process, if the shared memory hasn't been duplicated already.
172 The same goes very likely for "normal" mmap shared memory, too, but
173 with SYSV IPC it was the first time observed. So, *never* fixup
174 fdtab before fixing up shared memory. */
175 if (fixup_shms_after_fork ())
176 api_fatal ("recreate_shm areas after fork failed");
177
178 /* load dynamic dlls, if any, re-track main-executable and cygwin1.dll */
179 dlls.load_after_fork (hParent);
180
181 cygheap->fdtab.fixup_after_fork (hParent);
182
183 /* Signal that we have successfully initialized, so the parent can
184 - transfer data/bss for dynamically loaded dlls (if any), or
185 - terminate the current fork call even if the child is initialized. */
186 sync_with_parent ("performed fork fixups and dynamic dll loading", true);
187
188 ForceCloseHandle1 (fork_info->forker_finished, forker_finished);
189
190 pthread::atforkchild ();
191 cygbench ("fork-child");
192 ld_preload ();
193 fixup_hooks_after_fork ();
194 _my_tls.fixup_after_fork ();
195 /* Clear this or the destructor will close them. In the case of
196 rd_proc_pipe that would be an invalid handle. In the case of
197 wr_proc_pipe it would be == my_wr_proc_pipe. Both would be bad. */
198 ch.rd_proc_pipe = ch.wr_proc_pipe = NULL;
199 CloseHandle (hParent);
200 hParent = NULL;
201 cygwin_finished_initializing = true;
202 return 0;
203 }
204
205 int __stdcall
206 frok::parent (volatile char * volatile stack_here)
207 {
208 HANDLE forker_finished;
209 DWORD rc;
210 child_pid = -1;
211 this_errno = 0;
212 bool fix_impersonation = false;
213 pinfo child;
214
215 int c_flags = GetPriorityClass (GetCurrentProcess ());
216 debug_printf ("priority class %d", c_flags);
217 /* Per MSDN, this must be specified even if lpEnvironment is set to NULL,
218 otherwise UNICODE characters in the parent environment are not copied
219 correctly to the child. Omitting it may scramble %PATH% on non-English
220 systems. */
221 c_flags |= CREATE_UNICODE_ENVIRONMENT;
222
223 errmsg = NULL;
224 hchild = NULL;
225
226 /* If we don't have a console, then don't create a console for the
227 child either. */
228 HANDLE console_handle = CreateFile ("CONOUT$", GENERIC_WRITE,
229 FILE_SHARE_READ | FILE_SHARE_WRITE,
230 &sec_none_nih, OPEN_EXISTING,
231 FILE_ATTRIBUTE_NORMAL, NULL);
232
233 if (console_handle != INVALID_HANDLE_VALUE)
234 CloseHandle (console_handle);
235 else
236 c_flags |= DETACHED_PROCESS;
237
238 /* Some file types (currently only sockets) need extra effort in the
239 parent after CreateProcess and before copying the datastructures
240 to the child. So we have to start the child in suspend state,
241 unfortunately, to avoid a race condition. */
242 if (cygheap->fdtab.need_fixup_before ())
243 c_flags |= CREATE_SUSPENDED;
244
245 /* Remember if we need to load dynamically linked dlls.
246 We do this here so that this information will be available
247 in the parent and, when the stack is copied, in the child. */
248 load_dlls = dlls.reload_on_fork && dlls.loaded_dlls;
249
250 forker_finished = CreateEvent (&sec_all, FALSE, FALSE, NULL);
251 if (forker_finished == NULL)
252 {
253 this_errno = geterrno_from_win_error ();
254 error ("unable to allocate forker_finished event");
255 return -1;
256 }
257
258 ProtectHandleINH (forker_finished);
259
260 ch.forker_finished = forker_finished;
261
262 ch.stackbase = NtCurrentTeb ()->Tib.StackBase;
263 ch.stackaddr = NtCurrentTeb ()->DeallocationStack;
264 if (!ch.stackaddr)
265 {
266 /* If DeallocationStack is NULL, we're running on an application-provided
267 stack. If so, the entire stack is committed anyway and StackLimit
268 points to the allocation address of the stack. Mark in guardsize that
269 we must not set up guard pages. */
270 ch.stackaddr = ch.stacklimit = NtCurrentTeb ()->Tib.StackLimit;
271 ch.guardsize = (size_t) -1;
272 }
273 else
274 {
275 /* Otherwise we're running on a system-allocated stack. Since stack_here
276 is the address of the stack pointer we start the child with anyway, we
277 can set ch.stacklimit to this value rounded down to page size. The
278 child will not need the rest of the stack anyway. Guardsize depends
279 on whether we're running on a pthread or not. If pthread, we fetch
280 the guardpage size from the pthread attribs, otherwise we use the
281 system default. */
282 ch.stacklimit = (void *) ((uintptr_t) stack_here & ~(wincap.page_size () - 1));
283 ch.guardsize = (&_my_tls != _main_tls && _my_tls.tid)
284 ? _my_tls.tid->attr.guardsize
285 : wincap.def_guard_page_size ();
286 }
287 debug_printf ("stack - bottom %p, top %p, addr %p, guardsize %ly",
288 ch.stackbase, ch.stacklimit, ch.stackaddr, ch.guardsize);
289
290 PROCESS_INFORMATION pi;
291 STARTUPINFOW si;
292
293 memset (&si, 0, sizeof (si));
294 si.cb = sizeof si;
295
296 si.lpReserved2 = (LPBYTE) &ch;
297 si.cbReserved2 = sizeof (ch);
298
299 bool locked = __malloc_lock ();
300
301 /* Remove impersonation */
302 cygheap->user.deimpersonate ();
303 fix_impersonation = true;
304 ch.refresh_cygheap ();
305 ch.prefork (); /* set up process tracking pipes. */
306
307 *with_forkables = dlls.setup_forkables (*with_forkables);
308
309 ch.silentfail (!*with_forkables); /* fail silently without forkables */
310
311 tmp_pathbuf tp;
312 PSECURITY_ATTRIBUTES sa = (PSECURITY_ATTRIBUTES) tp.w_get ();
313 if (!sec_user_nih (sa, cygheap->user.saved_sid (),
314 well_known_authenticated_users_sid,
315 PROCESS_QUERY_LIMITED_INFORMATION))
316 sa = &sec_none_nih;
317
318 while (1)
319 {
320 PCWCHAR forking_progname = NULL;
321 if (dlls.main_executable)
322 forking_progname = dll_list::buffered_shortname
323 (dlls.main_executable->forkedntname ());
324 if (!forking_progname || !*forking_progname)
325 forking_progname = myself->progname;
326
327 syscall_printf ("CreateProcessW (%W, %W, 0, 0, 1, %y, 0, 0, %p, %p)",
328 forking_progname, myself->progname, c_flags, &si, &pi);
329
330 hchild = NULL;
331 /* cygwin1.dll may reuse the forking_progname buffer, even
332 in case of failure: don't reuse forking_progname later */
333 rc = CreateProcessW (forking_progname, /* image to run */
334 GetCommandLineW (), /* Take same space for command
335 line as in parent to make
336 sure child stack is allocated
337 in the same memory location
338 as in parent. */
339 sa,
340 sa,
341 TRUE, /* inherit handles */
342 c_flags,
343 NULL, /* environ filled in later */
344 0, /* use cwd */
345 &si,
346 &pi);
347
348 if (rc)
349 debug_printf ("forked pid %u", pi.dwProcessId);
350 else
351 {
352 this_errno = geterrno_from_win_error ();
353 error ("CreateProcessW failed for '%W'", myself->progname);
354 dlls.release_forkables ();
355 memset (&pi, 0, sizeof (pi));
356 goto cleanup;
357 }
358
359 if (cygheap->fdtab.need_fixup_before ())
360 {
361 cygheap->fdtab.fixup_before_fork (pi.dwProcessId);
362 ResumeThread (pi.hThread);
363 }
364
365 CloseHandle (pi.hThread);
366 hchild = pi.hProcess;
367
368 dlls.release_forkables ();
369
370 /* Protect the handle but name it similarly to the way it will
371 be called in subproc handling. */
372 ProtectHandle1 (hchild, childhProc);
373
374 strace.write_childpid (pi.dwProcessId);
375
376 /* Wait for subproc to initialize itself. */
377 if (!ch.sync (pi.dwProcessId, hchild, FORK_WAIT_TIMEOUT))
378 {
379 if (!error ("forked process %u died unexpectedly, retry %d, exit code %y",
380 pi.dwProcessId, ch.retry, ch.exit_code))
381 continue;
382 this_errno = EAGAIN;
383 goto cleanup;
384 }
385 break;
386 }
387
388 /* Restore impersonation */
389 cygheap->user.reimpersonate ();
390 fix_impersonation = false;
391
392 child_pid = cygwin_pid (pi.dwProcessId);
393 child.init (child_pid, PID_IN_USE | PID_NEW, NULL);
394
395 if (!child)
396 {
397 this_errno = get_errno () == ENOMEM ? ENOMEM : EAGAIN;
398 syscall_printf ("pinfo failed");
399 goto cleanup;
400 }
401
402 child->nice = myself->nice;
403
404 /* Initialize things that are done later in dll_crt0_1 that aren't done
405 for the forkee. */
406 wcscpy (child->progname, myself->progname);
407
408 /* Fill in fields in the child's process table entry. */
409 child->dwProcessId = pi.dwProcessId;
410 child.hProcess = hchild;
411 ch.postfork (child);
412
413 /* Hopefully, this will succeed. The alternative to doing things this
414 way is to reserve space prior to calling CreateProcess and then fill
415 it in afterwards. This requires more bookkeeping than I like, though,
416 so we'll just do it the easy way. So, terminate any child process if
417 we can't actually record the pid in the internal table. */
418 if (!child.remember (false))
419 {
420 this_errno = EAGAIN;
421 #ifdef DEBUGGING0
422 error ("child remember failed");
423 #endif
424 goto cleanup;
425 }
426
427 /* CHILD IS STOPPED */
428 debug_printf ("child is alive (but stopped)");
429
430
431 /* Initialize, in order: stack, dll data, dll bss.
432 data, bss, heap were done earlier (in dcrt0.cc)
433 Note: variables marked as NO_COPY will not be copied since they are
434 placed in a protected segment. */
435
436 const void *impure_beg;
437 const void *impure_end;
438 const char *impure;
439 if (&_my_tls == _main_tls)
440 impure_beg = impure_end = impure = NULL;
441 else
442 {
443 impure = "impure";
444 impure_beg = _impure_ptr;
445 impure_end = _impure_ptr + 1;
446 }
447 rc = child_copy (hchild, true, !*with_forkables,
448 "stack", stack_here, ch.stackbase,
449 impure, impure_beg, impure_end,
450 NULL);
451
452 __malloc_unlock ();
453 locked = false;
454 if (!rc)
455 {
456 this_errno = get_errno ();
457 error ("pid %u, exitval %p", pi.dwProcessId, ch.exit_code);
458 goto cleanup;
459 }
460
461 /* Now fill data/bss of any DLLs that were linked into the program. */
462 for (dll *d = dlls.istart (DLL_LINK); d; d = dlls.inext ())
463 {
464 debug_printf ("copying data/bss of a linked dll");
465 if (!child_copy (hchild, true, !*with_forkables,
466 "linked dll data", d->p.data_start, d->p.data_end,
467 "linked dll bss", d->p.bss_start, d->p.bss_end,
468 NULL))
469 {
470 this_errno = get_errno ();
471 error ("couldn't copy linked dll data/bss");
472 goto cleanup;
473 }
474 }
475
476 /* Start the child up, and then wait for it to
477 perform fork fixups and dynamic dll loading (if any). */
478 resume_child (forker_finished);
479 if (!ch.sync (child->pid, hchild, FORK_WAIT_TIMEOUT))
480 {
481 this_errno = EAGAIN;
482 error ("died waiting for dll loading");
483 goto cleanup;
484 }
485
486 /* If DLLs were loaded in the parent, then the child has reloaded all
487 of them and is now waiting to have all of the individual data and
488 bss sections filled in. */
489 if (load_dlls)
490 {
491 /* CHILD IS STOPPED */
492 /* write memory of reloaded dlls */
493 for (dll *d = dlls.istart (DLL_LOAD); d; d = dlls.inext ())
494 {
495 debug_printf ("copying data/bss for a loaded dll");
496 if (!child_copy (hchild, true, !*with_forkables,
497 "loaded dll data", d->p.data_start, d->p.data_end,
498 "loaded dll bss", d->p.bss_start, d->p.bss_end,
499 NULL))
500 {
501 this_errno = get_errno ();
502 #ifdef DEBUGGING
503 error ("copying data/bss for a loaded dll");
504 #endif
505 goto cleanup;
506 }
507 }
508 }
509
510 /* Do not attach to the child before it has successfully initialized.
511 Otherwise we may wait forever, or deliver an orphan SIGCHILD. */
512 if (!child.attach ())
513 {
514 this_errno = EAGAIN;
515 #ifdef DEBUGGING0
516 error ("child attach failed");
517 #endif
518 goto cleanup;
519 }
520
521 /* Finally start the child up. */
522 resume_child (forker_finished);
523
524 ForceCloseHandle (forker_finished);
525 forker_finished = NULL;
526
527 return child_pid;
528
529 /* Common cleanup code for failure cases */
530 cleanup:
531 /* release procinfo before hProcess in destructor */
532 child.allow_remove ();
533
534 if (fix_impersonation)
535 cygheap->user.reimpersonate ();
536 if (locked)
537 __malloc_unlock ();
538
539 /* Remember to de-allocate the fd table. */
540 if (hchild)
541 {
542 TerminateProcess (hchild, 1);
543 if (!child.hProcess) /* no child.procinfo */
544 ForceCloseHandle1 (hchild, childhProc);
545 }
546 if (forker_finished)
547 ForceCloseHandle (forker_finished);
548 debug_printf ("returning -1");
549 return -1;
550 }
551
552 extern "C" int
553 fork ()
554 {
555 bool with_forkables = false; /* do not force hardlinks on first try */
556 int res = dofork (NULL, &with_forkables);
557 if (res >= 0)
558 return res;
559 if (with_forkables)
560 return res; /* no need for second try when already enabled */
561 with_forkables = true; /* enable hardlinks for second try */
562 return dofork (NULL, &with_forkables);
563 }
564
565
566 /* __posix_spawn_fork is called from newlib's posix_spawn implementation.
567 The original code in newlib has been taken from FreeBSD, and the core
568 code relies on specific, non-portable behaviour of vfork(2). Our
569 replacement implementation needs the forked child's HANDLE for
570 synchronization, so __posix_spawn_fork returns it in proc. */
571 extern "C" int
572 __posix_spawn_fork (void **proc)
573 {
574 bool with_forkables = false; /* do not force hardlinks on first try */
575 int res = dofork (proc, &with_forkables);
576 if (res >= 0)
577 return res;
578 if (with_forkables)
579 return res; /* no need for second try when already enabled */
580 with_forkables = true; /* enable hardlinks for second try */
581 return dofork (proc, &with_forkables);
582 }
583
584 static int
585 dofork (void **proc, bool *with_forkables)
586 {
587 frok grouped (with_forkables);
588
589 debug_printf ("entering");
590 grouped.load_dlls = 0;
591
592 int res;
593 bool ischild = false;
594
595 myself->set_has_pgid_children ();
596
597 if (grouped.ch.parent == NULL)
598 return -1;
599 if (grouped.ch.subproc_ready == NULL)
600 {
601 system_printf ("unable to allocate subproc_ready event, %E");
602 return -1;
603 }
604
605 {
606 hold_everything held_everything (ischild);
607 /* This tmp_pathbuf constructor is required here because the below setjmp
608 magic will otherwise not restore the original buffer count values in
609 the thread-local storage. A process forking too deeply will run into
610 the problem to be out of temporary TLS path buffers. */
611 tmp_pathbuf tp;
612
613 if (!held_everything)
614 {
615 if (exit_state)
616 Sleep (INFINITE);
617 set_errno (EAGAIN);
618 return -1;
619 }
620
621 /* Put the dll list in topological dependency ordering, in
622 hopes that the child will have a better shot at loading dlls
623 properly if it only has to deal with one at a time. */
624 dlls.topsort ();
625
626 ischild = !!setjmp (grouped.ch.jmp);
627
628 volatile char * volatile stackp;
629 #ifdef __x86_64__
630 __asm__ volatile ("movq %%rsp,%0": "=r" (stackp));
631 #else
632 __asm__ volatile ("movl %%esp,%0": "=r" (stackp));
633 #endif
634
635 if (!ischild)
636 res = grouped.parent (stackp);
637 else
638 {
639 res = grouped.child (stackp);
640 in_forkee = false;
641 ischild = true; /* might have been reset by fork mem copy */
642 }
643 }
644
645 if (ischild)
646 {
647 myself->process_state |= PID_ACTIVE;
648 myself->process_state &= ~(PID_INITIALIZING | PID_EXITED | PID_REAPED);
649 }
650 else if (res < 0)
651 {
652 if (!grouped.errmsg)
653 syscall_printf ("fork failed - child pid %d, errno %d", grouped.child_pid, grouped.this_errno);
654 else if (grouped.ch.silentfail ())
655 debug_printf ("child %d - %s, errno %d", grouped.child_pid,
656 grouped.errmsg, grouped.this_errno);
657 else
658 system_printf ("child %d - %s, errno %d", grouped.child_pid,
659 grouped.errmsg, grouped.this_errno);
660
661 set_errno (grouped.this_errno);
662 }
663 else if (proc)
664 {
665 /* Return child process handle to posix_fork. */
666 *proc = grouped.hchild;
667 }
668 syscall_printf ("%R = fork()", res);
669 return res;
670 }
671 #ifdef DEBUGGING
672 void
673 fork_init ()
674 {
675 }
676 #endif /*DEBUGGING*/
677
678
679 extern "C" int
680 vfork ()
681 {
682 debug_printf ("stub called");
683 return fork ();
684 }
685
686 /* Copy memory from one process to another. */
687
688 bool
689 child_copy (HANDLE hp, bool write, bool silentfail, ...)
690 {
691 va_list args;
692 va_start (args, silentfail);
693 static const char *huh[] = {"read", "write"};
694
695 char *what;
696 while ((what = va_arg (args, char *)))
697 {
698 char *low = va_arg (args, char *);
699 char *high = va_arg (args, char *);
700 SIZE_T todo = high - low;
701 char *here;
702
703 for (here = low; here < high; here += todo)
704 {
705 SIZE_T done = 0;
706 if (here + todo > high)
707 todo = high - here;
708 BOOL res;
709 if (write)
710 res = WriteProcessMemory (hp, here, here, todo, &done);
711 else
712 res = ReadProcessMemory (hp, here, here, todo, &done);
713 debug_printf ("%s - hp %p low %p, high %p, res %d", what, hp, low, high, res);
714 if (!res || todo != done)
715 {
716 if (!res)
717 __seterrno ();
718 if (silentfail)
719 debug_printf ("%s %s copy failed, %p..%p, done %lu, windows pid %u, %E",
720 what, huh[write], low, high, done, myself->dwProcessId);
721 else
722 /* If this happens then there is a bug in our fork
723 implementation somewhere. */
724 system_printf ("%s %s copy failed, %p..%p, done %lu, windows pid %u, %E",
725 what, huh[write], low, high, done, myself->dwProcessId);
726 goto err;
727 }
728 }
729 }
730
731 va_end (args);
732 debug_printf ("done");
733 return true;
734
735 err:
736 va_end (args);
737 TerminateProcess (hp, 1);
738 set_errno (EAGAIN);
739 return false;
740 }
This page took 0.066244 seconds and 4 git commands to generate.