x86_64: Fix machdep.smp_active sysctl type.
[dragonfly.git] / lib / libc_r / uthread / uthread_fork.c
blob7188a05d4915fea2059da0ead05982b64f545de6
1 /*
2 * Copyright (c) 1995-1998 John Birrell <jb@cimlogic.com.au>
3 * All rights reserved.
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
7 * are met:
8 * 1. Redistributions of source code must retain the above copyright
9 * notice, this list of conditions and the following disclaimer.
10 * 2. Redistributions in binary form must reproduce the above copyright
11 * notice, this list of conditions and the following disclaimer in the
12 * documentation and/or other materials provided with the distribution.
13 * 3. All advertising materials mentioning features or use of this software
14 * must display the following acknowledgement:
15 * This product includes software developed by John Birrell.
16 * 4. Neither the name of the author nor the names of any co-contributors
17 * may be used to endorse or promote products derived from this software
18 * without specific prior written permission.
20 * THIS SOFTWARE IS PROVIDED BY JOHN BIRRELL AND CONTRIBUTORS ``AS IS'' AND
21 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
22 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
23 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
24 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
25 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
26 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
27 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
28 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
29 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
30 * SUCH DAMAGE.
32 * $FreeBSD: src/lib/libc_r/uthread/uthread_fork.c,v 1.19.2.7 2002/10/22 14:44:03 fjoe Exp $
35 #include <sys/syscall.h>
36 #include <errno.h>
37 #include <string.h>
38 #include <stdlib.h>
39 #include <unistd.h>
40 #include <fcntl.h>
41 #include <pthread.h>
42 #include "pthread_private.h"
44 pid_t
45 _fork(void)
47 struct pthread *curthread = _get_curthread();
48 struct pthread_atfork *af;
49 int i;
50 pid_t ret;
51 pthread_t pthread;
52 pthread_t pthread_save;
55 * Defer signals to protect the scheduling queues from access
56 * by the signal handler:
58 _thread_kern_sig_defer();
60 _pthread_mutex_lock(&_atfork_mutex);
62 /* Run down atfork prepare handlers. */
63 TAILQ_FOREACH_REVERSE(af, &_atfork_list, atfork_head, qe) {
64 if (af->prepare != NULL)
65 af->prepare();
68 /* Fork a new process: */
69 if ((ret = __syscall(SYS_fork)) != 0) {
70 /* Run down atfork parent handlers. */
71 TAILQ_FOREACH(af, &_atfork_list, qe) {
72 if (af->parent != NULL)
73 af->parent();
75 _pthread_mutex_unlock(&_atfork_mutex);
76 } else {
77 /* Close the pthread kernel pipe: */
78 __sys_close(_thread_kern_pipe[0]);
79 __sys_close(_thread_kern_pipe[1]);
81 /* Reset signals pending for the running thread: */
82 sigemptyset(&curthread->sigpend);
84 _thread_mksigpipe();
86 /* Reinitialize the GC mutex: */
87 if (_mutex_reinit(&_gc_mutex) != 0) {
88 /* Abort this application: */
89 PANIC("Cannot initialize GC mutex for forked process");
91 /* Reinitialize the GC condition variable: */
92 else if (_cond_reinit(&_gc_cond) != 0) {
93 /* Abort this application: */
94 PANIC("Cannot initialize GC condvar for forked process");
96 /* Initialize the ready queue: */
97 else if (_pq_init(&_readyq) != 0) {
98 /* Abort this application: */
99 PANIC("Cannot initialize priority ready queue.");
100 } else {
102 * Enter a loop to remove all threads other than
103 * the running thread from the thread list:
105 pthread = TAILQ_FIRST(&_thread_list);
106 while (pthread != NULL) {
107 /* Save the thread to be freed: */
108 pthread_save = pthread;
111 * Advance to the next thread before
112 * destroying the current thread:
114 pthread = TAILQ_NEXT(pthread, tle);
116 /* Make sure this isn't the running thread: */
117 if (pthread_save != curthread) {
118 /* Remove this thread from the list: */
119 TAILQ_REMOVE(&_thread_list,
120 pthread_save, tle);
122 if (pthread_save->attr.stackaddr_attr ==
123 NULL && pthread_save->stack != NULL) {
124 if (pthread_save->attr.stacksize_attr
125 == PTHREAD_STACK_DEFAULT) {
127 * Default-size stack.
128 * Cache it:
130 struct stack *spare_stack;
132 spare_stack
133 = (pthread_save->stack
134 + PTHREAD_STACK_DEFAULT
135 - sizeof(struct stack));
136 SLIST_INSERT_HEAD(&_stackq,
137 spare_stack, qe);
138 } else
140 * Free the stack of
141 * the dead thread:
143 free(pthread_save->stack);
146 if (pthread_save->specific_data != NULL)
147 free(pthread_save->specific_data);
149 if (pthread_save->poll_data.fds != NULL)
150 free(pthread_save->poll_data.fds);
152 _rtld_free_tls(pthread_save->tcb);
153 free(pthread_save);
157 /* Treat the current thread as the initial thread: */
158 _thread_initial = curthread;
160 /* Re-init the dead thread list: */
161 TAILQ_INIT(&_dead_list);
163 /* Re-init the waiting and work queues. */
164 TAILQ_INIT(&_waitingq);
165 TAILQ_INIT(&_workq);
167 /* Re-init the threads mutex queue: */
168 TAILQ_INIT(&curthread->mutexq);
170 /* No spinlocks yet: */
171 _spinblock_count = 0;
173 /* Don't queue signals yet: */
174 _queue_signals = 0;
176 /* Initialize the scheduling switch hook routine: */
177 _sched_switch_hook = NULL;
179 /* Clear out any locks in the file descriptor table: */
180 for (i = 0; i < _thread_dtablesize; i++) {
181 if (_thread_fd_table[i] != NULL) {
182 /* Initialise the file locks: */
183 memset(&_thread_fd_table[i]->lock, 0,
184 sizeof(_thread_fd_table[i]->lock));
185 _thread_fd_table[i]->r_owner = NULL;
186 _thread_fd_table[i]->w_owner = NULL;
187 _thread_fd_table[i]->r_fname = NULL;
188 _thread_fd_table[i]->w_fname = NULL;
189 _thread_fd_table[i]->r_lineno = 0;
190 _thread_fd_table[i]->w_lineno = 0;
191 _thread_fd_table[i]->r_lockcount = 0;
192 _thread_fd_table[i]->w_lockcount = 0;
194 /* Initialise the read/write queues: */
195 TAILQ_INIT(&_thread_fd_table[i]->r_queue);
196 TAILQ_INIT(&_thread_fd_table[i]->w_queue);
200 /* Run down atfork child handlers. */
201 TAILQ_FOREACH(af, &_atfork_list, qe) {
202 if (af->child != NULL)
203 af->child();
205 _mutex_reinit(&_atfork_mutex);
209 * Undefer and handle pending signals, yielding if necessary:
211 _thread_kern_sig_undefer();
213 /* Return the process ID: */
214 return (ret);
217 __strong_reference(_fork, fork);