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