]>
Commit | Line | Data |
---|---|---|
1fd5e000 CF |
1 | /* fork.cc |
2 | ||
bc837d22 | 3 | Copyright 1996, 1997, 1998, 1999, 2000, 2001, 2002, 2003, 2004, 2005, 2006, |
3c53eaeb | 4 | 2007, 2008, 2009, 2010, 2011, 2012 Red Hat, Inc. |
1fd5e000 CF |
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 | ||
4c8d72de | 12 | #include "winsup.h" |
1fd5e000 CF |
13 | #include <stdio.h> |
14 | #include <unistd.h> | |
15 | #include <stdlib.h> | |
169c465a | 16 | #include "cygerrno.h" |
0e1f0840 CF |
17 | #include "sigproc.h" |
18 | #include "pinfo.h" | |
47063f00 | 19 | #include "path.h" |
7ac61736 | 20 | #include "fhandler.h" |
e2ebe117 | 21 | #include "dtable.h" |
b0e82b74 | 22 | #include "cygheap.h" |
488c7683 | 23 | #include "child_info.h" |
8cb359d9 | 24 | #include "cygtls.h" |
752b16ce | 25 | #include "tls_pbuf.h" |
f0338f54 | 26 | #include "dll_init.h" |
c7e2187a | 27 | #include "cygmalloc.h" |
89d3c72d | 28 | #include "ntdll.h" |
1fd5e000 | 29 | |
22cf17b3 | 30 | #define NPIDS_HELD 4 |
a9f36d28 | 31 | |
1fd5e000 CF |
32 | /* Timeout to wait for child to start, parent to init child, etc. */ |
33 | /* FIXME: Once things stabilize, bump up to a few minutes. */ | |
34 | #define FORK_WAIT_TIMEOUT (300 * 1000) /* 300 seconds */ | |
35 | ||
280fdd0b CF |
36 | class frok |
37 | { | |
280fdd0b CF |
38 | bool load_dlls; |
39 | child_info_fork ch; | |
85510878 | 40 | const char *errmsg; |
280fdd0b CF |
41 | int child_pid; |
42 | int this_errno; | |
85510878 | 43 | HANDLE hchild; |
39fc0d36 CF |
44 | int __stdcall parent (volatile char * volatile here); |
45 | int __stdcall child (volatile char * volatile here); | |
85510878 | 46 | bool error (const char *fmt, ...); |
280fdd0b CF |
47 | friend int fork (); |
48 | }; | |
49 | ||
bbca1e4c | 50 | static void |
54dd79bb | 51 | resume_child (HANDLE forker_finished) |
1fd5e000 | 52 | { |
1fd5e000 | 53 | SetEvent (forker_finished); |
1ec4f618 | 54 | debug_printf ("signalled child"); |
bbca1e4c | 55 | return; |
1fd5e000 CF |
56 | } |
57 | ||
3178cfff | 58 | /* Notify parent that it is time for the next step. */ |
1ec4f618 | 59 | static void __stdcall |
c90e1cf1 | 60 | sync_with_parent (const char *s, bool hang_self) |
1fd5e000 | 61 | { |
1ec4f618 | 62 | debug_printf ("signalling parent: %s", s); |
54dd79bb | 63 | fork_info->ready (false); |
1ec4f618 CF |
64 | if (hang_self) |
65 | { | |
6ea3e429 | 66 | HANDLE h = fork_info->forker_finished; |
1ec4f618 CF |
67 | /* Wait for the parent to fill in our stack and heap. |
68 | Don't wait forever here. If our parent dies we don't want to clog | |
69 | the system. If the wait fails, we really can't continue so exit. */ | |
70 | DWORD psync_rc = WaitForSingleObject (h, FORK_WAIT_TIMEOUT); | |
71 | debug_printf ("awake"); | |
72 | switch (psync_rc) | |
73 | { | |
74 | case WAIT_TIMEOUT: | |
e431827c | 75 | api_fatal ("WFSO timed out %s", s); |
1ec4f618 CF |
76 | break; |
77 | case WAIT_FAILED: | |
78 | if (GetLastError () == ERROR_INVALID_HANDLE && | |
6ea3e429 | 79 | WaitForSingleObject (fork_info->forker_finished, 1) != WAIT_FAILED) |
1ec4f618 | 80 | break; |
e431827c | 81 | api_fatal ("WFSO failed %s, fork_finished %p, %E", s, |
6ea3e429 | 82 | fork_info->forker_finished); |
1ec4f618 CF |
83 | break; |
84 | default: | |
85 | debug_printf ("no problems"); | |
86 | break; | |
87 | } | |
88 | } | |
1fd5e000 CF |
89 | } |
90 | ||
85510878 CF |
91 | bool |
92 | frok::error (const char *fmt, ...) | |
93 | { | |
94 | DWORD exit_code = ch.exit_code; | |
95 | if (!exit_code && hchild) | |
96 | { | |
97 | exit_code = ch.proc_retry (hchild); | |
98 | if (!exit_code) | |
99 | return false; | |
100 | } | |
101 | if (exit_code != EXITCODE_FORK_FAILED) | |
102 | { | |
103 | va_list ap; | |
104 | static char buf[NT_MAX_PATH + 256]; | |
105 | va_start (ap, fmt); | |
106 | __small_vsprintf (buf, fmt, ap); | |
107 | errmsg = buf; | |
108 | } | |
109 | return true; | |
110 | } | |
111 | ||
1fb6667f CF |
112 | /* Set up a pipe which will track the life of a "pid" through |
113 | even after we've exec'ed. */ | |
114 | void | |
115 | child_info::prefork (bool detached) | |
116 | { | |
117 | if (!detached) | |
118 | { | |
119 | if (!CreatePipe (&rd_proc_pipe, &wr_proc_pipe, &sec_none_nih, 16)) | |
81f18683 | 120 | api_fatal ("prefork: couldn't create pipe process tracker, %E"); |
1fb6667f CF |
121 | |
122 | if (!SetHandleInformation (wr_proc_pipe, HANDLE_FLAG_INHERIT, | |
123 | HANDLE_FLAG_INHERIT)) | |
124 | api_fatal ("prefork: couldn't set process pipe(%p) inherit state, %E", | |
125 | wr_proc_pipe); | |
126 | ProtectHandle1 (rd_proc_pipe, rd_proc_pipe); | |
127 | ProtectHandle1 (wr_proc_pipe, wr_proc_pipe); | |
128 | } | |
129 | } | |
130 | ||
280fdd0b | 131 | int __stdcall |
39fc0d36 | 132 | frok::child (volatile char * volatile here) |
1fd5e000 | 133 | { |
280fdd0b | 134 | HANDLE& hParent = ch.parent; |
b1d9a0bd | 135 | extern void fixup_hooks_after_fork (); |
f6936c48 | 136 | extern void fixup_timers_after_fork (); |
1ec4f618 | 137 | |
6642f7da CF |
138 | /* NOTE: Logically this belongs in dll_list::load_after_fork, but by |
139 | doing it here, before the first sync_with_parent, we can exploit | |
140 | the existing retry mechanism in hopes of getting a more favorable | |
141 | address space layout next time. */ | |
142 | dlls.reserve_space (); | |
143 | ||
2e008fb9 | 144 | sync_with_parent ("after longjmp", true); |
ef8bff85 CF |
145 | debug_printf ("child is running. pid %d, ppid %d, stack here %p", |
146 | myself->pid, myself->ppid, __builtin_frame_address (0)); | |
71f53a2f | 147 | sigproc_printf ("hParent %p, load_dlls %d", hParent, load_dlls); |
1fd5e000 | 148 | |
e431827c CF |
149 | /* If we've played with the stack, stacksize != 0. That means that |
150 | fork() was invoked from other than the main thread. Make sure that | |
151 | the threadinfo information is properly set up. */ | |
89d3c72d | 152 | if (fork_info->stackaddr) |
e431827c CF |
153 | { |
154 | _main_tls = &_my_tls; | |
155 | _main_tls->init_thread (NULL, NULL); | |
156 | _main_tls->local_clib = *_impure_ptr; | |
157 | _impure_ptr = &_main_tls->local_clib; | |
158 | } | |
159 | ||
a76877e9 CV |
160 | set_cygwin_privileges (hProcToken); |
161 | clear_procimptoken (); | |
162 | cygheap->user.reimpersonate (); | |
f4a1f8a1 | 163 | |
1ec4f618 | 164 | #ifdef DEBUGGING |
5ab0b5cf | 165 | if (GetEnvironmentVariableA ("FORKDEBUG", NULL, 0)) |
1ec4f618 CF |
166 | try_to_debug (); |
167 | char buf[80]; | |
168 | /* This is useful for debugging fork problems. Use gdb to attach to | |
169 | the pid reported here. */ | |
5ab0b5cf | 170 | if (GetEnvironmentVariableA ("CYGWIN_FORK_SLEEP", buf, sizeof (buf))) |
1ec4f618 CF |
171 | { |
172 | small_printf ("Sleeping %d after fork, pid %u\n", atoi (buf), GetCurrentProcessId ()); | |
c90e1cf1 | 173 | Sleep (atoi (buf)); |
1ec4f618 CF |
174 | } |
175 | #endif | |
1fd5e000 | 176 | |
1ec4f618 | 177 | MALLOC_CHECK; |
1fd5e000 | 178 | |
b6e69d53 CV |
179 | /* Incredible but true: If we use sockets and SYSV IPC shared memory, |
180 | there's a good chance that a duplicated socket in the child occupies | |
181 | memory which is needed to duplicate shared memory from the parent | |
182 | process, if the shared memory hasn't been duplicated already. | |
183 | The same goes very likely for "normal" mmap shared memory, too, but | |
184 | with SYSV IPC it was the first time observed. So, *never* fixup | |
185 | fdtab before fixing up shared memory. */ | |
186 | if (fixup_shms_after_fork ()) | |
187 | api_fatal ("recreate_shm areas after fork failed"); | |
5ec14fe4 | 188 | |
1ec4f618 CF |
189 | MALLOC_CHECK; |
190 | ||
191 | /* If we haven't dynamically loaded any dlls, just signal | |
192 | the parent. Otherwise, load all the dlls, tell the parent | |
193 | that we're done, and wait for the parent to fill in the. | |
194 | loaded dlls' data/bss. */ | |
195 | if (!load_dlls) | |
d525130f CF |
196 | { |
197 | cygheap->fdtab.fixup_after_fork (hParent); | |
2e008fb9 | 198 | sync_with_parent ("performed fork fixup", false); |
d525130f | 199 | } |
1ec4f618 | 200 | else |
1fd5e000 | 201 | { |
71f53a2f | 202 | dlls.load_after_fork (hParent); |
d525130f | 203 | cygheap->fdtab.fixup_after_fork (hParent); |
2e008fb9 | 204 | sync_with_parent ("loaded dlls", true); |
1fd5e000 CF |
205 | } |
206 | ||
44d2fc0a | 207 | init_console_handler (myself->ctty > 0); |
0c55f6ed | 208 | ForceCloseHandle1 (fork_info->forker_finished, forker_finished); |
2eb392bd | 209 | |
f1f13795 | 210 | pthread::atforkchild (); |
f6936c48 | 211 | fixup_timers_after_fork (); |
166b2571 | 212 | cygbench ("fork-child"); |
b21413b3 | 213 | ld_preload (); |
f02b22dc | 214 | fixup_hooks_after_fork (); |
f02b22dc | 215 | _my_tls.fixup_after_fork (); |
1fb6667f CF |
216 | /* Clear this or the destructor will close them. In the case of |
217 | rd_proc_pipe that would be an invalid handle. In the case of | |
218 | wr_proc_pipe it would be == my_wr_proc_pipe. Both would be bad. */ | |
219 | ch.rd_proc_pipe = ch.wr_proc_pipe = NULL; | |
f359a29f | 220 | cygwin_finished_initializing = true; |
1ec4f618 CF |
221 | return 0; |
222 | } | |
1fd5e000 | 223 | |
280fdd0b | 224 | #define NO_SLOW_PID_REUSE |
5d9a7c87 | 225 | #ifndef NO_SLOW_PID_REUSE |
84aeff41 CF |
226 | static void |
227 | slow_pid_reuse (HANDLE h) | |
228 | { | |
24515d65 CF |
229 | static NO_COPY HANDLE last_fork_procs[NPIDS_HELD]; |
230 | static NO_COPY unsigned nfork_procs; | |
84aeff41 | 231 | |
5ba05cab | 232 | if (nfork_procs >= (sizeof (last_fork_procs) / sizeof (last_fork_procs [0]))) |
84aeff41 | 233 | nfork_procs = 0; |
54dd79bb | 234 | /* Keep a list of handles to child processes sitting around to prevent |
84aeff41 CF |
235 | Windows from reusing the same pid n times in a row. Having the same pids |
236 | close in succesion confuses bash. Keeping a handle open will stop | |
237 | windows from reusing the same pid. */ | |
238 | if (last_fork_procs[nfork_procs]) | |
5ba05cab | 239 | ForceCloseHandle1 (last_fork_procs[nfork_procs], fork_stupidity); |
f16706de CV |
240 | if (DuplicateHandle (GetCurrentProcess (), h, |
241 | GetCurrentProcess (), &last_fork_procs[nfork_procs], | |
242 | 0, FALSE, DUPLICATE_SAME_ACCESS)) | |
5ba05cab CF |
243 | ProtectHandle1 (last_fork_procs[nfork_procs], fork_stupidity); |
244 | else | |
84aeff41 CF |
245 | { |
246 | last_fork_procs[nfork_procs] = NULL; | |
247 | system_printf ("couldn't create last_fork_proc, %E"); | |
248 | } | |
249 | nfork_procs++; | |
250 | } | |
89e7a1ce | 251 | #endif |
84aeff41 | 252 | |
280fdd0b | 253 | int __stdcall |
39fc0d36 | 254 | frok::parent (volatile char * volatile stack_here) |
1ec4f618 | 255 | { |
54dd79bb | 256 | HANDLE forker_finished; |
1ec4f618 | 257 | DWORD rc; |
280fdd0b | 258 | child_pid = -1; |
280fdd0b CF |
259 | this_errno = 0; |
260 | bool fix_impersonation = false; | |
261 | pinfo child; | |
1fd5e000 | 262 | |
f16706de | 263 | int c_flags = GetPriorityClass (GetCurrentProcess ()); |
0dc24975 | 264 | debug_printf ("priority class %d", c_flags); |
1ec4f618 | 265 | |
85510878 CF |
266 | errmsg = NULL; |
267 | hchild = NULL; | |
268 | ||
1ec4f618 CF |
269 | /* If we don't have a console, then don't create a console for the |
270 | child either. */ | |
580e99a1 | 271 | HANDLE console_handle = CreateFile ("CONOUT$", GENERIC_WRITE, |
fc3e7da6 CV |
272 | FILE_SHARE_READ | FILE_SHARE_WRITE, |
273 | &sec_none_nih, OPEN_EXISTING, | |
274 | FILE_ATTRIBUTE_NORMAL, NULL); | |
1ec4f618 | 275 | |
580e99a1 | 276 | if (console_handle != INVALID_HANDLE_VALUE) |
1ec4f618 CF |
277 | CloseHandle (console_handle); |
278 | else | |
279 | c_flags |= DETACHED_PROCESS; | |
1fd5e000 | 280 | |
b14f53a8 CV |
281 | /* Some file types (currently only sockets) need extra effort in the |
282 | parent after CreateProcess and before copying the datastructures | |
283 | to the child. So we have to start the child in suspend state, | |
284 | unfortunately, to avoid a race condition. */ | |
285 | if (cygheap->fdtab.need_fixup_before ()) | |
286 | c_flags |= CREATE_SUSPENDED; | |
287 | ||
71f53a2f CF |
288 | /* Remember if we need to load dynamically linked dlls. |
289 | We do this here so that this information will be available | |
290 | in the parent and, when the stack is copied, in the child. */ | |
1ec4f618 | 291 | load_dlls = dlls.reload_on_fork && dlls.loaded_dlls; |
1fd5e000 | 292 | |
1ec4f618 CF |
293 | forker_finished = CreateEvent (&sec_all, FALSE, FALSE, NULL); |
294 | if (forker_finished == NULL) | |
295 | { | |
280fdd0b | 296 | this_errno = geterrno_from_win_error (); |
85510878 | 297 | error ("unable to allocate forker_finished event"); |
1ec4f618 CF |
298 | return -1; |
299 | } | |
1fd5e000 | 300 | |
0301bfd0 | 301 | ProtectHandleINH (forker_finished); |
1fd5e000 | 302 | |
1ec4f618 | 303 | ch.forker_finished = forker_finished; |
1fd5e000 | 304 | |
0dc24975 | 305 | ch.stackbottom = _tlsbase; |
89d3c72d CV |
306 | ch.stacktop = (void *) _tlstop; |
307 | ch.stackaddr = 0; | |
308 | ch.guardsize = 0; | |
309 | if (&_my_tls != _main_tls) | |
310 | { | |
311 | /* We have not been started from the main thread. Fetch the | |
312 | information required to set up the thread stack identically | |
313 | in the child. */ | |
314 | PTEB teb = NtCurrentTeb (); | |
315 | if (!teb->DeallocationStack) | |
b86f999a | 316 | { |
89d3c72d CV |
317 | /* Pthread with application-provided stack. Don't set up a |
318 | PAGE_GUARD page. guardsize == -1 is used in alloc_stack_hard_way | |
319 | to recognize this type of stack. */ | |
320 | ch.stackaddr = _my_tls.tid->attr.stackaddr; | |
321 | ch.guardsize = (size_t) -1; | |
322 | } | |
323 | else | |
324 | { | |
325 | ch.stackaddr = teb->DeallocationStack; | |
326 | /* If it's a pthread, fetch guardsize from thread attributes. */ | |
327 | if (_my_tls.tid) | |
328 | ch.guardsize = _my_tls.tid->attr.guardsize; | |
329 | } | |
330 | } | |
61522196 | 331 | debug_printf ("stack - bottom %p, top %p, addr %p, guardsize %lu", |
89d3c72d | 332 | ch.stackbottom, ch.stacktop, ch.stackaddr, ch.guardsize); |
1fd5e000 | 333 | |
bbca1e4c | 334 | PROCESS_INFORMATION pi; |
752b16ce | 335 | STARTUPINFOW si; |
bbca1e4c CF |
336 | |
337 | memset (&si, 0, sizeof (si)); | |
752b16ce | 338 | si.cb = sizeof si; |
c6674b53 | 339 | |
54dd79bb | 340 | si.lpReserved2 = (LPBYTE) &ch; |
c90e1cf1 | 341 | si.cbReserved2 = sizeof (ch); |
1fd5e000 | 342 | |
61522196 | 343 | syscall_printf ("CreateProcessW (%W, %W, 0, 0, 1, %y, 0, 0, %p, %p)", |
d3258e06 | 344 | myself->progname, myself->progname, c_flags, &si, &pi); |
12b33712 CF |
345 | bool locked = __malloc_lock (); |
346 | time_t start_time = time (NULL); | |
347 | ||
1ec4f618 | 348 | /* Remove impersonation */ |
70249d56 | 349 | cygheap->user.deimpersonate (); |
280fdd0b | 350 | fix_impersonation = true; |
977ad543 | 351 | ch.refresh_cygheap (); |
1fb6667f | 352 | ch.prefork (); /* set up process tracking pipes. */ |
1fd5e000 | 353 | |
84d38174 | 354 | while (1) |
1ec4f618 | 355 | { |
85510878 | 356 | hchild = NULL; |
30fa1549 CF |
357 | rc = CreateProcessW (myself->progname, /* image to run */ |
358 | myself->progname, /* what we send in arg0 */ | |
752b16ce CV |
359 | &sec_none_nih, |
360 | &sec_none_nih, | |
30fa1549 | 361 | TRUE, /* inherit handles from parent */ |
752b16ce | 362 | c_flags, |
30fa1549 CF |
363 | NULL, /* environment filled in later */ |
364 | 0, /* use current drive/directory */ | |
752b16ce CV |
365 | &si, |
366 | &pi); | |
84d38174 | 367 | |
56a19715 CF |
368 | if (rc) |
369 | debug_printf ("forked pid %u", pi.dwProcessId); | |
370 | else | |
84d38174 CF |
371 | { |
372 | this_errno = geterrno_from_win_error (); | |
85510878 | 373 | error ("CreateProcessW failed for '%W'", myself->progname); |
84d38174 CF |
374 | memset (&pi, 0, sizeof (pi)); |
375 | goto cleanup; | |
376 | } | |
64b30629 | 377 | |
b14f53a8 CV |
378 | if (cygheap->fdtab.need_fixup_before ()) |
379 | { | |
380 | cygheap->fdtab.fixup_before_fork (pi.dwProcessId); | |
381 | ResumeThread (pi.hThread); | |
382 | } | |
383 | ||
a9396868 | 384 | CloseHandle (pi.hThread); |
85510878 | 385 | hchild = pi.hProcess; |
a9396868 CF |
386 | |
387 | /* Protect the handle but name it similarly to the way it will | |
388 | be called in subproc handling. */ | |
85510878 | 389 | ProtectHandle1 (hchild, childhProc); |
a9396868 | 390 | |
ef8bff85 | 391 | strace.write_childpid (pi.dwProcessId); |
84d38174 CF |
392 | |
393 | /* Wait for subproc to initialize itself. */ | |
85510878 | 394 | if (!ch.sync (pi.dwProcessId, hchild, FORK_WAIT_TIMEOUT)) |
84d38174 | 395 | { |
dfd5d5be CF |
396 | if (!error ("forked process %u died unexpectedly, retry %d, exit code %d", |
397 | pi.dwProcessId, ch.retry, ch.exit_code)) | |
f02400f7 | 398 | continue; |
84d38174 | 399 | this_errno = EAGAIN; |
84d38174 CF |
400 | goto cleanup; |
401 | } | |
402 | break; | |
403 | } | |
5d970405 | 404 | |
12b33712 CF |
405 | /* Restore impersonation */ |
406 | cygheap->user.reimpersonate (); | |
407 | fix_impersonation = false; | |
408 | ||
280fdd0b CF |
409 | child_pid = cygwin_pid (pi.dwProcessId); |
410 | child.init (child_pid, 1, NULL); | |
72067cca | 411 | |
54dd79bb | 412 | if (!child) |
6c68fbbc | 413 | { |
280fdd0b | 414 | this_errno = get_errno () == ENOMEM ? ENOMEM : EAGAIN; |
6c68fbbc | 415 | syscall_printf ("pinfo failed"); |
6c68fbbc CF |
416 | goto cleanup; |
417 | } | |
1fd5e000 | 418 | |
84d38174 | 419 | child->start_time = start_time; /* Register child's starting time. */ |
f834829d CF |
420 | child->nice = myself->nice; |
421 | ||
1ec4f618 CF |
422 | /* Initialize things that are done later in dll_crt0_1 that aren't done |
423 | for the forkee. */ | |
d3258e06 | 424 | wcscpy (child->progname, myself->progname); |
1fd5e000 | 425 | |
1ec4f618 | 426 | /* Fill in fields in the child's process table entry. */ |
54dd79bb | 427 | child->dwProcessId = pi.dwProcessId; |
85510878 | 428 | child.hProcess = hchild; |
b7d95b5b | 429 | ch.postfork (child); |
cde0c2fb CF |
430 | |
431 | /* Hopefully, this will succeed. The alternative to doing things this | |
432 | way is to reserve space prior to calling CreateProcess and then fill | |
433 | it in afterwards. This requires more bookkeeping than I like, though, | |
434 | so we'll just do it the easy way. So, terminate any child process if | |
435 | we can't actually record the pid in the internal table. */ | |
4ee52924 | 436 | if (!child.remember (false)) |
cde0c2fb | 437 | { |
85510878 | 438 | TerminateProcess (hchild, 1); |
280fdd0b | 439 | this_errno = EAGAIN; |
40c7d132 | 440 | #ifdef DEBUGGING0 |
85510878 | 441 | error ("child remember failed"); |
280fdd0b | 442 | #endif |
cde0c2fb CF |
443 | goto cleanup; |
444 | } | |
445 | ||
5d9a7c87 | 446 | #ifndef NO_SLOW_PID_REUSE |
85510878 | 447 | slow_pid_reuse (hchild); |
89e7a1ce | 448 | #endif |
1ec4f618 | 449 | |
1ec4f618 CF |
450 | /* CHILD IS STOPPED */ |
451 | debug_printf ("child is alive (but stopped)"); | |
452 | ||
ef8bff85 | 453 | |
12b33712 CF |
454 | /* Initialize, in order: stack, dll data, dll bss. |
455 | data, bss, heap were done earlier (in dcrt0.cc) | |
456 | Note: variables marked as NO_COPY will not be copied since they are | |
457 | placed in a protected segment. */ | |
1fd5e000 | 458 | |
1ec4f618 | 459 | MALLOC_CHECK; |
ad02bb70 CF |
460 | const void *impure_beg; |
461 | const void *impure_end; | |
462 | const char *impure; | |
29d52c8a | 463 | if (&_my_tls == _main_tls) |
ad02bb70 | 464 | impure_beg = impure_end = impure = NULL; |
29d52c8a CF |
465 | else |
466 | { | |
ad02bb70 | 467 | impure = "impure"; |
29d52c8a CF |
468 | impure_beg = _impure_ptr; |
469 | impure_end = _impure_ptr + 1; | |
470 | } | |
85510878 | 471 | rc = child_copy (hchild, true, |
ad02bb70 CF |
472 | "stack", stack_here, ch.stackbottom, |
473 | impure, impure_beg, impure_end, | |
474 | NULL); | |
1fd5e000 | 475 | |
c7e2187a | 476 | __malloc_unlock (); |
e431827c | 477 | locked = false; |
1ec4f618 CF |
478 | MALLOC_CHECK; |
479 | if (!rc) | |
bbca1e4c CF |
480 | { |
481 | this_errno = get_errno (); | |
85510878 | 482 | error ("pid %u, exitval %p", pi.dwProcessId, ch.exit_code); |
bbca1e4c CF |
483 | goto cleanup; |
484 | } | |
1fd5e000 | 485 | |
1ec4f618 CF |
486 | /* Now fill data/bss of any DLLs that were linked into the program. */ |
487 | for (dll *d = dlls.istart (DLL_LINK); d; d = dlls.inext ()) | |
488 | { | |
489 | debug_printf ("copying data/bss of a linked dll"); | |
85510878 | 490 | if (!child_copy (hchild, true, |
ad02bb70 CF |
491 | "linked dll data", d->p.data_start, d->p.data_end, |
492 | "linked dll bss", d->p.bss_start, d->p.bss_end, | |
493 | NULL)) | |
280fdd0b CF |
494 | { |
495 | this_errno = get_errno (); | |
85510878 | 496 | error ("couldn't copy linked dll data/bss"); |
280fdd0b CF |
497 | goto cleanup; |
498 | } | |
1fd5e000 | 499 | } |
1fd5e000 | 500 | |
bbca1e4c CF |
501 | /* Start thread, and then wait for it to reload dlls. */ |
502 | resume_child (forker_finished); | |
85510878 | 503 | if (!ch.sync (child->pid, hchild, FORK_WAIT_TIMEOUT)) |
54dd79bb | 504 | { |
280fdd0b | 505 | this_errno = EAGAIN; |
85510878 | 506 | error ("died waiting for dll loading"); |
54dd79bb CF |
507 | goto cleanup; |
508 | } | |
1fd5e000 | 509 | |
1ec4f618 CF |
510 | /* If DLLs were loaded in the parent, then the child has reloaded all |
511 | of them and is now waiting to have all of the individual data and | |
512 | bss sections filled in. */ | |
513 | if (load_dlls) | |
514 | { | |
515 | /* CHILD IS STOPPED */ | |
516 | /* write memory of reloaded dlls */ | |
517 | for (dll *d = dlls.istart (DLL_LOAD); d; d = dlls.inext ()) | |
1fd5e000 | 518 | { |
1ec4f618 | 519 | debug_printf ("copying data/bss for a loaded dll"); |
85510878 | 520 | if (!child_copy (hchild, true, |
ad02bb70 CF |
521 | "loaded dll data", d->p.data_start, d->p.data_end, |
522 | "loaded dll bss", d->p.bss_start, d->p.bss_end, | |
523 | NULL)) | |
280fdd0b CF |
524 | { |
525 | this_errno = get_errno (); | |
526 | #ifdef DEBUGGING | |
85510878 | 527 | error ("copying data/bss for a loaded dll"); |
280fdd0b CF |
528 | #endif |
529 | goto cleanup; | |
530 | } | |
1fd5e000 | 531 | } |
1ec4f618 | 532 | /* Start the child up again. */ |
0c55f6ed | 533 | resume_child (forker_finished); |
1fd5e000 CF |
534 | } |
535 | ||
1ec4f618 CF |
536 | ForceCloseHandle (forker_finished); |
537 | forker_finished = NULL; | |
1fd5e000 | 538 | |
54dd79bb | 539 | return child_pid; |
1fd5e000 CF |
540 | |
541 | /* Common cleanup code for failure cases */ | |
280fdd0b CF |
542 | cleanup: |
543 | if (fix_impersonation) | |
544 | cygheap->user.reimpersonate (); | |
e431827c CF |
545 | if (locked) |
546 | __malloc_unlock (); | |
547 | ||
1fd5e000 | 548 | /* Remember to de-allocate the fd table. */ |
85510878 CF |
549 | if (hchild && !child.hProcess) |
550 | ForceCloseHandle1 (hchild, childhProc); | |
1fd5e000 CF |
551 | if (forker_finished) |
552 | ForceCloseHandle (forker_finished); | |
280fdd0b | 553 | debug_printf ("returning -1"); |
1fd5e000 CF |
554 | return -1; |
555 | } | |
556 | ||
1ec4f618 CF |
557 | extern "C" int |
558 | fork () | |
1fd5e000 | 559 | { |
280fdd0b | 560 | frok grouped; |
1ec4f618 | 561 | |
1ec4f618 | 562 | debug_printf ("entering"); |
aece55b9 | 563 | grouped.load_dlls = 0; |
1ec4f618 | 564 | |
f02b22dc | 565 | int res; |
39fc0d36 | 566 | bool ischild = false; |
f02b22dc | 567 | |
f8f9b12e CF |
568 | myself->set_has_pgid_children (); |
569 | ||
ce95c640 CF |
570 | if (grouped.ch.parent == NULL) |
571 | return -1; | |
572 | if (grouped.ch.subproc_ready == NULL) | |
54dd79bb CF |
573 | { |
574 | system_printf ("unable to allocate subproc_ready event, %E"); | |
575 | return -1; | |
576 | } | |
1ec4f618 | 577 | |
39fc0d36 CF |
578 | { |
579 | hold_everything held_everything (ischild); | |
637a1aec CV |
580 | /* This tmp_pathbuf constructor is required here because the below setjmp |
581 | magic will otherwise not restore the original buffer count values in | |
582 | the thread-local storage. A process forking too deeply will run into | |
583 | the problem to be out of temporary TLS path buffers. */ | |
584 | tmp_pathbuf tp; | |
07f89f85 | 585 | |
39fc0d36 CF |
586 | if (!held_everything) |
587 | { | |
588 | if (exit_state) | |
589 | Sleep (INFINITE); | |
590 | set_errno (EAGAIN); | |
591 | return -1; | |
592 | } | |
7912bcbf | 593 | |
977ad543 CF |
594 | /* Put the dll list in topological dependency ordering, in |
595 | hopes that the child will have a better shot at loading dlls | |
596 | properly if it only has to deal with one at a time. */ | |
597 | dlls.topsort (); | |
598 | ||
39fc0d36 | 599 | ischild = !!setjmp (grouped.ch.jmp); |
7912bcbf | 600 | |
61522196 CV |
601 | volatile char * volatile stackp; |
602 | #ifdef __x86_64__ | |
603 | __asm__ volatile ("movq %%rsp,%0": "=r" (stackp)); | |
604 | #else | |
605 | __asm__ volatile ("movl %%esp,%0": "=r" (stackp)); | |
606 | #endif | |
39fc0d36 | 607 | |
39fc0d36 | 608 | if (!ischild) |
61522196 | 609 | res = grouped.parent (stackp); |
39fc0d36 | 610 | else |
e943a1a3 | 611 | { |
61522196 | 612 | res = grouped.child (stackp); |
85510878 | 613 | in_forkee = false; |
e943a1a3 CF |
614 | ischild = true; /* might have been reset by fork mem copy */ |
615 | } | |
39fc0d36 | 616 | } |
1ec4f618 CF |
617 | |
618 | MALLOC_CHECK; | |
b9874a0c | 619 | if (ischild) |
fc0e5071 CF |
620 | { |
621 | myself->process_state |= PID_ACTIVE; | |
b8424c5e | 622 | myself->process_state &= ~(PID_INITIALIZING | PID_EXITED | PID_REAPED); |
fc0e5071 | 623 | } |
b9874a0c | 624 | else if (res < 0) |
280fdd0b | 625 | { |
85510878 | 626 | if (!grouped.errmsg) |
40c7d132 | 627 | syscall_printf ("fork failed - child pid %d, errno %d", grouped.child_pid, grouped.this_errno); |
280fdd0b | 628 | else |
40c7d132 | 629 | { |
85510878 | 630 | char buf[strlen (grouped.errmsg) + sizeof ("child %d - , errno 4294967295 ")]; |
40c7d132 | 631 | strcpy (buf, "child %d - "); |
85510878 | 632 | strcat (buf, grouped.errmsg); |
40c7d132 CF |
633 | strcat (buf, ", errno %d"); |
634 | system_printf (buf, grouped.child_pid, grouped.this_errno); | |
635 | } | |
636 | ||
280fdd0b CF |
637 | set_errno (grouped.this_errno); |
638 | } | |
b9aa8149 | 639 | syscall_printf ("%R = fork()", res); |
1ec4f618 | 640 | return res; |
1fd5e000 | 641 | } |
84aeff41 CF |
642 | #ifdef DEBUGGING |
643 | void | |
644 | fork_init () | |
645 | { | |
84aeff41 CF |
646 | } |
647 | #endif /*DEBUGGING*/ | |
1fd5e000 | 648 | |
1fd5e000 | 649 | |
8dca9e23 | 650 | extern "C" int |
1fd5e000 CF |
651 | vfork () |
652 | { | |
9e1ad59d | 653 | debug_printf ("stub called"); |
1fd5e000 | 654 | return fork (); |
1fd5e000 | 655 | } |
ce95c640 | 656 | |
ad02bb70 CF |
657 | /* Copy memory from one process to another. */ |
658 | ||
659 | bool | |
660 | child_copy (HANDLE hp, bool write, ...) | |
ce95c640 | 661 | { |
ad02bb70 CF |
662 | va_list args; |
663 | va_start (args, write); | |
664 | static const char *huh[] = {"read", "write"}; | |
665 | ||
666 | char *what; | |
667 | while ((what = va_arg (args, char *))) | |
668 | { | |
669 | char *low = va_arg (args, char *); | |
670 | char *high = va_arg (args, char *); | |
61522196 | 671 | SIZE_T todo = high - low; |
ad02bb70 CF |
672 | char *here; |
673 | ||
674 | for (here = low; here < high; here += todo) | |
675 | { | |
61522196 | 676 | SIZE_T done = 0; |
ad02bb70 CF |
677 | if (here + todo > high) |
678 | todo = high - here; | |
679 | int res; | |
680 | if (write) | |
681 | res = WriteProcessMemory (hp, here, here, todo, &done); | |
682 | else | |
683 | res = ReadProcessMemory (hp, here, here, todo, &done); | |
5d970405 | 684 | debug_printf ("%s - hp %p low %p, high %p, res %d", what, hp, low, high, res); |
ad02bb70 CF |
685 | if (!res || todo != done) |
686 | { | |
687 | if (!res) | |
688 | __seterrno (); | |
689 | /* If this happens then there is a bug in our fork | |
690 | implementation somewhere. */ | |
61522196 | 691 | system_printf ("%s %s copy failed, %p..%p, done %lu, windows pid %u, %E", |
0b7c56a5 | 692 | what, huh[write], low, high, done, myself->dwProcessId); |
ad02bb70 CF |
693 | goto err; |
694 | } | |
695 | } | |
696 | } | |
697 | ||
4cd31fc8 | 698 | va_end (args); |
ad02bb70 CF |
699 | debug_printf ("done"); |
700 | return true; | |
701 | ||
702 | err: | |
4cd31fc8 | 703 | va_end (args); |
ad02bb70 CF |
704 | TerminateProcess (hp, 1); |
705 | set_errno (EAGAIN); | |
706 | return false; | |
ce95c640 | 707 | } |