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
41 #include <machine/reg.h>
42 #include "namespace.h"
44 #include "un-namespace.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;
76 #if !defined(__ia64__)
84 * Locking functions in libc are required when there are
85 * threads other than the initial thread.
89 /* Allocate memory for the thread structure: */
90 if ((new_thread = (pthread_t) malloc(sizeof(struct pthread))) == NULL) {
91 /* Insufficient memory to create a thread: */
94 /* Check if default thread attributes are required: */
95 if (attr == NULL || *attr == NULL) {
96 /* Use the default thread attributes: */
97 pattr = &_pthread_attr_default;
101 /* Check if a stack was specified in the thread attributes: */
102 if ((stack = pattr->stackaddr_attr) != NULL) {
104 /* Allocate a stack: */
106 stack = _thread_stack_alloc(pattr->stacksize_attr,
107 pattr->guardsize_attr);
114 /* Check for errors: */
117 /* Initialise the thread structure: */
118 memset(new_thread, 0, sizeof(struct pthread));
119 new_thread->slice_usec = -1;
120 new_thread->stack = stack;
121 new_thread->start_routine = start_routine;
122 new_thread->arg = arg;
124 new_thread->cancelflags = PTHREAD_CANCEL_ENABLE |
125 PTHREAD_CANCEL_DEFERRED;
128 * Write a magic value to the thread structure
129 * to help identify valid ones:
131 new_thread->magic = PTHREAD_MAGIC;
133 /* Initialise the thread for signals: */
134 new_thread->sigmask = curthread->sigmask;
135 new_thread->sigmask_seqno = 0;
137 /* Initialize the signal frame: */
138 new_thread->curframe = NULL;
140 /* Initialise the jump buffer: */
141 _setjmp(new_thread->ctx.jb);
144 * Set up new stack frame so that it looks like it
145 * returned from a longjmp() to the beginning of
148 SET_RETURN_ADDR_JB(new_thread->ctx.jb, _thread_start);
150 #if !defined(__ia64__)
151 stackp = (long)new_thread->stack + pattr->stacksize_attr - sizeof(double);
152 #if defined(__amd64__)
155 /* The stack starts high and builds down: */
156 SET_STACK_JB(new_thread->ctx.jb, stackp);
158 SET_STACK_JB(new_thread->ctx.jb,
159 (long)new_thread->stack, pattr->stacksize_attr);
162 /* Copy the thread attributes: */
163 memcpy(&new_thread->attr, pattr, sizeof(struct pthread_attr));
166 * Check if this thread is to inherit the scheduling
167 * attributes from its parent:
169 if (new_thread->attr.flags & PTHREAD_INHERIT_SCHED) {
170 /* Copy the scheduling attributes: */
171 new_thread->base_priority =
172 curthread->base_priority &
173 ~PTHREAD_SIGNAL_PRIORITY;
174 new_thread->attr.prio =
175 curthread->base_priority &
176 ~PTHREAD_SIGNAL_PRIORITY;
177 new_thread->attr.sched_policy =
178 curthread->attr.sched_policy;
181 * Use just the thread priority, leaving the
182 * other scheduling attributes as their
185 new_thread->base_priority =
186 new_thread->attr.prio;
188 new_thread->active_priority = new_thread->base_priority;
189 new_thread->inherited_priority = 0;
191 /* Initialize joiner to NULL (no joiner): */
192 new_thread->joiner = NULL;
194 /* Initialize the mutex queue: */
195 TAILQ_INIT(&new_thread->mutexq);
197 /* Initialise hooks in the thread structure: */
198 new_thread->specific = NULL;
199 new_thread->cleanup = NULL;
200 new_thread->flags = 0;
201 new_thread->poll_data.nfds = 0;
202 new_thread->poll_data.fds = NULL;
203 new_thread->continuation = NULL;
206 * Defer signals to protect the scheduling queues
207 * from access by the signal handler:
209 _thread_kern_sig_defer();
212 * Initialise the unique id which GDB uses to
215 new_thread->uniqueid = next_uniqueid++;
218 * Check if the garbage collector thread
219 * needs to be started.
221 f_gc = (TAILQ_FIRST(&_thread_list) == _thread_initial);
223 /* Add the thread to the linked list of all threads: */
224 TAILQ_INSERT_HEAD(&_thread_list, new_thread, tle);
226 if (pattr->suspend == PTHREAD_CREATE_SUSPENDED) {
227 new_thread->flags |= PTHREAD_FLAGS_SUSPENDED;
228 new_thread->state = PS_SUSPENDED;
230 new_thread->state = PS_RUNNING;
231 PTHREAD_PRIOQ_INSERT_TAIL(new_thread);
235 * Undefer and handle pending signals, yielding
238 _thread_kern_sig_undefer();
240 /* Return a pointer to the thread structure: */
241 (*thread) = new_thread;
244 /* Install the scheduling timer: */
245 itimer.it_interval.tv_sec = 0;
246 itimer.it_interval.tv_usec = _clock_res_usec;
247 itimer.it_value = itimer.it_interval;
248 if (setitimer(_ITIMER_SCHED_TIMER, &itimer,
250 PANIC("Cannot set interval timer");
253 /* Schedule the new user thread: */
254 _thread_kern_sched(NULL);
257 * Start a garbage collector thread
260 if (f_gc && _pthread_create(&gc_thread, NULL,
261 _thread_gc, NULL) != 0)
262 PANIC("Can't create gc thread");
267 /* Return the status: */
274 struct pthread *curthread = _get_curthread();
276 /* We just left the scheduler via longjmp: */
277 _thread_kern_in_sched = 0;
279 /* Run the current thread's start routine with argument: */
280 _pthread_exit(curthread->start_routine(curthread->arg));
282 /* This point should never be reached. */
283 PANIC("Thread has resumed after exit");