1 /* $OpenBSD: uthread_fork.c,v 1.11 2003/08/06 21:08:05 millert Exp $ */
2 /*
3 * Copyright (c) 1995-1998 John Birrell <jb@cimlogic.com.au>
4 * All rights reserved.
5 *
6 * Redistribution and use in source and binary forms, with or without
7 * modification, are permitted provided that the following conditions
8 * are met:
9 * 1. Redistributions of source code must retain the above copyright
10 * notice, this list of conditions and the following disclaimer.
11 * 2. Redistributions in binary form must reproduce the above copyright
12 * notice, this list of conditions and the following disclaimer in the
13 * documentation and/or other materials provided with the distribution.
14 * 3. All advertising materials mentioning features or use of this software
15 * must display the following acknowledgement:
16 * This product includes software developed by John Birrell.
17 * 4. Neither the name of the author nor the names of any co-contributors
18 * may be used to endorse or promote products derived from this software
19 * without specific prior written permission.
20 *
21 * THIS SOFTWARE IS PROVIDED BY JOHN BIRRELL AND CONTRIBUTORS ``AS IS'' AND
22 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
23 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
24 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
25 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
26 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
27 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
28 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
29 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
30 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
31 * SUCH DAMAGE.
32 *
33 * $FreeBSD: uthread_fork.c,v 1.14 1999/09/29 15:18:38 marcel Exp $
34 */
35 #include <errno.h>
36 #include <string.h>
37 #include <unistd.h>
38 #include <fcntl.h>
39 #include <stdlib.h>
40 #ifdef _THREAD_SAFE
41 #include <pthread.h>
42 #include "pthread_private.h"
43
44 pid_t
fork(void)45 fork(void)
46 {
47 struct pthread *curthread = _get_curthread();
48 int i, flags;
49 pid_t ret;
50 pthread_t pthread;
51
52 /*
53 * Defer signals to protect the scheduling queues from access
54 * by the signal handler:
55 */
56 _thread_kern_sig_defer();
57
58 /* Fork a new process: */
59 if ((ret = _thread_sys_fork()) != 0) {
60 /* Parent process or error. Nothing to do here. */
61 } else {
62 /* Close the pthread kernel pipe: */
63 _thread_sys_close(_thread_kern_pipe[0]);
64 _thread_sys_close(_thread_kern_pipe[1]);
65
66 /* Reset signals pending for the running thread: */
67 sigemptyset(&curthread->sigpend);
68
69 /*
70 * Create a pipe that is written to by the signal handler to
71 * prevent signals being missed in calls to
72 * _thread_sys_select:
73 */
74 if (_thread_sys_pipe(_thread_kern_pipe) != 0) {
75 /* Cannot create pipe, so abort: */
76 PANIC("Cannot create pthread kernel pipe for forked process");
77 }
78 /* Get the flags for the read pipe: */
79 else if ((flags = _thread_sys_fcntl(_thread_kern_pipe[0], F_GETFL, NULL)) == -1) {
80 /* Abort this application: */
81 abort();
82 }
83 /* Make the read pipe non-blocking: */
84 else if (_thread_sys_fcntl(_thread_kern_pipe[0], F_SETFL, flags | O_NONBLOCK) == -1) {
85 /* Abort this application: */
86 abort();
87 }
88 /* Get the flags for the write pipe: */
89 else if ((flags = _thread_sys_fcntl(_thread_kern_pipe[1], F_GETFL, NULL)) == -1) {
90 /* Abort this application: */
91 abort();
92 }
93 /* Make the write pipe non-blocking: */
94 else if (_thread_sys_fcntl(_thread_kern_pipe[1], F_SETFL, flags | O_NONBLOCK) == -1) {
95 /* Abort this application: */
96 abort();
97 }
98 /* Reinitialize the GC mutex: */
99 else if (_mutex_reinit(&_gc_mutex) != 0) {
100 /* Abort this application: */
101 PANIC("Cannot initialize GC mutex for forked process");
102 }
103 /* Reinitialize the GC condition variable: */
104 else if (_cond_reinit(&_gc_cond) != 0) {
105 /* Abort this application: */
106 PANIC("Cannot initialize GC condvar for forked process");
107 }
108 /* Initialize the ready queue: */
109 else if (_pq_init(&_readyq) != 0) {
110 /* Abort this application: */
111 PANIC("Cannot initialize priority ready queue.");
112 } else {
113 /*
114 * Enter a loop to remove all threads other than
115 * the running thread from the thread list:
116 */
117 while ((pthread = TAILQ_FIRST(&_thread_list)) != NULL) {
118 TAILQ_REMOVE(&_thread_list, pthread, tle);
119
120 /* Make sure this isn't the running thread: */
121 if (pthread != curthread) {
122 /* XXX should let gc do all this. */
123 if(pthread->stack != NULL)
124 _thread_stack_free(pthread->stack);
125
126 if (pthread->specific_data != NULL)
127 free(pthread->specific_data);
128
129 if (pthread->poll_data.fds != NULL)
130 free(pthread->poll_data.fds);
131
132 free(pthread);
133 }
134 }
135
136 /* Restore the running thread */
137 TAILQ_INSERT_HEAD(&_thread_list, curthread, tle);
138
139 /* Re-init the dead thread list: */
140 TAILQ_INIT(&_dead_list);
141
142 /* Re-init the waiting and work queues. */
143 TAILQ_INIT(&_waitingq);
144 TAILQ_INIT(&_workq);
145
146 /* Re-init the threads mutex queue: */
147 TAILQ_INIT(&curthread->mutexq);
148
149 /* No spinlocks yet: */
150 _spinblock_count = 0;
151
152 /* Don't queue signals yet: */
153 _queue_signals = 0;
154
155 /* Initialize signal handling: */
156 _thread_sig_init();
157
158 /* Initialize the scheduling switch hook routine: */
159 _sched_switch_hook = NULL;
160
161 /* Clear out any locks in the file descriptor table: */
162 for (i = 0; i < _thread_dtablesize; i++) {
163 if (_thread_fd_table[i] != NULL) {
164 /* Initialise the file locks: */
165 _SPINLOCK_INIT(&_thread_fd_table[i]->lock);
166 _thread_fd_table[i]->r_owner = NULL;
167 _thread_fd_table[i]->w_owner = NULL;
168 _thread_fd_table[i]->r_fname = NULL;
169 _thread_fd_table[i]->w_fname = NULL;
170 _thread_fd_table[i]->r_lineno = 0;
171 _thread_fd_table[i]->w_lineno = 0;
172 _thread_fd_table[i]->r_lockcount = 0;
173 _thread_fd_table[i]->w_lockcount = 0;
174
175 /* Initialise the read/write queues: */
176 TAILQ_INIT(&_thread_fd_table[i]->r_queue);
177 TAILQ_INIT(&_thread_fd_table[i]->w_queue);
178 }
179 }
180 }
181 }
182
183 /*
184 * Undefer and handle pending signals, yielding if necessary:
185 */
186 _thread_kern_sig_undefer();
187
188 /* Return the process ID: */
189 return (ret);
190 }
191 #endif
192