Deleted Added
full compact
thr_create.c (22315) thr_create.c (33292)
1/*
2 * Copyright (c) 1995 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 REGENTS 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 */
33#include <errno.h>
34#include <stdlib.h>
35#include <string.h>
36#include <fcntl.h>
37#include <unistd.h>
38#include <sys/time.h>
39#ifdef _THREAD_SAFE
40#include <machine/reg.h>
41#include <pthread.h>
42#include "pthread_private.h"
43
44int
45_thread_create(pthread_t * thread, const pthread_attr_t * attr,
46 void *(*start_routine) (void *), void *arg, pthread_t parent)
47{
48 int i;
49 int ret = 0;
50 int status;
51 pthread_t new_thread;
52 pthread_attr_t pattr;
53 void *stack;
54
55 /* Block signals: */
56 _thread_kern_sig_block(&status);
57
58 /* Allocate memory for the thread structure: */
59 if ((new_thread = (pthread_t) malloc(sizeof(struct pthread))) == NULL) {
60 /* Insufficient memory to create a thread: */
61 ret = EAGAIN;
62 } else {
63 /* Check if default thread attributes are required: */
64 if (attr == NULL || *attr == NULL) {
65 /* Use the default thread attributes: */
66 pattr = &pthread_attr_default;
67 } else {
68 pattr = *attr;
69 }
70 /* Check if a stack was specified in the thread attributes: */
71 if ((stack = pattr->stackaddr_attr) != NULL) {
72 }
73 /* Allocate memory for the stack: */
74 else if ((stack = (void *) malloc(pattr->stacksize_attr)) == NULL) {
75 /* Insufficient memory to create a thread: */
76 ret = EAGAIN;
77 free(new_thread);
78 }
79 /* Check for errors: */
80 if (ret != 0) {
81 } else {
82 /* Initialise the thread structure: */
83 memset(new_thread, 0, sizeof(struct pthread));
84 new_thread->slice_usec = -1;
85 new_thread->sig_saved = 0;
86 new_thread->stack = stack;
87 new_thread->start_routine = start_routine;
88 new_thread->arg = arg;
89 if (pattr->suspend == PTHREAD_CREATE_SUSPENDED) {
90 PTHREAD_NEW_STATE(new_thread,PS_SUSPENDED);
91 } else {
92 PTHREAD_NEW_STATE(new_thread,PS_RUNNING);
93 }
94
95 /* Initialise the thread for signals: */
96 new_thread->sigmask = _thread_run->sigmask;
97
98 /*
99 * Enter a loop to initialise the signal handler
100 * array:
101 */
102 for (i = 1; i < NSIG; i++) {
103 /* Default the signal handler: */
104 sigfillset(&new_thread->act[i - 1].sa_mask);
105 new_thread->act[i - 1].sa_handler = _thread_run->act[i - 1].sa_handler;
106 new_thread->act[i - 1].sa_flags = _thread_run->act[i - 1].sa_flags;
107 }
108
109 /* Initialise the jump buffer: */
110 _thread_sys_setjmp(new_thread->saved_jmp_buf);
111
112 /*
113 * Set up new stack frame so that it looks like it
114 * returned from a longjmp() to the beginning of
115 * _thread_start(). Check if this is a user thread:
116 */
117 if (parent == NULL) {
118 /* Use the user start function: */
119#if defined(__FreeBSD__)
120 new_thread->saved_jmp_buf[0]._jb[0] = (long) _thread_start;
121#elif defined(__NetBSD__)
122#if defined(__alpha)
123 new_thread->saved_jmp_buf[2] = (long) _thread_start;
124 new_thread->saved_jmp_buf[4 + R_RA] = 0;
125 new_thread->saved_jmp_buf[4 + R_T12] = (long) _thread_start;
126#else
127 new_thread->saved_jmp_buf[0] = (long) _thread_start;
128#endif
129#else
130#error "Don't recognize this operating system!"
131#endif
132 } else {
133 /*
134 * Use the (funny) signal handler start
135 * function:
136 */
137#if defined(__FreeBSD__)
138 new_thread->saved_jmp_buf[0]._jb[0] = (int) _thread_start_sig_handler;
139#elif defined(__NetBSD__)
140#if defined(__alpha)
141 new_thread->saved_jmp_buf[2] = (long) _thread_start_sig_handler;
142 new_thread->saved_jmp_buf[4 + R_RA] = 0;
143 new_thread->saved_jmp_buf[4 + R_T12] = (long) _thread_start_sig_handler;
144#else
145 new_thread->saved_jmp_buf[0] = (long) _thread_start_sig_handler;
146#endif
147#else
148#error "Don't recognize this operating system!"
149#endif
150 }
151
152 /* The stack starts high and builds down: */
153#if defined(__FreeBSD__)
154 new_thread->saved_jmp_buf[0]._jb[2] = (int) (new_thread->stack + pattr->stacksize_attr - sizeof(double));
155#elif defined(__NetBSD__)
156#if defined(__alpha)
157 new_thread->saved_jmp_buf[4 + R_SP] = (long) new_thread->stack + pattr->stacksize_attr - sizeof(double);
158#else
159 new_thread->saved_jmp_buf[2] = (long) new_thread->stack + pattr->stacksize_attr - sizeof(double);
160#endif
161#else
162#error "Don't recognize this operating system!"
163#endif
164
165 /* Copy the thread attributes: */
166 memcpy(&new_thread->attr, pattr, sizeof(struct pthread_attr));
167
168 /*
169 * Check if this thread is to inherit the scheduling
170 * attributes from its parent:
171 */
172 if (new_thread->attr.flags & PTHREAD_INHERIT_SCHED) {
173 /* Copy the scheduling attributes: */
174 new_thread->pthread_priority = _thread_run->pthread_priority;
175 new_thread->attr.prio = _thread_run->pthread_priority;
176 new_thread->attr.schedparam_policy = _thread_run->attr.schedparam_policy;
177 } else {
178 /*
179 * Use just the thread priority, leaving the
180 * other scheduling attributes as their
181 * default values:
182 */
183 new_thread->pthread_priority = new_thread->attr.prio;
184 }
185
186 /* Initialise the join queue for the new thread: */
187 _thread_queue_init(&(new_thread->join_queue));
188
189 /* Initialise hooks in the thread structure: */
190 new_thread->specific_data = NULL;
191 new_thread->cleanup = NULL;
192 new_thread->queue = NULL;
193 new_thread->qnxt = NULL;
194 new_thread->parent_thread = parent;
195 new_thread->flags = 0;
196
197 /* Add the thread to the linked list of all threads: */
198 new_thread->nxt = _thread_link_list;
199 _thread_link_list = new_thread;
200
201 /* Return a pointer to the thread structure: */
1/*
2 * Copyright (c) 1995 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 REGENTS 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 */
33#include <errno.h>
34#include <stdlib.h>
35#include <string.h>
36#include <fcntl.h>
37#include <unistd.h>
38#include <sys/time.h>
39#ifdef _THREAD_SAFE
40#include <machine/reg.h>
41#include <pthread.h>
42#include "pthread_private.h"
43
44int
45_thread_create(pthread_t * thread, const pthread_attr_t * attr,
46 void *(*start_routine) (void *), void *arg, pthread_t parent)
47{
48 int i;
49 int ret = 0;
50 int status;
51 pthread_t new_thread;
52 pthread_attr_t pattr;
53 void *stack;
54
55 /* Block signals: */
56 _thread_kern_sig_block(&status);
57
58 /* Allocate memory for the thread structure: */
59 if ((new_thread = (pthread_t) malloc(sizeof(struct pthread))) == NULL) {
60 /* Insufficient memory to create a thread: */
61 ret = EAGAIN;
62 } else {
63 /* Check if default thread attributes are required: */
64 if (attr == NULL || *attr == NULL) {
65 /* Use the default thread attributes: */
66 pattr = &pthread_attr_default;
67 } else {
68 pattr = *attr;
69 }
70 /* Check if a stack was specified in the thread attributes: */
71 if ((stack = pattr->stackaddr_attr) != NULL) {
72 }
73 /* Allocate memory for the stack: */
74 else if ((stack = (void *) malloc(pattr->stacksize_attr)) == NULL) {
75 /* Insufficient memory to create a thread: */
76 ret = EAGAIN;
77 free(new_thread);
78 }
79 /* Check for errors: */
80 if (ret != 0) {
81 } else {
82 /* Initialise the thread structure: */
83 memset(new_thread, 0, sizeof(struct pthread));
84 new_thread->slice_usec = -1;
85 new_thread->sig_saved = 0;
86 new_thread->stack = stack;
87 new_thread->start_routine = start_routine;
88 new_thread->arg = arg;
89 if (pattr->suspend == PTHREAD_CREATE_SUSPENDED) {
90 PTHREAD_NEW_STATE(new_thread,PS_SUSPENDED);
91 } else {
92 PTHREAD_NEW_STATE(new_thread,PS_RUNNING);
93 }
94
95 /* Initialise the thread for signals: */
96 new_thread->sigmask = _thread_run->sigmask;
97
98 /*
99 * Enter a loop to initialise the signal handler
100 * array:
101 */
102 for (i = 1; i < NSIG; i++) {
103 /* Default the signal handler: */
104 sigfillset(&new_thread->act[i - 1].sa_mask);
105 new_thread->act[i - 1].sa_handler = _thread_run->act[i - 1].sa_handler;
106 new_thread->act[i - 1].sa_flags = _thread_run->act[i - 1].sa_flags;
107 }
108
109 /* Initialise the jump buffer: */
110 _thread_sys_setjmp(new_thread->saved_jmp_buf);
111
112 /*
113 * Set up new stack frame so that it looks like it
114 * returned from a longjmp() to the beginning of
115 * _thread_start(). Check if this is a user thread:
116 */
117 if (parent == NULL) {
118 /* Use the user start function: */
119#if defined(__FreeBSD__)
120 new_thread->saved_jmp_buf[0]._jb[0] = (long) _thread_start;
121#elif defined(__NetBSD__)
122#if defined(__alpha)
123 new_thread->saved_jmp_buf[2] = (long) _thread_start;
124 new_thread->saved_jmp_buf[4 + R_RA] = 0;
125 new_thread->saved_jmp_buf[4 + R_T12] = (long) _thread_start;
126#else
127 new_thread->saved_jmp_buf[0] = (long) _thread_start;
128#endif
129#else
130#error "Don't recognize this operating system!"
131#endif
132 } else {
133 /*
134 * Use the (funny) signal handler start
135 * function:
136 */
137#if defined(__FreeBSD__)
138 new_thread->saved_jmp_buf[0]._jb[0] = (int) _thread_start_sig_handler;
139#elif defined(__NetBSD__)
140#if defined(__alpha)
141 new_thread->saved_jmp_buf[2] = (long) _thread_start_sig_handler;
142 new_thread->saved_jmp_buf[4 + R_RA] = 0;
143 new_thread->saved_jmp_buf[4 + R_T12] = (long) _thread_start_sig_handler;
144#else
145 new_thread->saved_jmp_buf[0] = (long) _thread_start_sig_handler;
146#endif
147#else
148#error "Don't recognize this operating system!"
149#endif
150 }
151
152 /* The stack starts high and builds down: */
153#if defined(__FreeBSD__)
154 new_thread->saved_jmp_buf[0]._jb[2] = (int) (new_thread->stack + pattr->stacksize_attr - sizeof(double));
155#elif defined(__NetBSD__)
156#if defined(__alpha)
157 new_thread->saved_jmp_buf[4 + R_SP] = (long) new_thread->stack + pattr->stacksize_attr - sizeof(double);
158#else
159 new_thread->saved_jmp_buf[2] = (long) new_thread->stack + pattr->stacksize_attr - sizeof(double);
160#endif
161#else
162#error "Don't recognize this operating system!"
163#endif
164
165 /* Copy the thread attributes: */
166 memcpy(&new_thread->attr, pattr, sizeof(struct pthread_attr));
167
168 /*
169 * Check if this thread is to inherit the scheduling
170 * attributes from its parent:
171 */
172 if (new_thread->attr.flags & PTHREAD_INHERIT_SCHED) {
173 /* Copy the scheduling attributes: */
174 new_thread->pthread_priority = _thread_run->pthread_priority;
175 new_thread->attr.prio = _thread_run->pthread_priority;
176 new_thread->attr.schedparam_policy = _thread_run->attr.schedparam_policy;
177 } else {
178 /*
179 * Use just the thread priority, leaving the
180 * other scheduling attributes as their
181 * default values:
182 */
183 new_thread->pthread_priority = new_thread->attr.prio;
184 }
185
186 /* Initialise the join queue for the new thread: */
187 _thread_queue_init(&(new_thread->join_queue));
188
189 /* Initialise hooks in the thread structure: */
190 new_thread->specific_data = NULL;
191 new_thread->cleanup = NULL;
192 new_thread->queue = NULL;
193 new_thread->qnxt = NULL;
194 new_thread->parent_thread = parent;
195 new_thread->flags = 0;
196
197 /* Add the thread to the linked list of all threads: */
198 new_thread->nxt = _thread_link_list;
199 _thread_link_list = new_thread;
200
201 /* Return a pointer to the thread structure: */
202 (*thread) = new_thread;
202 if(thread)
203 (*thread) = new_thread;
203
204 /* Check if a parent thread was specified: */
205 if (parent != NULL) {
206 /*
207 * A parent thread was specified, so this is
208 * a signal handler thread which must now
209 * wait for the signal handler to complete:
210 */
211 PTHREAD_NEW_STATE(parent,PS_SIGTHREAD);
212 } else {
213 /* Schedule the new user thread: */
214 _thread_kern_sched(NULL);
215 }
216 }
217 }
218
219 /* Unblock signals: */
220 _thread_kern_sig_unblock(status);
221
222 /* Return the status: */
223 return (ret);
224}
225
226int
227pthread_create(pthread_t * thread, const pthread_attr_t * attr,
228 void *(*start_routine) (void *), void *arg)
229{
230 int ret = 0;
231
232 /*
233 * Call the low level thread creation function which allows a parent
234 * thread to be specified:
235 */
236 ret = _thread_create(thread, attr, start_routine, arg, NULL);
237
238 /* Return the status: */
239 return (ret);
240}
241
242void
243_thread_start(void)
244{
245 /* Run the current thread's start routine with argument: */
246 pthread_exit(_thread_run->start_routine(_thread_run->arg));
247
248 /* This point should never be reached. */
249 PANIC("Thread has resumed after exit");
250}
251
252void
253_thread_start_sig_handler(void)
254{
255 int sig;
256 long arg;
257 void (*sig_routine) (int);
258
259 /*
260 * Cast the argument from 'void *' to a variable that is NO SMALLER
261 * than a pointer (otherwise gcc under NetBSD/Alpha will complain):
262 */
263 arg = (long) _thread_run->arg;
264
265 /* Cast the argument as a signal number: */
266 sig = (int) arg;
267
268 /* Cast a pointer to the signal handler function: */
269 sig_routine = (void (*) (int)) _thread_run->start_routine;
270
271 /* Call the signal handler function: */
272 (*sig_routine) (sig);
273
274 /* Exit the signal handler thread: */
275 pthread_exit(&arg);
276
277 /* This point should never be reached. */
278 PANIC("Signal handler thread has resumed after exit");
279}
280#endif
204
205 /* Check if a parent thread was specified: */
206 if (parent != NULL) {
207 /*
208 * A parent thread was specified, so this is
209 * a signal handler thread which must now
210 * wait for the signal handler to complete:
211 */
212 PTHREAD_NEW_STATE(parent,PS_SIGTHREAD);
213 } else {
214 /* Schedule the new user thread: */
215 _thread_kern_sched(NULL);
216 }
217 }
218 }
219
220 /* Unblock signals: */
221 _thread_kern_sig_unblock(status);
222
223 /* Return the status: */
224 return (ret);
225}
226
227int
228pthread_create(pthread_t * thread, const pthread_attr_t * attr,
229 void *(*start_routine) (void *), void *arg)
230{
231 int ret = 0;
232
233 /*
234 * Call the low level thread creation function which allows a parent
235 * thread to be specified:
236 */
237 ret = _thread_create(thread, attr, start_routine, arg, NULL);
238
239 /* Return the status: */
240 return (ret);
241}
242
243void
244_thread_start(void)
245{
246 /* Run the current thread's start routine with argument: */
247 pthread_exit(_thread_run->start_routine(_thread_run->arg));
248
249 /* This point should never be reached. */
250 PANIC("Thread has resumed after exit");
251}
252
253void
254_thread_start_sig_handler(void)
255{
256 int sig;
257 long arg;
258 void (*sig_routine) (int);
259
260 /*
261 * Cast the argument from 'void *' to a variable that is NO SMALLER
262 * than a pointer (otherwise gcc under NetBSD/Alpha will complain):
263 */
264 arg = (long) _thread_run->arg;
265
266 /* Cast the argument as a signal number: */
267 sig = (int) arg;
268
269 /* Cast a pointer to the signal handler function: */
270 sig_routine = (void (*) (int)) _thread_run->start_routine;
271
272 /* Call the signal handler function: */
273 (*sig_routine) (sig);
274
275 /* Exit the signal handler thread: */
276 pthread_exit(&arg);
277
278 /* This point should never be reached. */
279 PANIC("Signal handler thread has resumed after exit");
280}
281#endif