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: */
|
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
|