2 * Copyright (c) 1995-1998 John Birrell <jb@cimlogic.com.au>
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
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. Neither the name of the author nor the names of any co-contributors
14 * may be used to endorse or promote products derived from this software
15 * without specific prior written permission.
17 * THIS SOFTWARE IS PROVIDED BY JOHN BIRRELL AND CONTRIBUTORS ``AS IS'' AND
18 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
19 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
20 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
21 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
22 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
23 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
24 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
25 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
26 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
31 #include <sys/param.h>
38 #include "pthread_private.h"
40 static void free_thread_resources(struct pthread *thread);
42 __weak_reference(_fork, fork);
47 struct pthread *curthread = _get_curthread();
48 struct pthread_atfork *af;
49 int i, flags, use_deadlist = 0;
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)
68 /* Fork a new process: */
69 if ((ret = __sys_fork()) != 0) {
70 /* Run down atfork parent handlers. */
71 TAILQ_FOREACH(af, &_atfork_list, qe) {
72 if (af->parent != NULL)
75 _pthread_mutex_unlock(&_atfork_mutex);
78 /* Close the pthread kernel pipe: */
79 __sys_close(_thread_kern_pipe[0]);
80 __sys_close(_thread_kern_pipe[1]);
82 /* Reset signals pending for the running thread: */
83 sigemptyset(&curthread->sigpend);
86 * Create a pipe that is written to by the signal handler to
87 * prevent signals being missed in calls to
90 if (__sys_pipe(_thread_kern_pipe) != 0) {
91 /* Cannot create pipe, so abort: */
92 PANIC("Cannot create pthread kernel pipe for forked process");
94 /* Get the flags for the read pipe: */
95 else if ((flags = __sys_fcntl(_thread_kern_pipe[0], F_GETFL, NULL)) == -1) {
96 /* Abort this application: */
99 /* Make the read pipe non-blocking: */
100 else if (__sys_fcntl(_thread_kern_pipe[0], F_SETFL, flags | O_NONBLOCK) == -1) {
101 /* Abort this application: */
104 /* Get the flags for the write pipe: */
105 else if ((flags = __sys_fcntl(_thread_kern_pipe[1], F_GETFL, NULL)) == -1) {
106 /* Abort this application: */
109 /* Make the write pipe non-blocking: */
110 else if (__sys_fcntl(_thread_kern_pipe[1], F_SETFL, flags | O_NONBLOCK) == -1) {
111 /* Abort this application: */
114 /* Reinitialize the GC mutex: */
115 else if (_mutex_reinit(&_gc_mutex) != 0) {
116 /* Abort this application: */
117 PANIC("Cannot initialize GC mutex for forked process");
119 /* Reinitialize the GC condition variable: */
120 else if (_cond_reinit(&_gc_cond) != 0) {
121 /* Abort this application: */
122 PANIC("Cannot initialize GC condvar for forked process");
124 /* Initialize the ready queue: */
125 else if (_pq_init(&_readyq) != 0) {
126 /* Abort this application: */
127 PANIC("Cannot initialize priority ready queue.");
130 * Enter a loop to remove all threads other than
131 * the running thread from the thread list:
133 if ((pthread = TAILQ_FIRST(&_thread_list)) == NULL) {
134 pthread = TAILQ_FIRST(&_dead_list);
137 while (pthread != NULL) {
138 /* Save the thread to be freed: */
139 pthread_save = pthread;
142 * Advance to the next thread before
143 * destroying the current thread:
145 if (use_deadlist != 0)
146 pthread = TAILQ_NEXT(pthread, dle);
148 pthread = TAILQ_NEXT(pthread, tle);
150 /* Make sure this isn't the running thread: */
151 if (pthread_save != curthread) {
153 * Remove this thread from the
156 if (use_deadlist != 0)
157 TAILQ_REMOVE(&_thread_list,
160 TAILQ_REMOVE(&_thread_list,
163 free_thread_resources(pthread_save);
167 * Switch to the deadlist when the active
168 * thread list has been consumed. This can't
169 * be at the top of the loop because it is
170 * used to determine to which list the thread
171 * belongs (when it is removed from the list).
173 if (pthread == NULL) {
174 pthread = TAILQ_FIRST(&_dead_list);
179 /* Treat the current thread as the initial thread: */
180 _thread_initial = curthread;
182 /* Re-init the dead thread list: */
183 TAILQ_INIT(&_dead_list);
185 /* Re-init the waiting and work queues. */
186 TAILQ_INIT(&_waitingq);
189 /* Re-init the threads mutex queue: */
190 TAILQ_INIT(&curthread->mutexq);
192 /* No spinlocks yet: */
193 _spinblock_count = 0;
195 /* Don't queue signals yet: */
198 /* Initialize the scheduling switch hook routine: */
199 _sched_switch_hook = NULL;
201 /* Clear out any locks in the file descriptor table: */
202 for (i = 0; i < _thread_dtablesize; i++) {
203 if (_thread_fd_table[i] != NULL) {
204 /* Initialise the file locks: */
205 memset(&_thread_fd_table[i]->lock, 0,
206 sizeof(_thread_fd_table[i]->lock));
207 _thread_fd_table[i]->r_owner = NULL;
208 _thread_fd_table[i]->w_owner = NULL;
209 _thread_fd_table[i]->r_fname = NULL;
210 _thread_fd_table[i]->w_fname = NULL;
211 _thread_fd_table[i]->r_lineno = 0;;
212 _thread_fd_table[i]->w_lineno = 0;;
213 _thread_fd_table[i]->r_lockcount = 0;;
214 _thread_fd_table[i]->w_lockcount = 0;;
216 /* Initialise the read/write queues: */
217 TAILQ_INIT(&_thread_fd_table[i]->r_queue);
218 TAILQ_INIT(&_thread_fd_table[i]->w_queue);
222 /* Run down atfork child handlers. */
223 TAILQ_FOREACH(af, &_atfork_list, qe) {
224 if (af->child != NULL)
227 _mutex_reinit(&_atfork_mutex);
232 * Undefer and handle pending signals, yielding if necessary:
234 _thread_kern_sig_undefer();
236 /* Return the process ID: */
241 free_thread_resources(struct pthread *thread)
244 /* Check to see if the threads library allocated the stack. */
245 if ((thread->attr.stackaddr_attr == NULL) && (thread->stack != NULL)) {
247 * Since this is being called from fork, we are currently single
248 * threaded so there is no need to protect the call to
249 * _thread_stack_free() with _gc_mutex.
251 _thread_stack_free(thread->stack, thread->attr.stacksize_attr,
252 thread->attr.guardsize_attr);
255 if (thread->specific != NULL)
256 free(thread->specific);
258 if (thread->poll_data.fds != NULL)
259 free(thread->poll_data.fds);