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. Neither the name of the author nor the names of any co-contributors
14 * may be used to endorse or promote products derived from this software
15 * without specific prior written permission.
17 * THIS SOFTWARE IS PROVIDED BY JOHN BIRRELL AND CONTRIBUTORS ``AS IS'' AND
18 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
19 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
20 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
21 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
22 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
23 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
24 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
25 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
26 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
38 #include <machine/reg.h>
39 #include "namespace.h"
41 #include "un-namespace.h"
43 #include "pthread_private.h"
44 #include "libc_private.h"
46 static u_int64_t next_uniqueid
= 1;
48 #define OFF(f) offsetof(struct pthread, f)
49 int _thread_next_offset
= OFF(tle
.tqe_next
);
50 int _thread_uniqueid_offset
= OFF(uniqueid
);
51 int _thread_state_offset
= OFF(state
);
52 int _thread_name_offset
= OFF(name
);
53 int _thread_ctx_offset
= OFF(ctx
);
56 int _thread_PS_RUNNING_value
= PS_RUNNING
;
57 int _thread_PS_DEAD_value
= PS_DEAD
;
59 __weak_reference(_pthread_create
, pthread_create
);
62 _pthread_create(pthread_t
*thread
, const pthread_attr_t
*attr
,
63 void *(*start_routine
) (void *), void *arg
)
65 struct pthread
*curthread
= _get_curthread();
66 struct itimerval itimer
;
73 #if !defined(__ia64__)
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 a stack: */
103 stack
= _thread_stack_alloc(pattr
->stacksize_attr
,
104 pattr
->guardsize_attr
);
111 /* Check for errors: */
114 /* Initialise the thread structure: */
115 memset(new_thread
, 0, sizeof(struct pthread
));
116 new_thread
->slice_usec
= -1;
117 new_thread
->stack
= stack
;
118 new_thread
->start_routine
= start_routine
;
119 new_thread
->arg
= arg
;
121 new_thread
->cancelflags
= PTHREAD_CANCEL_ENABLE
|
122 PTHREAD_CANCEL_DEFERRED
;
125 * Write a magic value to the thread structure
126 * to help identify valid ones:
128 new_thread
->magic
= PTHREAD_MAGIC
;
130 /* Initialise the thread for signals: */
131 new_thread
->sigmask
= curthread
->sigmask
;
132 new_thread
->sigmask_seqno
= 0;
134 /* Initialize the signal frame: */
135 new_thread
->curframe
= NULL
;
137 /* Initialise the jump buffer: */
138 _setjmp(new_thread
->ctx
.jb
);
141 * Set up new stack frame so that it looks like it
142 * returned from a longjmp() to the beginning of
145 SET_RETURN_ADDR_JB(new_thread
->ctx
.jb
, _thread_start
);
147 #if !defined(__ia64__)
148 stackp
= (long)new_thread
->stack
+ pattr
->stacksize_attr
- sizeof(double);
149 #if defined(__amd64__)
152 /* The stack starts high and builds down: */
153 SET_STACK_JB(new_thread
->ctx
.jb
, stackp
);
155 SET_STACK_JB(new_thread
->ctx
.jb
,
156 (long)new_thread
->stack
, pattr
->stacksize_attr
);
159 /* Copy the thread attributes: */
160 memcpy(&new_thread
->attr
, pattr
, sizeof(struct pthread_attr
));
163 * Check if this thread is to inherit the scheduling
164 * attributes from its parent:
166 if (new_thread
->attr
.flags
& PTHREAD_INHERIT_SCHED
) {
167 /* Copy the scheduling attributes: */
168 new_thread
->base_priority
=
169 curthread
->base_priority
&
170 ~PTHREAD_SIGNAL_PRIORITY
;
171 new_thread
->attr
.prio
=
172 curthread
->base_priority
&
173 ~PTHREAD_SIGNAL_PRIORITY
;
174 new_thread
->attr
.sched_policy
=
175 curthread
->attr
.sched_policy
;
178 * Use just the thread priority, leaving the
179 * other scheduling attributes as their
182 new_thread
->base_priority
=
183 new_thread
->attr
.prio
;
185 new_thread
->active_priority
= new_thread
->base_priority
;
186 new_thread
->inherited_priority
= 0;
188 /* Initialize joiner to NULL (no joiner): */
189 new_thread
->joiner
= NULL
;
191 /* Initialize the mutex queue: */
192 TAILQ_INIT(&new_thread
->mutexq
);
194 /* Initialise hooks in the thread structure: */
195 new_thread
->specific
= NULL
;
196 new_thread
->cleanup
= NULL
;
197 new_thread
->flags
= 0;
198 new_thread
->poll_data
.nfds
= 0;
199 new_thread
->poll_data
.fds
= NULL
;
200 new_thread
->continuation
= NULL
;
203 * Defer signals to protect the scheduling queues
204 * from access by the signal handler:
206 _thread_kern_sig_defer();
209 * Initialise the unique id which GDB uses to
212 new_thread
->uniqueid
= next_uniqueid
++;
215 * Check if the garbage collector thread
216 * needs to be started.
218 f_gc
= (TAILQ_FIRST(&_thread_list
) == _thread_initial
);
220 /* Add the thread to the linked list of all threads: */
221 TAILQ_INSERT_HEAD(&_thread_list
, new_thread
, tle
);
223 if (pattr
->suspend
== PTHREAD_CREATE_SUSPENDED
) {
224 new_thread
->flags
|= PTHREAD_FLAGS_SUSPENDED
;
225 new_thread
->state
= PS_SUSPENDED
;
227 new_thread
->state
= PS_RUNNING
;
228 PTHREAD_PRIOQ_INSERT_TAIL(new_thread
);
232 * Undefer and handle pending signals, yielding
235 _thread_kern_sig_undefer();
237 /* Return a pointer to the thread structure: */
238 (*thread
) = new_thread
;
241 /* Install the scheduling timer: */
242 itimer
.it_interval
.tv_sec
= 0;
243 itimer
.it_interval
.tv_usec
= _clock_res_usec
;
244 itimer
.it_value
= itimer
.it_interval
;
245 if (setitimer(_ITIMER_SCHED_TIMER
, &itimer
,
247 PANIC("Cannot set interval timer");
250 /* Schedule the new user thread: */
251 _thread_kern_sched(NULL
);
254 * Start a garbage collector thread
257 if (f_gc
&& _pthread_create(&gc_thread
, NULL
,
258 _thread_gc
, NULL
) != 0)
259 PANIC("Can't create gc thread");
264 /* Return the status: */
271 struct pthread
*curthread
= _get_curthread();
273 /* We just left the scheduler via longjmp: */
274 _thread_kern_in_sched
= 0;
276 /* Run the current thread's start routine with argument: */
277 _pthread_exit(curthread
->start_routine(curthread
->arg
));
279 /* This point should never be reached. */
280 PANIC("Thread has resumed after exit");