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