]> CyberLeo.Net >> Repos - FreeBSD/releng/8.1.git/blob - lib/libc_r/uthread/uthread_create.c
Copy stable/8 to releng/8.1 in preparation for 8.1-RC1.
[FreeBSD/releng/8.1.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. 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.
16  *
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.
28  *
29  * $FreeBSD$
30  */
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"
42
43 #include "pthread_private.h"
44 #include "libc_private.h"
45
46 static u_int64_t next_uniqueid = 1;
47
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
55
56 int _thread_PS_RUNNING_value            = PS_RUNNING;
57 int _thread_PS_DEAD_value               = PS_DEAD;
58
59 __weak_reference(_pthread_create, pthread_create);
60
61 int
62 _pthread_create(pthread_t *thread, const pthread_attr_t *attr,
63                void *(*start_routine) (void *), void *arg)
64 {
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
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 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);
108                         }
109                 }
110
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;
120
121                         new_thread->cancelflags = PTHREAD_CANCEL_ENABLE |
122                             PTHREAD_CANCEL_DEFERRED;
123
124                         /*
125                          * Write a magic value to the thread structure
126                          * to help identify valid ones:
127                          */
128                         new_thread->magic = PTHREAD_MAGIC;
129
130                         /* Initialise the thread for signals: */
131                         new_thread->sigmask = curthread->sigmask;
132                         new_thread->sigmask_seqno = 0;
133
134                         /* Initialize the signal frame: */
135                         new_thread->curframe = NULL;
136
137                         /* Initialise the jump buffer: */
138                         _setjmp(new_thread->ctx.jb);
139
140                         /*
141                          * Set up new stack frame so that it looks like it
142                          * returned from a longjmp() to the beginning of
143                          * _thread_start().
144                          */
145                         SET_RETURN_ADDR_JB(new_thread->ctx.jb, _thread_start);
146
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
158
159                         /* Copy the thread attributes: */
160                         memcpy(&new_thread->attr, pattr, sizeof(struct pthread_attr));
161
162                         /*
163                          * Check if this thread is to inherit the scheduling
164                          * attributes from its parent:
165                          */
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 {
177                                 /*
178                                  * Use just the thread priority, leaving the
179                                  * other scheduling attributes as their
180                                  * default values:
181                                  */
182                                 new_thread->base_priority =
183                                     new_thread->attr.prio;
184                         }
185                         new_thread->active_priority = new_thread->base_priority;
186                         new_thread->inherited_priority = 0;
187
188                         /* Initialize joiner to NULL (no joiner): */
189                         new_thread->joiner = NULL;
190
191                         /* Initialize the mutex queue: */
192                         TAILQ_INIT(&new_thread->mutexq);
193
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;
201
202                         /*
203                          * Defer signals to protect the scheduling queues
204                          * from access by the signal handler:
205                          */
206                         _thread_kern_sig_defer();
207
208                         /*
209                          * Initialise the unique id which GDB uses to
210                          * track threads.
211                          */
212                         new_thread->uniqueid = next_uniqueid++;
213
214                         /*
215                          * Check if the garbage collector thread
216                          * needs to be started.
217                          */
218                         f_gc = (TAILQ_FIRST(&_thread_list) == _thread_initial);
219
220                         /* Add the thread to the linked list of all threads: */
221                         TAILQ_INSERT_HEAD(&_thread_list, new_thread, tle);
222
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);
229                         }
230
231                         /*
232                          * Undefer and handle pending signals, yielding
233                          * if necessary.
234                          */
235                         _thread_kern_sig_undefer();
236
237                         /* Return a pointer to the thread structure: */
238                         (*thread) = new_thread;
239
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");
248                         }
249
250                         /* Schedule the new user thread: */
251                         _thread_kern_sched(NULL);
252
253                         /*
254                          * Start a garbage collector thread
255                          * if necessary.
256                          */
257                         if (f_gc && _pthread_create(&gc_thread, NULL,
258                                     _thread_gc, NULL) != 0)
259                                 PANIC("Can't create gc thread");
260
261                 }
262         }
263
264         /* Return the status: */
265         return (ret);
266 }
267
268 void
269 _thread_start(void)
270 {
271         struct pthread  *curthread = _get_curthread();
272
273         /* We just left the scheduler via longjmp: */
274         _thread_kern_in_sched = 0;
275
276         /* Run the current thread's start routine with argument: */
277         _pthread_exit(curthread->start_routine(curthread->arg));
278
279         /* This point should never be reached. */
280         PANIC("Thread has resumed after exit");
281 }