1 /* $OpenBSD: uthread_create.c,v 1.21 2005/01/23 19:23:47 kettenis 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_create.c,v 1.19 1999/08/28 00:03:28 peter Exp $
34 */
35 #include <errno.h>
36 #include <stdlib.h>
37 #include <string.h>
38 #include <fcntl.h>
39 #include <unistd.h>
40 #include <stddef.h>
41 #include <sys/time.h>
42 #include <sys/types.h>
43 #include <sys/mman.h>
44 #ifdef _THREAD_SAFE
45 #include <machine/reg.h>
46 #include <pthread.h>
47 #include "pthread_private.h"
48
49 /* Symbols that help gdb find the information it needs. */
50 int _thread_next_offset = offsetof(struct pthread, tle.tqe_next);
51 int _thread_state_offset = offsetof(struct pthread, state);
52
53 int
pthread_create(pthread_t * thread,const pthread_attr_t * attr,void * (* start_routine)(void *),void * arg)54 pthread_create(pthread_t *thread, const pthread_attr_t *attr,
55 void *(*start_routine) (void *), void *arg)
56 {
57 struct pthread *curthread = _get_curthread();
58 struct itimerval itimer;
59 int f_gc = 0;
60 int ret = 0;
61 pthread_t gc_thread;
62 pthread_t new_thread;
63 pthread_attr_t pattr;
64 struct stack *stack;
65
66 if (thread == NULL)
67 return(EINVAL);
68
69 /*
70 * Locking functions in libc are required when there are
71 * threads other than the initial thread.
72 */
73 __isthreaded = 1;
74
75 /* Allocate memory for the thread structure: */
76 if ((new_thread = (pthread_t) malloc(sizeof(struct pthread))) == NULL) {
77 /* Insufficient memory to create a thread: */
78 ret = EAGAIN;
79 } else {
80 /* Check if default thread attributes are required: */
81 if (attr == NULL || *attr == NULL) {
82 /* Use the default thread attributes: */
83 pattr = &pthread_attr_default;
84 } else {
85 pattr = *attr;
86 }
87 /* Check if a stack was specified in the thread attributes: */
88 if ((stack = pattr->stackaddr_attr) != NULL) {
89 }
90 /* Allocate a stack: */
91 else {
92 stack = _thread_stack_alloc(pattr->stackaddr_attr,
93 pattr->stacksize_attr);
94 if (stack == NULL) {
95 ret = EAGAIN;
96 free(new_thread);
97 }
98 }
99
100 /* Check for errors: */
101 if (ret != 0) {
102 } else {
103 /* Initialise the thread structure: */
104 memset(new_thread, 0, sizeof(struct pthread));
105 _SPINLOCK_INIT(&new_thread->lock);
106 new_thread->slice_usec = -1;
107 new_thread->sig_saved = 0;
108 new_thread->stack = stack;
109 new_thread->start_routine = start_routine;
110 new_thread->arg = arg;
111
112 new_thread->cancelflags = PTHREAD_CANCEL_ENABLE |
113 PTHREAD_CANCEL_DEFERRED;
114
115 /*
116 * Write a magic value to the thread structure
117 * to help identify valid ones:
118 */
119 new_thread->magic = PTHREAD_MAGIC;
120
121 /* Initialise the thread for signals: */
122 new_thread->sigmask = curthread->sigmask;
123
124 /*
125 * Set up new stack frame so that it 'returns' to
126 * the beginning of _thread_start() after it is
127 * switched to:
128 */
129 _thread_machdep_init(&new_thread->_machdep,
130 stack->base, stack->size, _thread_start);
131
132 /* Copy the thread attributes: */
133 memcpy(&new_thread->attr, pattr, sizeof(struct pthread_attr));
134
135 /*
136 * Check if this thread is to inherit the scheduling
137 * attributes from its parent:
138 */
139 if (new_thread->attr.flags & PTHREAD_INHERIT_SCHED) {
140 /* Copy the scheduling attributes: */
141 new_thread->base_priority =
142 curthread->base_priority &
143 ~PTHREAD_SIGNAL_PRIORITY;
144 new_thread->attr.prio =
145 curthread->base_priority &
146 ~PTHREAD_SIGNAL_PRIORITY;
147 new_thread->attr.sched_policy =
148 curthread->attr.sched_policy;
149 } else {
150 /*
151 * Use just the thread priority, leaving the
152 * other scheduling attributes as their
153 * default values:
154 */
155 new_thread->base_priority =
156 new_thread->attr.prio;
157 }
158 new_thread->active_priority = new_thread->base_priority;
159 new_thread->inherited_priority = 0;
160
161 /* Initialize joiner to NULL (no joiner): */
162 new_thread->joiner = NULL;
163
164 /* Initialize the mutex queue: */
165 TAILQ_INIT(&new_thread->mutexq);
166
167 /* Initialise hooks in the thread structure: */
168 new_thread->specific_data = NULL;
169 new_thread->cleanup = NULL;
170 new_thread->flags = 0;
171 new_thread->poll_data.nfds = 0;
172 new_thread->poll_data.fds = NULL;
173 new_thread->continuation = NULL;
174
175 /*
176 * Defer signals to protect the scheduling queues
177 * from access by the signal handler:
178 */
179 _thread_kern_sig_defer();
180
181 /*
182 * Check if the garbage collector thread
183 * needs to be started.
184 */
185 f_gc = (TAILQ_FIRST(&_thread_list) == _thread_initial);
186
187 /* Add the thread to the linked list of all threads: */
188 TAILQ_INSERT_HEAD(&_thread_list, new_thread, tle);
189
190 if (pattr->suspend == PTHREAD_CREATE_SUSPENDED)
191 new_thread->state = PS_SUSPENDED;
192 else {
193 new_thread->state = PS_RUNNING;
194 PTHREAD_PRIOQ_INSERT_TAIL(new_thread);
195 }
196
197 /*
198 * Undefer and handle pending signals, yielding
199 * if necessary.
200 */
201 _thread_kern_sig_undefer();
202
203 /* Return a pointer to the thread structure: */
204 if (thread != NULL)
205 (*thread) = new_thread;
206
207 if (f_gc != 0) {
208 /* Install the scheduling timer: */
209 itimer.it_interval.tv_sec = 0;
210 itimer.it_interval.tv_usec = _clock_res_usec;
211 itimer.it_value = itimer.it_interval;
212 if (setitimer(_ITIMER_SCHED_TIMER, &itimer,
213 NULL) != 0)
214 PANIC("Cannot set interval timer");
215 }
216
217 /* Schedule the new user thread: */
218 _thread_kern_sched(NULL);
219
220 /*
221 * Start a garbage collector thread
222 * if necessary.
223 */
224 if (f_gc && pthread_create(&gc_thread,NULL,
225 _thread_gc,NULL) != 0)
226 PANIC("Can't create gc thread");
227
228 }
229 }
230
231 /* Return the status: */
232 return (ret);
233 }
234
235 void
_thread_start(void)236 _thread_start(void)
237 {
238 struct pthread *curthread = _get_curthread();
239
240 /* We just left the scheduler via longjmp: */
241 _thread_kern_in_sched = 0;
242
243 /* Run the current thread's start routine with argument: */
244 pthread_exit(curthread->start_routine(curthread->arg));
245
246 /* This point should never be reached. */
247 PANIC("Thread has resumed after exit");
248 }
249 #endif
250