]> CyberLeo.Net >> Repos - FreeBSD/FreeBSD.git/blob - 6/lib/libc_r/uthread/uthread_create.c
Clone Kip's Xen on stable/6 tree so that I can work on improving FreeBSD/amd64
[FreeBSD/FreeBSD.git] / 6 / lib / libc_r / uthread / uthread_create.c
1 /*
2  * Copyright (c) 1995-1998 John Birrell <jb@cimlogic.com.au>
3  * All rights reserved.
4  *
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. 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.
19  *
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
30  * SUCH DAMAGE.
31  *
32  * $FreeBSD$
33  */
34 #include <errno.h>
35 #include <stdlib.h>
36 #include <string.h>
37 #include <fcntl.h>
38 #include <unistd.h>
39 #include <stddef.h>
40 #include <sys/time.h>
41 #include <machine/reg.h>
42 #include "namespace.h"
43 #include <pthread.h>
44 #include "un-namespace.h"
45
46 #include "pthread_private.h"
47 #include "libc_private.h"
48
49 static u_int64_t next_uniqueid = 1;
50
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);
57 #undef OFF
58
59 int _thread_PS_RUNNING_value            = PS_RUNNING;
60 int _thread_PS_DEAD_value               = PS_DEAD;
61
62 __weak_reference(_pthread_create, pthread_create);
63
64 int
65 _pthread_create(pthread_t *thread, const pthread_attr_t *attr,
66                void *(*start_routine) (void *), void *arg)
67 {
68         struct pthread  *curthread = _get_curthread();
69         struct itimerval itimer;
70         int             f_gc = 0;
71         int             ret = 0;
72         pthread_t       gc_thread;
73         pthread_t       new_thread;
74         pthread_attr_t  pattr;
75         void           *stack;
76 #if !defined(__ia64__)
77         u_long          stackp;
78 #endif
79
80         if (thread == NULL)
81                 return(EINVAL);
82
83         /*
84          * Locking functions in libc are required when there are
85          * threads other than the initial thread.
86          */
87         __isthreaded = 1;
88
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: */
92                 ret = EAGAIN;
93         } else {
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;
98                 } else {
99                         pattr = *attr;
100                 }
101                 /* Check if a stack was specified in the thread attributes: */
102                 if ((stack = pattr->stackaddr_attr) != NULL) {
103                 }
104                 /* Allocate a stack: */
105                 else {
106                         stack = _thread_stack_alloc(pattr->stacksize_attr,
107                             pattr->guardsize_attr);
108                         if (stack == NULL) {
109                                 ret = EAGAIN;
110                                 free(new_thread);
111                         }
112                 }
113
114                 /* Check for errors: */
115                 if (ret != 0) {
116                 } else {
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;
123
124                         new_thread->cancelflags = PTHREAD_CANCEL_ENABLE |
125                             PTHREAD_CANCEL_DEFERRED;
126
127                         /*
128                          * Write a magic value to the thread structure
129                          * to help identify valid ones:
130                          */
131                         new_thread->magic = PTHREAD_MAGIC;
132
133                         /* Initialise the thread for signals: */
134                         new_thread->sigmask = curthread->sigmask;
135                         new_thread->sigmask_seqno = 0;
136
137                         /* Initialize the signal frame: */
138                         new_thread->curframe = NULL;
139
140                         /* Initialise the jump buffer: */
141                         _setjmp(new_thread->ctx.jb);
142
143                         /*
144                          * Set up new stack frame so that it looks like it
145                          * returned from a longjmp() to the beginning of
146                          * _thread_start().
147                          */
148                         SET_RETURN_ADDR_JB(new_thread->ctx.jb, _thread_start);
149
150 #if !defined(__ia64__)
151                         stackp = (long)new_thread->stack + pattr->stacksize_attr - sizeof(double);
152 #if defined(__amd64__)
153                         stackp &= ~0xFUL;
154 #endif
155                         /* The stack starts high and builds down: */
156                         SET_STACK_JB(new_thread->ctx.jb, stackp);
157 #else
158                         SET_STACK_JB(new_thread->ctx.jb,
159                             (long)new_thread->stack, pattr->stacksize_attr);
160 #endif
161
162                         /* Copy the thread attributes: */
163                         memcpy(&new_thread->attr, pattr, sizeof(struct pthread_attr));
164
165                         /*
166                          * Check if this thread is to inherit the scheduling
167                          * attributes from its parent:
168                          */
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;
179                         } else {
180                                 /*
181                                  * Use just the thread priority, leaving the
182                                  * other scheduling attributes as their
183                                  * default values:
184                                  */
185                                 new_thread->base_priority =
186                                     new_thread->attr.prio;
187                         }
188                         new_thread->active_priority = new_thread->base_priority;
189                         new_thread->inherited_priority = 0;
190
191                         /* Initialize joiner to NULL (no joiner): */
192                         new_thread->joiner = NULL;
193
194                         /* Initialize the mutex queue: */
195                         TAILQ_INIT(&new_thread->mutexq);
196
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;
204
205                         /*
206                          * Defer signals to protect the scheduling queues
207                          * from access by the signal handler:
208                          */
209                         _thread_kern_sig_defer();
210
211                         /*
212                          * Initialise the unique id which GDB uses to
213                          * track threads.
214                          */
215                         new_thread->uniqueid = next_uniqueid++;
216
217                         /*
218                          * Check if the garbage collector thread
219                          * needs to be started.
220                          */
221                         f_gc = (TAILQ_FIRST(&_thread_list) == _thread_initial);
222
223                         /* Add the thread to the linked list of all threads: */
224                         TAILQ_INSERT_HEAD(&_thread_list, new_thread, tle);
225
226                         if (pattr->suspend == PTHREAD_CREATE_SUSPENDED) {
227                                 new_thread->flags |= PTHREAD_FLAGS_SUSPENDED;
228                                 new_thread->state = PS_SUSPENDED;
229                         } else {
230                                 new_thread->state = PS_RUNNING;
231                                 PTHREAD_PRIOQ_INSERT_TAIL(new_thread);
232                         }
233
234                         /*
235                          * Undefer and handle pending signals, yielding
236                          * if necessary.
237                          */
238                         _thread_kern_sig_undefer();
239
240                         /* Return a pointer to the thread structure: */
241                         (*thread) = new_thread;
242
243                         if (f_gc != 0) {
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,
249                                     NULL) != 0)
250                                         PANIC("Cannot set interval timer");
251                         }
252
253                         /* Schedule the new user thread: */
254                         _thread_kern_sched(NULL);
255
256                         /*
257                          * Start a garbage collector thread
258                          * if necessary.
259                          */
260                         if (f_gc && _pthread_create(&gc_thread, NULL,
261                                     _thread_gc, NULL) != 0)
262                                 PANIC("Can't create gc thread");
263
264                 }
265         }
266
267         /* Return the status: */
268         return (ret);
269 }
270
271 void
272 _thread_start(void)
273 {
274         struct pthread  *curthread = _get_curthread();
275
276         /* We just left the scheduler via longjmp: */
277         _thread_kern_in_sched = 0;
278
279         /* Run the current thread's start routine with argument: */
280         _pthread_exit(curthread->start_routine(curthread->arg));
281
282         /* This point should never be reached. */
283         PANIC("Thread has resumed after exit");
284 }