Initial import from FreeBSD RELENG_4:
[dragonfly.git] / 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: src/lib/libc_r/uthread/uthread_create.c,v 1.24.2.6 2003/01/08 05:04:26 fjoe Exp $
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 <sys/param.h>
42 #include <sys/mman.h>
43 #include <machine/reg.h>
44 #include <pthread.h>
45 #include "pthread_private.h"
46 #include "libc_private.h"
47
48 static u_int64_t next_uniqueid = 1;
49
50 #define OFF(f)  offsetof(struct pthread, f)
51 int _thread_next_offset                 = OFF(tle.tqe_next);
52 int _thread_uniqueid_offset             = OFF(uniqueid);
53 int _thread_state_offset                = OFF(state);
54 int _thread_name_offset                 = OFF(name);
55 int _thread_ctx_offset                  = OFF(ctx);
56 #undef OFF
57
58 int _thread_PS_RUNNING_value            = PS_RUNNING;
59 int _thread_PS_DEAD_value               = PS_DEAD;
60
61 __weak_reference(_pthread_create, pthread_create);
62
63 int
64 _pthread_create(pthread_t *thread, const pthread_attr_t *attr,
65                void *(*start_routine) (void *), void *arg)
66 {
67         struct pthread  *curthread = _get_curthread();
68         struct itimerval itimer;
69         int             f_gc = 0;
70         int             ret = 0;
71         pthread_t       gc_thread;
72         pthread_t       new_thread;
73         pthread_attr_t  pattr;
74         void           *stack;
75
76         if (thread == NULL)
77                 return (EINVAL);
78
79         /*
80          * Locking functions in libc are required when there are
81          * threads other than the initial thread.
82          */
83         __isthreaded = 1;
84
85         /* Allocate memory for the thread structure: */
86         if ((new_thread = (pthread_t) malloc(sizeof(struct pthread))) == NULL) {
87                 /* Insufficient memory to create a thread: */
88                 ret = EAGAIN;
89         } else {
90                 /* Check if default thread attributes are required: */
91                 if (attr == NULL || *attr == NULL) {
92                         /* Use the default thread attributes: */
93                         pattr = &pthread_attr_default;
94                 } else {
95                         pattr = *attr;
96                 }
97                 /* Check if a stack was specified in the thread attributes: */
98                 if ((stack = pattr->stackaddr_attr) != NULL) {
99                 }
100                 /* Allocate memory for a default-size stack: */
101                 else if (pattr->stacksize_attr == PTHREAD_STACK_DEFAULT) {
102                         struct stack    *spare_stack;
103                         
104                         /* Allocate or re-use a default-size stack. */
105                         
106                         /*
107                          * Use the garbage collector mutex for synchronization
108                          * of the spare stack list.
109                          */
110                         if (pthread_mutex_lock(&_gc_mutex) != 0)
111                                 PANIC("Cannot lock gc mutex");
112                         
113                         if ((spare_stack = SLIST_FIRST(&_stackq)) != NULL) {
114                                 /* Use the spare stack. */
115                                 SLIST_REMOVE_HEAD(&_stackq, qe);
116                                 
117                                 /* Unlock the garbage collector mutex. */
118                                 if (pthread_mutex_unlock(&_gc_mutex) != 0)
119                                         PANIC("Cannot unlock gc mutex");
120                                 
121                                 stack = sizeof(struct stack)
122                                     + (void *) spare_stack
123                                     - PTHREAD_STACK_DEFAULT;
124                         } else {
125                                 /* Allocate a new stack. */
126                                 stack = _next_stack + PTHREAD_STACK_GUARD;
127
128                                 /*
129                                  * Even if stack allocation fails, we don't want
130                                  * to try to use this location again, so
131                                  * unconditionally decrement _next_stack.  Under
132                                  * normal operating conditions, the most likely
133                                  * reason for an mmap() error is a stack
134                                  * overflow of the adjacent thread stack.
135                                  */
136                                 _next_stack -= (PTHREAD_STACK_DEFAULT
137                                     + PTHREAD_STACK_GUARD);
138
139                                 /* Unlock the garbage collector mutex. */
140                                 if (pthread_mutex_unlock(&_gc_mutex) != 0)
141                                         PANIC("Cannot unlock gc mutex");
142
143                                 /* Stack: */
144                                 if (mmap(stack, PTHREAD_STACK_DEFAULT,
145                                     PROT_READ | PROT_WRITE, MAP_STACK,
146                                     -1, 0) == MAP_FAILED) {
147                                         ret = EAGAIN;
148                                         free(new_thread);
149                                 }
150                         }
151                 }
152                 /*
153                  * The user wants a stack of a particular size.  Lets hope they
154                  * really know what they want, and simply malloc the stack.
155                  */
156                 else if ((stack = (void *) malloc(pattr->stacksize_attr))
157                     == NULL) {
158                         /* Insufficient memory to create a thread: */
159                         ret = EAGAIN;
160                         free(new_thread);
161                 }
162
163                 /* Check for errors: */
164                 if (ret != 0) {
165                 } else {
166                         /* Initialise the thread structure: */
167                         memset(new_thread, 0, sizeof(struct pthread));
168                         new_thread->slice_usec = -1;
169                         new_thread->stack = stack;
170                         new_thread->start_routine = start_routine;
171                         new_thread->arg = arg;
172
173                         new_thread->cancelflags = PTHREAD_CANCEL_ENABLE |
174                             PTHREAD_CANCEL_DEFERRED;
175
176                         /*
177                          * Write a magic value to the thread structure
178                          * to help identify valid ones:
179                          */
180                         new_thread->magic = PTHREAD_MAGIC;
181
182                         /* Initialise the thread for signals: */
183                         new_thread->sigmask = curthread->sigmask;
184                         new_thread->sigmask_seqno = 0;
185
186                         /* Initialize the signal frame: */
187                         new_thread->curframe = NULL;
188
189                         /* Initialise the jump buffer: */
190                         _setjmp(new_thread->ctx.jb);
191
192                         /*
193                          * Set up new stack frame so that it looks like it
194                          * returned from a longjmp() to the beginning of
195                          * _thread_start().
196                          */
197                         SET_RETURN_ADDR_JB(new_thread->ctx.jb, _thread_start);
198
199                         /* The stack starts high and builds down: */
200                         SET_STACK_JB(new_thread->ctx.jb,
201                             (long)new_thread->stack + pattr->stacksize_attr
202                             - sizeof(double));
203
204                         /* Copy the thread attributes: */
205                         memcpy(&new_thread->attr, pattr, sizeof(struct pthread_attr));
206
207                         /*
208                          * Check if this thread is to inherit the scheduling
209                          * attributes from its parent:
210                          */
211                         if (new_thread->attr.flags & PTHREAD_INHERIT_SCHED) {
212                                 /* Copy the scheduling attributes: */
213                                 new_thread->base_priority =
214                                     curthread->base_priority &
215                                     ~PTHREAD_SIGNAL_PRIORITY;
216                                 new_thread->attr.prio =
217                                     curthread->base_priority &
218                                     ~PTHREAD_SIGNAL_PRIORITY;
219                                 new_thread->attr.sched_policy =
220                                     curthread->attr.sched_policy;
221                         } else {
222                                 /*
223                                  * Use just the thread priority, leaving the
224                                  * other scheduling attributes as their
225                                  * default values:
226                                  */
227                                 new_thread->base_priority =
228                                     new_thread->attr.prio;
229                         }
230                         new_thread->active_priority = new_thread->base_priority;
231                         new_thread->inherited_priority = 0;
232
233                         /* Initialize joiner to NULL (no joiner): */
234                         new_thread->joiner = NULL;
235
236                         /* Initialize the mutex queue: */
237                         TAILQ_INIT(&new_thread->mutexq);
238
239                         /* Initialise hooks in the thread structure: */
240                         new_thread->specific_data = NULL;
241                         new_thread->cleanup = NULL;
242                         new_thread->flags = 0;
243                         new_thread->poll_data.nfds = 0;
244                         new_thread->poll_data.fds = NULL;
245                         new_thread->continuation = NULL;
246
247                         /*
248                          * Defer signals to protect the scheduling queues
249                          * from access by the signal handler:
250                          */
251                         _thread_kern_sig_defer();
252
253                         /*
254                          * Initialise the unique id which GDB uses to
255                          * track threads.
256                          */
257                         new_thread->uniqueid = next_uniqueid++;
258
259                         /*
260                          * Check if the garbage collector thread
261                          * needs to be started.
262                          */
263                         f_gc = (TAILQ_FIRST(&_thread_list) == _thread_initial);
264
265                         /* Add the thread to the linked list of all threads: */
266                         TAILQ_INSERT_HEAD(&_thread_list, new_thread, tle);
267
268                         if (pattr->suspend == PTHREAD_CREATE_SUSPENDED) {
269                                 new_thread->flags |= PTHREAD_FLAGS_SUSPENDED;
270                                 new_thread->state = PS_SUSPENDED;
271                         } else {
272                                 new_thread->state = PS_RUNNING;
273                                 PTHREAD_PRIOQ_INSERT_TAIL(new_thread);
274                         }
275
276                         /*
277                          * Undefer and handle pending signals, yielding
278                          * if necessary.
279                          */
280                         _thread_kern_sig_undefer();
281
282                         /* Return a pointer to the thread structure: */
283                         (*thread) = new_thread;
284
285                         if (f_gc != 0) {
286                                 /* Install the scheduling timer: */
287                                 itimer.it_interval.tv_sec = 0;
288                                 itimer.it_interval.tv_usec = _clock_res_usec;
289                                 itimer.it_value = itimer.it_interval;
290                                 if (setitimer(_ITIMER_SCHED_TIMER, &itimer,
291                                     NULL) != 0)
292                                         PANIC("Cannot set interval timer");
293                         }
294
295                         /* Schedule the new user thread: */
296                         _thread_kern_sched(NULL);
297
298                         /*
299                          * Start a garbage collector thread
300                          * if necessary.
301                          */
302                         if (f_gc && pthread_create(&gc_thread,NULL,
303                                     _thread_gc,NULL) != 0)
304                                 PANIC("Can't create gc thread");
305
306                 }
307         }
308
309         /* Return the status: */
310         return (ret);
311 }
312
313 void
314 _thread_start(void)
315 {
316         struct pthread  *curthread = _get_curthread();
317
318         /* We just left the scheduler via longjmp: */
319         _thread_kern_in_sched = 0;
320
321         /* Run the current thread's start routine with argument: */
322         pthread_exit(curthread->start_routine(curthread->arg));
323
324         /* This point should never be reached. */
325         PANIC("Thread has resumed after exit");
326 }