Ignore machine-check MSRs
[freebsd-src/fkvm-freebsd.git] / lib / libc_r / uthread / uthread_create.c
blob3474bfa2f994908fe2975707c41f4b65d43382d9
1 /*
2 * Copyright (c) 1995-1998 John Birrell <jb@cimlogic.com.au>
3 * All rights reserved.
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
7 * are met:
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
27 * SUCH DAMAGE.
29 * $FreeBSD$
31 #include <errno.h>
32 #include <stdlib.h>
33 #include <string.h>
34 #include <fcntl.h>
35 #include <unistd.h>
36 #include <stddef.h>
37 #include <sys/time.h>
38 #include <machine/reg.h>
39 #include "namespace.h"
40 #include <pthread.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);
54 #undef OFF
56 int _thread_PS_RUNNING_value = PS_RUNNING;
57 int _thread_PS_DEAD_value = PS_DEAD;
59 __weak_reference(_pthread_create, pthread_create);
61 int
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;
67 int f_gc = 0;
68 int ret = 0;
69 pthread_t gc_thread;
70 pthread_t new_thread;
71 pthread_attr_t pattr;
72 void *stack;
73 #if !defined(__ia64__)
74 u_long stackp;
75 #endif
77 if (thread == NULL)
78 return(EINVAL);
81 * Locking functions in libc are required when there are
82 * threads other than the initial thread.
84 __isthreaded = 1;
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: */
89 ret = EAGAIN;
90 } else {
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;
95 } else {
96 pattr = *attr;
98 /* Check if a stack was specified in the thread attributes: */
99 if ((stack = pattr->stackaddr_attr) != NULL) {
101 /* Allocate a stack: */
102 else {
103 stack = _thread_stack_alloc(pattr->stacksize_attr,
104 pattr->guardsize_attr);
105 if (stack == NULL) {
106 ret = EAGAIN;
107 free(new_thread);
111 /* Check for errors: */
112 if (ret != 0) {
113 } else {
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
143 * _thread_start().
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__)
150 stackp &= ~0xFUL;
151 #endif
152 /* The stack starts high and builds down: */
153 SET_STACK_JB(new_thread->ctx.jb, stackp);
154 #else
155 SET_STACK_JB(new_thread->ctx.jb,
156 (long)new_thread->stack, pattr->stacksize_attr);
157 #endif
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;
176 } else {
178 * Use just the thread priority, leaving the
179 * other scheduling attributes as their
180 * default values:
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
210 * track threads.
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;
226 } else {
227 new_thread->state = PS_RUNNING;
228 PTHREAD_PRIOQ_INSERT_TAIL(new_thread);
232 * Undefer and handle pending signals, yielding
233 * if necessary.
235 _thread_kern_sig_undefer();
237 /* Return a pointer to the thread structure: */
238 (*thread) = new_thread;
240 if (f_gc != 0) {
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,
246 NULL) != 0)
247 PANIC("Cannot set interval timer");
250 /* Schedule the new user thread: */
251 _thread_kern_sched(NULL);
254 * Start a garbage collector thread
255 * if necessary.
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: */
265 return (ret);
268 void
269 _thread_start(void)
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");