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