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. 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
32 * $FreeBSD: src/lib/libc_r/uthread/uthread_create.c,v 1.24.2.6 2003/01/08 05:04:26 fjoe Exp $
41 #include <sys/param.h>
43 #include <machine/reg.h>
45 #include "pthread_private.h"
46 #include "libc_private.h"
48 static u_int64_t next_uniqueid = 1;
50 #define OFF(f) offsetof(struct pthread, f)
51 int _thread_next_offset = OFF(tle.tqe_next);
52 int _thread_uniqueid_offset = OFF(uniqueid);
53 int _thread_state_offset = OFF(state);
54 int _thread_name_offset = OFF(name);
55 int _thread_ctx_offset = OFF(ctx);
58 int _thread_PS_RUNNING_value = PS_RUNNING;
59 int _thread_PS_DEAD_value = PS_DEAD;
61 __weak_reference(_pthread_create, pthread_create);
64 _pthread_create(pthread_t *thread, const pthread_attr_t *attr,
65 void *(*start_routine) (void *), void *arg)
67 struct pthread *curthread = _get_curthread();
68 struct itimerval itimer;
80 * Locking functions in libc are required when there are
81 * threads other than the initial thread.
85 /* Allocate memory for the thread structure: */
86 if ((new_thread = (pthread_t) malloc(sizeof(struct pthread))) == NULL) {
87 /* Insufficient memory to create a thread: */
90 /* Check if default thread attributes are required: */
91 if (attr == NULL || *attr == NULL) {
92 /* Use the default thread attributes: */
93 pattr = &pthread_attr_default;
97 /* Check if a stack was specified in the thread attributes: */
98 if ((stack = pattr->stackaddr_attr) != NULL) {
100 /* Allocate memory for a default-size stack: */
101 else if (pattr->stacksize_attr == PTHREAD_STACK_DEFAULT) {
102 struct stack *spare_stack;
104 /* Allocate or re-use a default-size stack. */
107 * Use the garbage collector mutex for synchronization
108 * of the spare stack list.
110 if (pthread_mutex_lock(&_gc_mutex) != 0)
111 PANIC("Cannot lock gc mutex");
113 if ((spare_stack = SLIST_FIRST(&_stackq)) != NULL) {
114 /* Use the spare stack. */
115 SLIST_REMOVE_HEAD(&_stackq, qe);
117 /* Unlock the garbage collector mutex. */
118 if (pthread_mutex_unlock(&_gc_mutex) != 0)
119 PANIC("Cannot unlock gc mutex");
121 stack = sizeof(struct stack)
122 + (void *) spare_stack
123 - PTHREAD_STACK_DEFAULT;
125 /* Allocate a new stack. */
126 stack = _next_stack + PTHREAD_STACK_GUARD;
129 * Even if stack allocation fails, we don't want
130 * to try to use this location again, so
131 * unconditionally decrement _next_stack. Under
132 * normal operating conditions, the most likely
133 * reason for an mmap() error is a stack
134 * overflow of the adjacent thread stack.
136 _next_stack -= (PTHREAD_STACK_DEFAULT
137 + PTHREAD_STACK_GUARD);
139 /* Unlock the garbage collector mutex. */
140 if (pthread_mutex_unlock(&_gc_mutex) != 0)
141 PANIC("Cannot unlock gc mutex");
144 if (mmap(stack, PTHREAD_STACK_DEFAULT,
145 PROT_READ | PROT_WRITE, MAP_STACK,
146 -1, 0) == MAP_FAILED) {
153 * The user wants a stack of a particular size. Lets hope they
154 * really know what they want, and simply malloc the stack.
156 else if ((stack = (void *) malloc(pattr->stacksize_attr))
158 /* Insufficient memory to create a thread: */
163 /* Check for errors: */
166 /* Initialise the thread structure: */
167 memset(new_thread, 0, sizeof(struct pthread));
168 new_thread->slice_usec = -1;
169 new_thread->stack = stack;
170 new_thread->start_routine = start_routine;
171 new_thread->arg = arg;
173 new_thread->cancelflags = PTHREAD_CANCEL_ENABLE |
174 PTHREAD_CANCEL_DEFERRED;
177 * Write a magic value to the thread structure
178 * to help identify valid ones:
180 new_thread->magic = PTHREAD_MAGIC;
182 /* Initialise the thread for signals: */
183 new_thread->sigmask = curthread->sigmask;
184 new_thread->sigmask_seqno = 0;
186 /* Initialize the signal frame: */
187 new_thread->curframe = NULL;
189 /* Initialise the jump buffer: */
190 _setjmp(new_thread->ctx.jb);
193 * Set up new stack frame so that it looks like it
194 * returned from a longjmp() to the beginning of
197 SET_RETURN_ADDR_JB(new_thread->ctx.jb, _thread_start);
199 /* The stack starts high and builds down: */
200 SET_STACK_JB(new_thread->ctx.jb,
201 (long)new_thread->stack + pattr->stacksize_attr
204 /* Copy the thread attributes: */
205 memcpy(&new_thread->attr, pattr, sizeof(struct pthread_attr));
208 * Check if this thread is to inherit the scheduling
209 * attributes from its parent:
211 if (new_thread->attr.flags & PTHREAD_INHERIT_SCHED) {
212 /* Copy the scheduling attributes: */
213 new_thread->base_priority =
214 curthread->base_priority &
215 ~PTHREAD_SIGNAL_PRIORITY;
216 new_thread->attr.prio =
217 curthread->base_priority &
218 ~PTHREAD_SIGNAL_PRIORITY;
219 new_thread->attr.sched_policy =
220 curthread->attr.sched_policy;
223 * Use just the thread priority, leaving the
224 * other scheduling attributes as their
227 new_thread->base_priority =
228 new_thread->attr.prio;
230 new_thread->active_priority = new_thread->base_priority;
231 new_thread->inherited_priority = 0;
233 /* Initialize joiner to NULL (no joiner): */
234 new_thread->joiner = NULL;
236 /* Initialize the mutex queue: */
237 TAILQ_INIT(&new_thread->mutexq);
239 /* Initialise hooks in the thread structure: */
240 new_thread->specific_data = NULL;
241 new_thread->cleanup = NULL;
242 new_thread->flags = 0;
243 new_thread->poll_data.nfds = 0;
244 new_thread->poll_data.fds = NULL;
245 new_thread->continuation = NULL;
248 * Defer signals to protect the scheduling queues
249 * from access by the signal handler:
251 _thread_kern_sig_defer();
254 * Initialise the unique id which GDB uses to
257 new_thread->uniqueid = next_uniqueid++;
260 * Check if the garbage collector thread
261 * needs to be started.
263 f_gc = (TAILQ_FIRST(&_thread_list) == _thread_initial);
265 /* Add the thread to the linked list of all threads: */
266 TAILQ_INSERT_HEAD(&_thread_list, new_thread, tle);
268 if (pattr->suspend == PTHREAD_CREATE_SUSPENDED) {
269 new_thread->flags |= PTHREAD_FLAGS_SUSPENDED;
270 new_thread->state = PS_SUSPENDED;
272 new_thread->state = PS_RUNNING;
273 PTHREAD_PRIOQ_INSERT_TAIL(new_thread);
277 * Undefer and handle pending signals, yielding
280 _thread_kern_sig_undefer();
282 /* Return a pointer to the thread structure: */
283 (*thread) = new_thread;
286 /* Install the scheduling timer: */
287 itimer.it_interval.tv_sec = 0;
288 itimer.it_interval.tv_usec = _clock_res_usec;
289 itimer.it_value = itimer.it_interval;
290 if (setitimer(_ITIMER_SCHED_TIMER, &itimer,
292 PANIC("Cannot set interval timer");
295 /* Schedule the new user thread: */
296 _thread_kern_sched(NULL);
299 * Start a garbage collector thread
302 if (f_gc && pthread_create(&gc_thread,NULL,
303 _thread_gc,NULL) != 0)
304 PANIC("Can't create gc thread");
309 /* Return the status: */
316 struct pthread *curthread = _get_curthread();
318 /* We just left the scheduler via longjmp: */
319 _thread_kern_in_sched = 0;
321 /* Run the current thread's start routine with argument: */
322 pthread_exit(curthread->start_routine(curthread->arg));
324 /* This point should never be reached. */
325 PANIC("Thread has resumed after exit");