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