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 $
33 * $DragonFly: src/lib/libc_r/uthread/uthread_create.c,v 1.2 2003/06/17 04:26:48 dillon Exp $
42 #include <sys/param.h>
44 #include <machine/reg.h>
46 #include "pthread_private.h"
47 #include "libc_private.h"
49 static u_int64_t next_uniqueid = 1;
51 #define OFF(f) offsetof(struct pthread, f)
52 int _thread_next_offset = OFF(tle.tqe_next);
53 int _thread_uniqueid_offset = OFF(uniqueid);
54 int _thread_state_offset = OFF(state);
55 int _thread_name_offset = OFF(name);
56 int _thread_ctx_offset = OFF(ctx);
59 int _thread_PS_RUNNING_value = PS_RUNNING;
60 int _thread_PS_DEAD_value = PS_DEAD;
62 __weak_reference(_pthread_create, pthread_create);
65 _pthread_create(pthread_t *thread, const pthread_attr_t *attr,
66 void *(*start_routine) (void *), void *arg)
68 struct pthread *curthread = _get_curthread();
69 struct itimerval itimer;
81 * Locking functions in libc are required when there are
82 * threads other than the initial thread.
86 /* Allocate memory for the thread structure: */
87 if ((new_thread = (pthread_t) malloc(sizeof(struct pthread))) == NULL) {
88 /* Insufficient memory to create a thread: */
91 /* Check if default thread attributes are required: */
92 if (attr == NULL || *attr == NULL) {
93 /* Use the default thread attributes: */
94 pattr = &pthread_attr_default;
98 /* Check if a stack was specified in the thread attributes: */
99 if ((stack = pattr->stackaddr_attr) != NULL) {
101 /* Allocate memory for a default-size stack: */
102 else if (pattr->stacksize_attr == PTHREAD_STACK_DEFAULT) {
103 struct stack *spare_stack;
105 /* Allocate or re-use a default-size stack. */
108 * Use the garbage collector mutex for synchronization
109 * of the spare stack list.
111 if (pthread_mutex_lock(&_gc_mutex) != 0)
112 PANIC("Cannot lock gc mutex");
114 if ((spare_stack = SLIST_FIRST(&_stackq)) != NULL) {
115 /* Use the spare stack. */
116 SLIST_REMOVE_HEAD(&_stackq, qe);
118 /* Unlock the garbage collector mutex. */
119 if (pthread_mutex_unlock(&_gc_mutex) != 0)
120 PANIC("Cannot unlock gc mutex");
122 stack = sizeof(struct stack)
123 + (void *) spare_stack
124 - PTHREAD_STACK_DEFAULT;
126 /* Allocate a new stack. */
127 stack = _next_stack + PTHREAD_STACK_GUARD;
130 * Even if stack allocation fails, we don't want
131 * to try to use this location again, so
132 * unconditionally decrement _next_stack. Under
133 * normal operating conditions, the most likely
134 * reason for an mmap() error is a stack
135 * overflow of the adjacent thread stack.
137 _next_stack -= (PTHREAD_STACK_DEFAULT
138 + PTHREAD_STACK_GUARD);
140 /* Unlock the garbage collector mutex. */
141 if (pthread_mutex_unlock(&_gc_mutex) != 0)
142 PANIC("Cannot unlock gc mutex");
145 if (mmap(stack, PTHREAD_STACK_DEFAULT,
146 PROT_READ | PROT_WRITE, MAP_STACK,
147 -1, 0) == MAP_FAILED) {
154 * The user wants a stack of a particular size. Lets hope they
155 * really know what they want, and simply malloc the stack.
157 else if ((stack = (void *) malloc(pattr->stacksize_attr))
159 /* Insufficient memory to create a thread: */
164 /* Check for errors: */
167 /* Initialise the thread structure: */
168 memset(new_thread, 0, sizeof(struct pthread));
169 new_thread->slice_usec = -1;
170 new_thread->stack = stack;
171 new_thread->start_routine = start_routine;
172 new_thread->arg = arg;
174 new_thread->cancelflags = PTHREAD_CANCEL_ENABLE |
175 PTHREAD_CANCEL_DEFERRED;
178 * Write a magic value to the thread structure
179 * to help identify valid ones:
181 new_thread->magic = PTHREAD_MAGIC;
183 /* Initialise the thread for signals: */
184 new_thread->sigmask = curthread->sigmask;
185 new_thread->sigmask_seqno = 0;
187 /* Initialize the signal frame: */
188 new_thread->curframe = NULL;
190 /* Initialise the jump buffer: */
191 _setjmp(new_thread->ctx.jb);
194 * Set up new stack frame so that it looks like it
195 * returned from a longjmp() to the beginning of
198 SET_RETURN_ADDR_JB(new_thread->ctx.jb, _thread_start);
200 /* The stack starts high and builds down: */
201 SET_STACK_JB(new_thread->ctx.jb,
202 (long)new_thread->stack + pattr->stacksize_attr
205 /* Copy the thread attributes: */
206 memcpy(&new_thread->attr, pattr, sizeof(struct pthread_attr));
209 * Check if this thread is to inherit the scheduling
210 * attributes from its parent:
212 if (new_thread->attr.flags & PTHREAD_INHERIT_SCHED) {
213 /* Copy the scheduling attributes: */
214 new_thread->base_priority =
215 curthread->base_priority &
216 ~PTHREAD_SIGNAL_PRIORITY;
217 new_thread->attr.prio =
218 curthread->base_priority &
219 ~PTHREAD_SIGNAL_PRIORITY;
220 new_thread->attr.sched_policy =
221 curthread->attr.sched_policy;
224 * Use just the thread priority, leaving the
225 * other scheduling attributes as their
228 new_thread->base_priority =
229 new_thread->attr.prio;
231 new_thread->active_priority = new_thread->base_priority;
232 new_thread->inherited_priority = 0;
234 /* Initialize joiner to NULL (no joiner): */
235 new_thread->joiner = NULL;
237 /* Initialize the mutex queue: */
238 TAILQ_INIT(&new_thread->mutexq);
240 /* Initialise hooks in the thread structure: */
241 new_thread->specific_data = NULL;
242 new_thread->cleanup = NULL;
243 new_thread->flags = 0;
244 new_thread->poll_data.nfds = 0;
245 new_thread->poll_data.fds = NULL;
246 new_thread->continuation = NULL;
249 * Defer signals to protect the scheduling queues
250 * from access by the signal handler:
252 _thread_kern_sig_defer();
255 * Initialise the unique id which GDB uses to
258 new_thread->uniqueid = next_uniqueid++;
261 * Check if the garbage collector thread
262 * needs to be started.
264 f_gc = (TAILQ_FIRST(&_thread_list) == _thread_initial);
266 /* Add the thread to the linked list of all threads: */
267 TAILQ_INSERT_HEAD(&_thread_list, new_thread, tle);
269 if (pattr->suspend == PTHREAD_CREATE_SUSPENDED) {
270 new_thread->flags |= PTHREAD_FLAGS_SUSPENDED;
271 new_thread->state = PS_SUSPENDED;
273 new_thread->state = PS_RUNNING;
274 PTHREAD_PRIOQ_INSERT_TAIL(new_thread);
278 * Undefer and handle pending signals, yielding
281 _thread_kern_sig_undefer();
283 /* Return a pointer to the thread structure: */
284 (*thread) = new_thread;
287 /* Install the scheduling timer: */
288 itimer.it_interval.tv_sec = 0;
289 itimer.it_interval.tv_usec = _clock_res_usec;
290 itimer.it_value = itimer.it_interval;
291 if (setitimer(_ITIMER_SCHED_TIMER, &itimer,
293 PANIC("Cannot set interval timer");
296 /* Schedule the new user thread: */
297 _thread_kern_sched(NULL);
300 * Start a garbage collector thread
303 if (f_gc && pthread_create(&gc_thread,NULL,
304 _thread_gc,NULL) != 0)
305 PANIC("Can't create gc thread");
310 /* Return the status: */
317 struct pthread *curthread = _get_curthread();
319 /* We just left the scheduler via longjmp: */
320 _thread_kern_in_sched = 0;
322 /* Run the current thread's start routine with argument: */
323 pthread_exit(curthread->start_routine(curthread->arg));
325 /* This point should never be reached. */
326 PANIC("Thread has resumed after exit");