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.6 2005/05/30 20:50:53 joerg 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
;
63 _pthread_create(pthread_t
*thread
, const pthread_attr_t
*attr
,
64 void *(*start_routine
) (void *), void *arg
)
66 struct pthread
*curthread
= _get_curthread();
67 struct itimerval itimer
;
79 * Locking functions in libc are required when there are
80 * threads other than the initial thread.
84 /* Allocate memory for the thread structure: */
85 if ((new_thread
= (pthread_t
) malloc(sizeof(struct pthread
))) == NULL
) {
86 /* Insufficient memory to create a thread: */
89 /* Check if default thread attributes are required: */
90 if (attr
== NULL
|| *attr
== NULL
) {
91 /* Use the default thread attributes: */
92 pattr
= &pthread_attr_default
;
96 /* Check if a stack was specified in the thread attributes: */
97 if ((stack
= pattr
->stackaddr_attr
) != NULL
) {
99 /* Allocate memory for a default-size stack: */
100 else if (pattr
->stacksize_attr
== PTHREAD_STACK_DEFAULT
) {
101 struct stack
*spare_stack
;
103 /* Allocate or re-use a default-size stack. */
106 * Use the garbage collector mutex for synchronization
107 * of the spare stack list.
109 if (pthread_mutex_lock(&_gc_mutex
) != 0)
110 PANIC("Cannot lock gc mutex");
112 if ((spare_stack
= SLIST_FIRST(&_stackq
)) != NULL
) {
113 /* Use the spare stack. */
114 SLIST_REMOVE_HEAD(&_stackq
, qe
);
116 /* Unlock the garbage collector mutex. */
117 if (pthread_mutex_unlock(&_gc_mutex
) != 0)
118 PANIC("Cannot unlock gc mutex");
120 stack
= sizeof(struct stack
)
121 + (void *) spare_stack
122 - PTHREAD_STACK_DEFAULT
;
124 /* Allocate a new stack. */
125 stack
= _next_stack
+ PTHREAD_STACK_GUARD
;
128 * Even if stack allocation fails, we don't want
129 * to try to use this location again, so
130 * unconditionally decrement _next_stack. Under
131 * normal operating conditions, the most likely
132 * reason for an mmap() error is a stack
133 * overflow of the adjacent thread stack.
135 _next_stack
-= (PTHREAD_STACK_DEFAULT
136 + PTHREAD_STACK_GUARD
);
138 /* Unlock the garbage collector mutex. */
139 if (pthread_mutex_unlock(&_gc_mutex
) != 0)
140 PANIC("Cannot unlock gc mutex");
143 if (mmap(stack
, PTHREAD_STACK_DEFAULT
,
144 PROT_READ
| PROT_WRITE
, MAP_STACK
,
145 -1, 0) == MAP_FAILED
) {
152 * The user wants a stack of a particular size. Lets hope they
153 * really know what they want, and simply malloc the stack.
155 else if ((stack
= (void *) malloc(pattr
->stacksize_attr
))
157 /* Insufficient memory to create a thread: */
162 /* Check for errors: */
165 /* Initialise the thread structure: */
166 memset(new_thread
, 0, sizeof(struct pthread
));
167 new_thread
->tcb
= _libc_allocate_tls();
168 if (new_thread
->tcb
== NULL
)
169 PANIC("Cannot allocate TLS and TCB");
170 new_thread
->slice_usec
= -1;
171 new_thread
->stack
= stack
;
172 new_thread
->start_routine
= start_routine
;
173 new_thread
->arg
= arg
;
175 new_thread
->cancelflags
= PTHREAD_CANCEL_ENABLE
|
176 PTHREAD_CANCEL_DEFERRED
;
179 * Write a magic value to the thread structure
180 * to help identify valid ones:
182 new_thread
->magic
= PTHREAD_MAGIC
;
184 /* Initialise the thread for signals: */
185 new_thread
->sigmask
= curthread
->sigmask
;
186 new_thread
->sigmask_seqno
= 0;
188 /* Initialize the signal frame: */
189 new_thread
->curframe
= NULL
;
191 /* Initialise the jump buffer: */
192 _setjmp(new_thread
->ctx
.jb
);
195 * Set up new stack frame so that it looks like it
196 * returned from a longjmp() to the beginning of
199 SET_RETURN_ADDR_JB(new_thread
->ctx
.jb
, _thread_start
);
201 /* The stack starts high and builds down: */
202 SET_STACK_JB(new_thread
->ctx
.jb
,
203 (long)new_thread
->stack
+ pattr
->stacksize_attr
206 /* Copy the thread attributes: */
207 memcpy(&new_thread
->attr
, pattr
, sizeof(struct pthread_attr
));
210 * Check if this thread is to inherit the scheduling
211 * attributes from its parent:
213 if (new_thread
->attr
.sched_inherit
& PTHREAD_INHERIT_SCHED
) {
214 /* Copy the scheduling attributes: */
215 new_thread
->base_priority
=
216 curthread
->base_priority
&
217 ~PTHREAD_SIGNAL_PRIORITY
;
218 new_thread
->attr
.prio
=
219 curthread
->base_priority
&
220 ~PTHREAD_SIGNAL_PRIORITY
;
221 new_thread
->attr
.sched_policy
=
222 curthread
->attr
.sched_policy
;
225 * Use just the thread priority, leaving the
226 * other scheduling attributes as their
229 new_thread
->base_priority
=
230 new_thread
->attr
.prio
;
232 new_thread
->active_priority
= new_thread
->base_priority
;
233 new_thread
->inherited_priority
= 0;
235 /* Initialize joiner to NULL (no joiner): */
236 new_thread
->joiner
= NULL
;
238 /* Initialize the mutex queue: */
239 TAILQ_INIT(&new_thread
->mutexq
);
241 /* Initialise hooks in the thread structure: */
242 new_thread
->specific_data
= NULL
;
243 new_thread
->cleanup
= NULL
;
244 new_thread
->flags
= 0;
245 new_thread
->poll_data
.nfds
= 0;
246 new_thread
->poll_data
.fds
= NULL
;
247 new_thread
->continuation
= NULL
;
250 * Defer signals to protect the scheduling queues
251 * from access by the signal handler:
253 _thread_kern_sig_defer();
256 * Initialise the unique id which GDB uses to
259 new_thread
->uniqueid
= next_uniqueid
++;
262 * Check if the garbage collector thread
263 * needs to be started.
265 f_gc
= (TAILQ_FIRST(&_thread_list
) == _thread_initial
);
267 /* Add the thread to the linked list of all threads: */
268 TAILQ_INSERT_HEAD(&_thread_list
, new_thread
, tle
);
270 if (pattr
->suspend
== PTHREAD_CREATE_SUSPENDED
) {
271 new_thread
->flags
|= PTHREAD_FLAGS_SUSPENDED
;
272 new_thread
->state
= PS_SUSPENDED
;
274 new_thread
->state
= PS_RUNNING
;
275 PTHREAD_PRIOQ_INSERT_TAIL(new_thread
);
279 * Undefer and handle pending signals, yielding
282 _thread_kern_sig_undefer();
284 /* Return a pointer to the thread structure: */
285 (*thread
) = new_thread
;
288 /* Install the scheduling timer: */
289 itimer
.it_interval
.tv_sec
= 0;
290 itimer
.it_interval
.tv_usec
= _clock_res_usec
;
291 itimer
.it_value
= itimer
.it_interval
;
292 if (setitimer(_ITIMER_SCHED_TIMER
, &itimer
,
294 PANIC("Cannot set interval timer");
297 /* Schedule the new user thread: */
298 _thread_kern_sched(NULL
);
301 * Start a garbage collector thread
304 if (f_gc
&& pthread_create(&gc_thread
,NULL
,
305 _thread_gc
,NULL
) != 0)
306 PANIC("Can't create gc thread");
311 /* Return the status: */
318 struct pthread
*curthread
= _get_curthread();
320 /* We just left the scheduler via longjmp: */
321 _thread_kern_in_sched
= 0;
323 /* Run the current thread's start routine with argument: */
324 pthread_exit(curthread
->start_routine(curthread
->arg
));
326 /* This point should never be reached. */
327 PANIC("Thread has resumed after exit");
330 __strong_reference(_pthread_create
, pthread_create
);