1 | /* Copyright (C) 1994-2024 Free Software Foundation, Inc. |
2 | This file is part of the GNU C Library. |
3 | |
4 | The GNU C Library is free software; you can redistribute it and/or |
5 | modify it under the terms of the GNU Lesser General Public |
6 | License as published by the Free Software Foundation; either |
7 | version 2.1 of the License, or (at your option) any later version. |
8 | |
9 | The GNU C Library is distributed in the hope that it will be useful, |
10 | but WITHOUT ANY WARRANTY; without even the implied warranty of |
11 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU |
12 | Lesser General Public License for more details. |
13 | |
14 | You should have received a copy of the GNU Lesser General Public |
15 | License along with the GNU C Library; if not, see |
16 | <https://www.gnu.org/licenses/>. */ |
17 | |
18 | #include <errno.h> |
19 | #include <unistd.h> |
20 | #include <hurd.h> |
21 | #include <hurd/signal.h> |
22 | #include <hurd/threadvar.h> |
23 | #include <setjmp.h> |
24 | #include <thread_state.h> |
25 | #include <sysdep.h> /* For stack growth direction. */ |
26 | #include "set-hooks.h" |
27 | #include <assert.h> |
28 | #include "hurdmalloc.h" /* XXX */ |
29 | #include <tls.h> |
30 | #include <malloc/malloc-internal.h> |
31 | #include <nss/nss_database.h> |
32 | #include <unwind-link.h> |
33 | #include <register-atfork.h> |
34 | |
35 | #undef __fork |
36 | |
37 | |
38 | /* Things that want to be locked while forking. */ |
39 | symbol_set_declare (_hurd_fork_locks) |
40 | |
41 | /* Things that want to be called before we fork, to prepare the parent for |
42 | task_create, when the new child task will inherit our address space. */ |
43 | DEFINE_HOOK (_hurd_fork_prepare_hook, (void)); |
44 | |
45 | /* Things that want to be called when we are forking, with the above all |
46 | locked. They are passed the task port of the child. The child process |
47 | is all set up except for doing proc_child, and has no threads yet. */ |
48 | DEFINE_HOOK (_hurd_fork_setup_hook, (void)); |
49 | |
50 | /* Things to be run in the child fork. */ |
51 | DEFINE_HOOK (_hurd_fork_child_hook, (void)); |
52 | |
53 | /* Things to be run in the parent fork. */ |
54 | DEFINE_HOOK (_hurd_fork_parent_hook, (void)); |
55 | |
56 | |
57 | /* Clone the calling process, creating an exact copy. |
58 | Return -1 for errors, 0 to the new process, |
59 | and the process ID of the new process to the old process. */ |
60 | pid_t |
61 | _Fork (void) |
62 | { |
63 | jmp_buf env; |
64 | pid_t pid; |
65 | size_t i; |
66 | error_t err; |
67 | struct hurd_sigstate *volatile ss; |
68 | |
69 | ss = _hurd_self_sigstate (); |
70 | retry: |
71 | __spin_lock (&ss->critical_section_lock); |
72 | |
73 | #undef LOSE |
74 | #define LOSE do { assert_perror (err); goto lose; } while (0) /* XXX */ |
75 | |
76 | if (! setjmp (env)) |
77 | { |
78 | process_t newproc; |
79 | task_t newtask; |
80 | thread_t thread, sigthread; |
81 | mach_port_urefs_t thread_refs, sigthread_refs; |
82 | struct machine_thread_state state; |
83 | mach_msg_type_number_t statecount; |
84 | mach_port_t *portnames = NULL; |
85 | mach_msg_type_number_t nportnames = 0; |
86 | mach_port_type_t *porttypes = NULL; |
87 | mach_msg_type_number_t nporttypes = 0; |
88 | thread_t *threads = NULL; |
89 | mach_msg_type_number_t nthreads = 0; |
90 | int ports_locked = 0, stopped = 0; |
91 | |
92 | void resume_threads (void) |
93 | { |
94 | if (! stopped) |
95 | return; |
96 | |
97 | assert (threads); |
98 | |
99 | for (i = 0; i < nthreads; ++i) |
100 | if (threads[i] != ss->thread) |
101 | __thread_resume (threads[i]); |
102 | stopped = 0; |
103 | } |
104 | |
105 | /* Run things that prepare for forking before we create the task. */ |
106 | RUN_HOOK (_hurd_fork_prepare_hook, ()); |
107 | |
108 | /* Lock things that want to be locked before we fork. */ |
109 | { |
110 | void *const *p; |
111 | for (p = symbol_set_first_element (_hurd_fork_locks); |
112 | ! symbol_set_end_p (_hurd_fork_locks, p); |
113 | ++p) |
114 | __mutex_lock (*p); |
115 | } |
116 | __mutex_lock (&_hurd_siglock); |
117 | |
118 | /* Acquire malloc locks. This needs to come last because fork |
119 | handlers may use malloc, and the libio list lock has an |
120 | indirect malloc dependency as well (via the getdelim |
121 | function). */ |
122 | _hurd_malloc_fork_prepare (); |
123 | |
124 | newtask = MACH_PORT_NULL; |
125 | thread = sigthread = MACH_PORT_NULL; |
126 | newproc = MACH_PORT_NULL; |
127 | |
128 | /* Lock all the port cells for the standard ports while we copy the |
129 | address space. We want to insert all the send rights into the |
130 | child with the same names. */ |
131 | for (i = 0; i < _hurd_nports; ++i) |
132 | __spin_lock (&_hurd_ports[i].lock); |
133 | ports_locked = 1; |
134 | |
135 | |
136 | /* Keep our SS locked while stopping other threads, so they don't get a |
137 | chance to have it locked in the copied space. */ |
138 | __spin_lock (&ss->lock); |
139 | /* Stop all other threads while copying the address space, |
140 | so nothing changes. */ |
141 | err = __proc_dostop (_hurd_ports[INIT_PORT_PROC].port, ss->thread); |
142 | __spin_unlock (&ss->lock); |
143 | if (!err) |
144 | { |
145 | stopped = 1; |
146 | |
147 | #define XXX_KERNEL_PAGE_FAULT_BUG /* XXX work around page fault bug in mk */ |
148 | |
149 | #ifdef XXX_KERNEL_PAGE_FAULT_BUG |
150 | /* Gag me with a pitchfork. |
151 | The bug scenario is this: |
152 | |
153 | - The page containing __mach_task_self_ is paged out. |
154 | - The signal thread was faulting on that page when we |
155 | suspended it via proc_dostop. It holds some lock, or set |
156 | some busy bit, or somesuch. |
157 | - Now this thread faults on that same page. |
158 | - GRATUIOUS DEADLOCK |
159 | |
160 | We can break the deadlock by aborting the thread that faulted |
161 | first, which if the bug happened was the signal thread because |
162 | it is the only other thread and we just suspended it. |
163 | */ |
164 | __thread_abort (_hurd_msgport_thread); |
165 | #endif |
166 | /* Create the child task. It will inherit a copy of our memory. */ |
167 | err = __task_create (__mach_task_self (), |
168 | #ifdef KERN_INVALID_LEDGER |
169 | NULL, 0, /* OSF Mach */ |
170 | #endif |
171 | 1, &newtask); |
172 | } |
173 | |
174 | /* Unlock the global signal state lock, so we do not |
175 | block the signal thread any longer than necessary. */ |
176 | __mutex_unlock (&_hurd_siglock); |
177 | |
178 | if (err) |
179 | LOSE; |
180 | |
181 | /* Fetch the names of all ports used in this task. */ |
182 | if (err = __mach_port_names (__mach_task_self (), |
183 | &portnames, &nportnames, |
184 | &porttypes, &nporttypes)) |
185 | LOSE; |
186 | if (nportnames != nporttypes) |
187 | { |
188 | err = EGRATUITOUS; |
189 | LOSE; |
190 | } |
191 | |
192 | /* Get send rights for all the threads in this task. |
193 | We want to avoid giving these rights to the child. */ |
194 | if (err = __task_threads (__mach_task_self (), &threads, &nthreads)) |
195 | LOSE; |
196 | |
197 | /* Get the child process's proc server port. We will insert it into |
198 | the child with the same name as we use for our own proc server |
199 | port; and we will need it to set the child's message port. */ |
200 | if (err = __proc_task2proc (_hurd_ports[INIT_PORT_PROC].port, |
201 | newtask, &newproc)) |
202 | LOSE; |
203 | |
204 | /* Insert all our port rights into the child task. */ |
205 | thread_refs = sigthread_refs = 0; |
206 | for (i = 0; i < nportnames; ++i) |
207 | { |
208 | if (porttypes[i] & MACH_PORT_TYPE_RECEIVE) |
209 | { |
210 | /* This is a receive right. We want to give the child task |
211 | its own new receive right under the same name. */ |
212 | if (err = __mach_port_allocate_name (newtask, |
213 | MACH_PORT_RIGHT_RECEIVE, |
214 | portnames[i])) |
215 | LOSE; |
216 | if (porttypes[i] & MACH_PORT_TYPE_SEND) |
217 | { |
218 | /* Give the child as many send rights for its receive |
219 | right as we have for ours. */ |
220 | mach_port_urefs_t refs; |
221 | mach_port_t port; |
222 | mach_msg_type_name_t poly; |
223 | if (err = __mach_port_get_refs (__mach_task_self (), |
224 | portnames[i], |
225 | MACH_PORT_RIGHT_SEND, |
226 | &refs)) |
227 | LOSE; |
228 | if (err = __mach_port_extract_right (newtask, |
229 | portnames[i], |
230 | MACH_MSG_TYPE_MAKE_SEND, |
231 | &port, &poly)) |
232 | LOSE; |
233 | if (portnames[i] == _hurd_msgport) |
234 | { |
235 | /* We just created a receive right for the child's |
236 | message port and are about to insert send rights |
237 | for it. Now, while we happen to have a send right |
238 | for it, give it to the proc server. */ |
239 | mach_port_t old; |
240 | if (err = __proc_setmsgport (newproc, port, &old)) |
241 | LOSE; |
242 | if (old != MACH_PORT_NULL) |
243 | /* XXX what to do here? */ |
244 | __mach_port_deallocate (__mach_task_self (), old); |
245 | /* The new task will receive its own exceptions |
246 | on its message port. */ |
247 | if (err = |
248 | #ifdef TASK_EXCEPTION_PORT |
249 | __task_set_special_port (newtask, |
250 | TASK_EXCEPTION_PORT, |
251 | port) |
252 | #elif defined (EXC_MASK_ALL) |
253 | __task_set_exception_ports |
254 | (newtask, EXC_MASK_ALL & ~(EXC_MASK_SYSCALL |
255 | | EXC_MASK_MACH_SYSCALL |
256 | | EXC_MASK_RPC_ALERT), |
257 | port, EXCEPTION_DEFAULT, MACHINE_THREAD_STATE) |
258 | #else |
259 | # error task_set_exception_port? |
260 | #endif |
261 | ) |
262 | LOSE; |
263 | } |
264 | if (err = __mach_port_insert_right (newtask, |
265 | portnames[i], |
266 | port, |
267 | MACH_MSG_TYPE_MOVE_SEND)) |
268 | LOSE; |
269 | if (refs > 1 |
270 | && (err = __mach_port_mod_refs (newtask, |
271 | portnames[i], |
272 | MACH_PORT_RIGHT_SEND, |
273 | refs - 1))) |
274 | LOSE; |
275 | } |
276 | if (porttypes[i] & MACH_PORT_TYPE_SEND_ONCE) |
277 | { |
278 | /* Give the child a send-once right for its receive right, |
279 | since we have one for ours. */ |
280 | mach_port_t port; |
281 | mach_msg_type_name_t poly; |
282 | if (err = __mach_port_extract_right |
283 | (newtask, |
284 | portnames[i], |
285 | MACH_MSG_TYPE_MAKE_SEND_ONCE, |
286 | &port, &poly)) |
287 | LOSE; |
288 | if (err = __mach_port_insert_right |
289 | (newtask, |
290 | portnames[i], port, |
291 | MACH_MSG_TYPE_MOVE_SEND_ONCE)) |
292 | LOSE; |
293 | } |
294 | } |
295 | else if (porttypes[i] |
296 | & (MACH_PORT_TYPE_SEND|MACH_PORT_TYPE_DEAD_NAME)) |
297 | { |
298 | /* This is a send right or a dead name. |
299 | Give the child as many references for it as we have. */ |
300 | mach_port_urefs_t refs = 0, *record_refs = NULL; |
301 | mach_port_t insert; |
302 | mach_msg_type_name_t insert_type = MACH_MSG_TYPE_COPY_SEND; |
303 | if (portnames[i] == newtask || portnames[i] == newproc) |
304 | /* Skip the name we use for the child's task or proc ports. */ |
305 | continue; |
306 | if (portnames[i] == __mach_task_self ()) |
307 | /* For the name we use for our own task port, |
308 | insert the child's task port instead. */ |
309 | insert = newtask; |
310 | else if (portnames[i] == _hurd_ports[INIT_PORT_PROC].port) |
311 | { |
312 | /* Use the proc server port for the new task. */ |
313 | insert = newproc; |
314 | insert_type = MACH_MSG_TYPE_COPY_SEND; |
315 | } |
316 | else if (portnames[i] == ss->thread) |
317 | { |
318 | /* For the name we use for our own thread port, we will |
319 | insert the thread port for the child main user thread |
320 | after we create it. */ |
321 | insert = MACH_PORT_NULL; |
322 | record_refs = &thread_refs; |
323 | /* Allocate a dead name right for this name as a |
324 | placeholder, so the kernel will not chose this name |
325 | for any other new port (it might use it for one of the |
326 | rights created when a thread is created). */ |
327 | if (err = __mach_port_allocate_name |
328 | (newtask, MACH_PORT_RIGHT_DEAD_NAME, portnames[i])) |
329 | LOSE; |
330 | } |
331 | else if (portnames[i] == _hurd_msgport_thread) |
332 | /* For the name we use for our signal thread's thread port, |
333 | we will insert the thread port for the child's signal |
334 | thread after we create it. */ |
335 | { |
336 | insert = MACH_PORT_NULL; |
337 | record_refs = &sigthread_refs; |
338 | /* Allocate a dead name right as a placeholder. */ |
339 | if (err = __mach_port_allocate_name |
340 | (newtask, MACH_PORT_RIGHT_DEAD_NAME, portnames[i])) |
341 | LOSE; |
342 | } |
343 | else |
344 | { |
345 | /* Skip the name we use for any of our own thread ports. */ |
346 | mach_msg_type_number_t j; |
347 | for (j = 0; j < nthreads; ++j) |
348 | if (portnames[i] == threads[j]) |
349 | break; |
350 | if (j < nthreads) |
351 | continue; |
352 | |
353 | /* Copy our own send right. */ |
354 | insert = portnames[i]; |
355 | } |
356 | /* Find out how many user references we have for |
357 | the send right with this name. */ |
358 | if (err = __mach_port_get_refs (__mach_task_self (), |
359 | portnames[i], |
360 | MACH_PORT_RIGHT_SEND, |
361 | record_refs ?: &refs)) |
362 | LOSE; |
363 | if (insert == MACH_PORT_NULL) |
364 | continue; |
365 | if (insert == portnames[i] |
366 | && (porttypes[i] & MACH_PORT_TYPE_DEAD_NAME)) |
367 | /* This is a dead name; allocate another dead name |
368 | with the same name in the child. */ |
369 | allocate_dead_name: |
370 | err = __mach_port_allocate_name (newtask, |
371 | MACH_PORT_RIGHT_DEAD_NAME, |
372 | portnames[i]); |
373 | else |
374 | /* Insert the chosen send right into the child. */ |
375 | err = __mach_port_insert_right (newtask, |
376 | portnames[i], |
377 | insert, insert_type); |
378 | switch (err) |
379 | { |
380 | case KERN_NAME_EXISTS: |
381 | { |
382 | /* It already has a send right under this name (?!). |
383 | Well, it starts out with a send right for its task |
384 | port, and inherits the bootstrap and exception ports |
385 | from us. */ |
386 | mach_port_t childport; |
387 | mach_msg_type_name_t poly; |
388 | assert (__mach_port_extract_right (newtask, portnames[i], |
389 | MACH_MSG_TYPE_COPY_SEND, |
390 | &childport, |
391 | &poly) == 0 |
392 | && childport == insert |
393 | && __mach_port_deallocate (__mach_task_self (), |
394 | childport) == 0); |
395 | break; |
396 | } |
397 | |
398 | case KERN_INVALID_CAPABILITY: |
399 | /* The port just died. It was a send right, |
400 | and now it's a dead name. */ |
401 | goto allocate_dead_name; |
402 | |
403 | default: |
404 | LOSE; |
405 | break; |
406 | |
407 | case KERN_SUCCESS: |
408 | /* Give the child as many user references as we have. */ |
409 | if (refs > 1 |
410 | && (err = __mach_port_mod_refs (newtask, |
411 | portnames[i], |
412 | MACH_PORT_RIGHT_SEND, |
413 | refs - 1))) |
414 | LOSE; |
415 | } |
416 | } |
417 | } |
418 | |
419 | /* Unlock the standard port cells. The child must unlock its own |
420 | copies too. */ |
421 | for (i = 0; i < _hurd_nports; ++i) |
422 | __spin_unlock (&_hurd_ports[i].lock); |
423 | ports_locked = 0; |
424 | |
425 | /* All state has now been copied from the parent. It is safe to |
426 | resume other parent threads. */ |
427 | resume_threads (); |
428 | |
429 | /* Create the child main user thread and signal thread. */ |
430 | if ((err = __thread_create (newtask, &thread)) |
431 | || (err = __thread_create (newtask, &sigthread))) |
432 | LOSE; |
433 | |
434 | /* Insert send rights for those threads. We previously allocated |
435 | dead name rights with the names we want to give the thread ports |
436 | in the child as placeholders. Now deallocate them so we can use |
437 | the names. */ |
438 | if ((err = __mach_port_deallocate (newtask, ss->thread)) |
439 | || (err = __mach_port_insert_right (newtask, ss->thread, |
440 | thread, |
441 | MACH_MSG_TYPE_COPY_SEND))) |
442 | LOSE; |
443 | /* XXX consumed? (_hurd_sigthread is no more) */ |
444 | if (thread_refs > 1 |
445 | && (err = __mach_port_mod_refs (newtask, ss->thread, |
446 | MACH_PORT_RIGHT_SEND, |
447 | thread_refs - 1))) |
448 | LOSE; |
449 | if ((_hurd_msgport_thread != MACH_PORT_NULL) /* Let user have none. */ |
450 | && ((err = __mach_port_deallocate (newtask, _hurd_msgport_thread)) |
451 | || (err = __mach_port_insert_right (newtask, |
452 | _hurd_msgport_thread, |
453 | sigthread, |
454 | MACH_MSG_TYPE_COPY_SEND)))) |
455 | LOSE; |
456 | if (sigthread_refs > 1 |
457 | && (err = __mach_port_mod_refs (newtask, _hurd_msgport_thread, |
458 | MACH_PORT_RIGHT_SEND, |
459 | sigthread_refs - 1))) |
460 | LOSE; |
461 | |
462 | /* This seems like a convenient juncture to copy the proc server's |
463 | idea of what addresses our argv and envp are found at from the |
464 | parent into the child. Since we happen to know that the child |
465 | shares our memory image, it is we who should do this copying. */ |
466 | { |
467 | vm_address_t argv, envp; |
468 | err = (__USEPORT (PROC, __proc_get_arg_locations (port, &argv, &envp)) |
469 | ?: __proc_set_arg_locations (newproc, argv, envp)); |
470 | if (err) |
471 | LOSE; |
472 | } |
473 | |
474 | /* Set the child signal thread up to run the msgport server function |
475 | using the same signal thread stack copied from our address space. |
476 | We fetch the state before longjmp'ing it so that miscellaneous |
477 | registers not affected by longjmp (such as i386 segment registers) |
478 | are in their normal default state. */ |
479 | statecount = MACHINE_THREAD_STATE_COUNT; |
480 | if (err = __thread_get_state (_hurd_msgport_thread, |
481 | MACHINE_THREAD_STATE_FLAVOR, |
482 | (natural_t *) &state, &statecount)) |
483 | LOSE; |
484 | |
485 | MACHINE_THREAD_STATE_SETUP_CALL(&state, |
486 | __hurd_sigthread_stack_base, |
487 | __hurd_sigthread_stack_end - __hurd_sigthread_stack_base, |
488 | (uintptr_t) _hurd_msgport_receive); |
489 | |
490 | /* Do special signal thread setup for TLS if needed. */ |
491 | if (err = _hurd_tls_fork (sigthread, _hurd_msgport_thread, &state)) |
492 | LOSE; |
493 | |
494 | if (err = __thread_set_state (sigthread, MACHINE_THREAD_STATE_FLAVOR, |
495 | (natural_t *) &state, statecount)) |
496 | LOSE; |
497 | /* We do not thread_resume SIGTHREAD here because the child |
498 | fork needs to do more setup before it can take signals. */ |
499 | |
500 | /* Set the child user thread up to return 1 from the setjmp above. */ |
501 | _hurd_longjmp_thread_state (&state, env, 1); |
502 | |
503 | /* Do special thread setup for TLS if needed. */ |
504 | if (err = _hurd_tls_fork (thread, ss->thread, &state)) |
505 | LOSE; |
506 | |
507 | if (err = __thread_set_state (thread, MACHINE_THREAD_STATE_FLAVOR, |
508 | (natural_t *) &state, statecount)) |
509 | LOSE; |
510 | |
511 | /* Get the PID of the child from the proc server. We must do this |
512 | before calling proc_child below, because at that point any |
513 | authorized POSIX.1 process may kill the child task with SIGKILL. */ |
514 | if (err = __USEPORT (PROC, __proc_task2pid (port, newtask, &pid))) |
515 | LOSE; |
516 | |
517 | /* Register the child with the proc server. It is important that |
518 | this be that last thing we do before starting the child thread |
519 | running. Once proc_child has been done for the task, it appears |
520 | as a POSIX.1 process. Any errors we get must be detected before |
521 | this point, and the child must have a message port so it responds |
522 | to POSIX.1 signals. */ |
523 | if (err = __USEPORT (PROC, __proc_child (port, newtask))) |
524 | LOSE; |
525 | |
526 | /* This must be the absolutely last thing we do; we can't assume that |
527 | the child will remain alive for even a moment once we do this. We |
528 | ignore errors because we have committed to the fork and are not |
529 | allowed to return them after the process becomes visible to |
530 | POSIX.1 (which happened right above when we called proc_child). */ |
531 | (void) __thread_resume (thread); |
532 | |
533 | lose: |
534 | if (ports_locked) |
535 | for (i = 0; i < _hurd_nports; ++i) |
536 | __spin_unlock (&_hurd_ports[i].lock); |
537 | |
538 | resume_threads (); |
539 | |
540 | if (newtask != MACH_PORT_NULL) |
541 | { |
542 | if (err) |
543 | __task_terminate (newtask); |
544 | __mach_port_deallocate (__mach_task_self (), newtask); |
545 | } |
546 | if (thread != MACH_PORT_NULL) |
547 | __mach_port_deallocate (__mach_task_self (), thread); |
548 | if (sigthread != MACH_PORT_NULL) |
549 | __mach_port_deallocate (__mach_task_self (), sigthread); |
550 | if (newproc != MACH_PORT_NULL) |
551 | __mach_port_deallocate (__mach_task_self (), newproc); |
552 | |
553 | if (portnames) |
554 | __vm_deallocate (__mach_task_self (), |
555 | (vm_address_t) portnames, |
556 | nportnames * sizeof (*portnames)); |
557 | if (porttypes) |
558 | __vm_deallocate (__mach_task_self (), |
559 | (vm_address_t) porttypes, |
560 | nporttypes * sizeof (*porttypes)); |
561 | if (threads) |
562 | { |
563 | for (i = 0; i < nthreads; ++i) |
564 | __mach_port_deallocate (__mach_task_self (), threads[i]); |
565 | __vm_deallocate (__mach_task_self (), |
566 | (vm_address_t) threads, |
567 | nthreads * sizeof (*threads)); |
568 | } |
569 | |
570 | /* Release malloc locks. */ |
571 | _hurd_malloc_fork_parent (); |
572 | |
573 | /* Run things that want to run in the parent to restore it to |
574 | normality. Usually prepare hooks and parent hooks are |
575 | symmetrical: the prepare hook arrests state in some way for the |
576 | fork, and the parent hook restores the state for the parent to |
577 | continue executing normally. */ |
578 | RUN_HOOK (_hurd_fork_parent_hook, ()); |
579 | } |
580 | else |
581 | { |
582 | struct hurd_sigstate *oldstates; |
583 | |
584 | /* We are the child task. Unlock the standard port cells, which were |
585 | locked in the parent when we copied its memory. The parent has |
586 | inserted send rights with the names that were in the cells then. */ |
587 | for (i = 0; i < _hurd_nports; ++i) |
588 | __spin_unlock (&_hurd_ports[i].lock); |
589 | |
590 | /* Claim our sigstate structure and unchain the rest: the |
591 | threads existed in the parent task but don't exist in this |
592 | task (the child process). Delay freeing them until later |
593 | because some of the further setup and unlocking might be |
594 | required for free to work. Before we finish cleaning up, |
595 | we will reclaim the signal thread's sigstate structure (if |
596 | it had one). */ |
597 | oldstates = _hurd_sigstates; |
598 | if (oldstates == ss) |
599 | oldstates = ss->next; |
600 | else |
601 | { |
602 | while (_hurd_sigstates->next != ss) |
603 | _hurd_sigstates = _hurd_sigstates->next; |
604 | _hurd_sigstates->next = ss->next; |
605 | } |
606 | ss->next = NULL; |
607 | _hurd_sigstates = ss; |
608 | __mutex_unlock (&_hurd_siglock); |
609 | /* Earlier on, the global sigstate may have been tainted and now needs to |
610 | be reinitialized. Nobody is interested in its present state anymore: |
611 | we're not, the signal thread will be restarted, and there are no other |
612 | threads. |
613 | |
614 | We can't simply allocate a fresh global sigstate here, as |
615 | _hurd_thread_sigstate will call malloc and that will deadlock trying |
616 | to determine the current thread's sigstate. */ |
617 | #if 0 |
618 | _hurd_thread_sigstate_init (_hurd_global_sigstate, MACH_PORT_NULL); |
619 | #else |
620 | /* Only reinitialize the lock -- otherwise we might have to do additional |
621 | setup as done in hurdsig.c:_hurdsig_init. */ |
622 | __spin_lock_init (&_hurd_global_sigstate->lock); |
623 | #endif |
624 | |
625 | /* We are one of the (exactly) two threads in this new task, we |
626 | will take the task-global signals. */ |
627 | _hurd_sigstate_set_global_rcv (ss); |
628 | |
629 | /* Fetch our new process IDs from the proc server. No need to |
630 | refetch our pgrp; it is always inherited from the parent (so |
631 | _hurd_pgrp is already correct), and the proc server will send us a |
632 | proc_newids notification when it changes. */ |
633 | err = __USEPORT (PROC, __proc_getpids (port, &_hurd_pid, &_hurd_ppid, |
634 | &_hurd_orphaned)); |
635 | |
636 | /* Forking clears the trace flag and pending masks. */ |
637 | __sigemptyset (&_hurdsig_traced); |
638 | __sigemptyset (&_hurd_global_sigstate->pending); |
639 | __sigemptyset (set: &ss->pending); |
640 | |
641 | __libc_unwind_link_after_fork (); |
642 | |
643 | /* Release malloc locks. */ |
644 | _hurd_malloc_fork_child (); |
645 | call_function_static_weak (__malloc_fork_unlock_child); |
646 | |
647 | /* Run things that want to run in the child task to set up. */ |
648 | RUN_HOOK (_hurd_fork_child_hook, ()); |
649 | |
650 | /* Set up proc server-assisted fault recovery for the signal thread. */ |
651 | _hurdsig_fault_init (); |
652 | |
653 | /* Start the signal thread listening on the message port. */ |
654 | if (!err) |
655 | err = __thread_resume (_hurd_msgport_thread); |
656 | |
657 | /* Reclaim the signal thread's sigstate structure and free the |
658 | other old sigstate structures. */ |
659 | while (oldstates != NULL) |
660 | { |
661 | struct hurd_sigstate *next = oldstates->next; |
662 | |
663 | if (oldstates->thread == _hurd_msgport_thread) |
664 | { |
665 | /* If we have a second signal state structure then we |
666 | must have been through here before--not good. */ |
667 | assert (_hurd_sigstates->next == 0); |
668 | _hurd_sigstates->next = oldstates; |
669 | oldstates->next = 0; |
670 | } |
671 | else |
672 | free (ptr: oldstates); |
673 | |
674 | oldstates = next; |
675 | } |
676 | |
677 | /* XXX what to do if we have any errors here? */ |
678 | |
679 | pid = 0; |
680 | } |
681 | |
682 | /* Unlock things we locked before creating the child task. |
683 | They are locked in both the parent and child tasks. */ |
684 | { |
685 | void *const *p; |
686 | for (p = symbol_set_first_element (_hurd_fork_locks); |
687 | ! symbol_set_end_p (_hurd_fork_locks, p); |
688 | ++p) |
689 | __mutex_unlock (*p); |
690 | } |
691 | |
692 | _hurd_critical_section_unlock (ss); |
693 | if (err == EINTR) |
694 | /* Got a signal while inside an RPC of the critical section, retry again */ |
695 | goto retry; |
696 | |
697 | return err ? __hurd_fail (err) : pid; |
698 | } |
699 | libc_hidden_def (_Fork) |
700 | |