1 /*	$OpenBSD: uthread_create.c,v 1.21 2005/01/23 19:23:47 kettenis Exp $	*/
2 /*
3  * Copyright (c) 1995-1998 John Birrell <jb@cimlogic.com.au>
4  * All rights reserved.
5  *
6  * Redistribution and use in source and binary forms, with or without
7  * modification, are permitted provided that the following conditions
8  * are met:
9  * 1. Redistributions of source code must retain the above copyright
10  *    notice, this list of conditions and the following disclaimer.
11  * 2. Redistributions in binary form must reproduce the above copyright
12  *    notice, this list of conditions and the following disclaimer in the
13  *    documentation and/or other materials provided with the distribution.
14  * 3. All advertising materials mentioning features or use of this software
15  *    must display the following acknowledgement:
16  *	This product includes software developed by John Birrell.
17  * 4. Neither the name of the author nor the names of any co-contributors
18  *    may be used to endorse or promote products derived from this software
19  *    without specific prior written permission.
20  *
21  * THIS SOFTWARE IS PROVIDED BY JOHN BIRRELL AND CONTRIBUTORS ``AS IS'' AND
22  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
23  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
24  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
25  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
26  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
27  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
28  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
29  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
30  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
31  * SUCH DAMAGE.
32  *
33  * $FreeBSD: uthread_create.c,v 1.19 1999/08/28 00:03:28 peter 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/types.h>
43 #include <sys/mman.h>
44 #ifdef _THREAD_SAFE
45 #include <machine/reg.h>
46 #include <pthread.h>
47 #include "pthread_private.h"
48 
49 /* Symbols that help gdb find the information it needs. */
50 int _thread_next_offset = offsetof(struct pthread, tle.tqe_next);
51 int _thread_state_offset = offsetof(struct pthread, state);
52 
53 int
pthread_create(pthread_t * thread,const pthread_attr_t * attr,void * (* start_routine)(void *),void * arg)54 pthread_create(pthread_t *thread, const pthread_attr_t *attr,
55 	       void *(*start_routine) (void *), void *arg)
56 {
57 	struct pthread	*curthread = _get_curthread();
58 	struct itimerval itimer;
59 	int		f_gc = 0;
60 	int             ret = 0;
61 	pthread_t       gc_thread;
62 	pthread_t       new_thread;
63 	pthread_attr_t	pattr;
64 	struct stack   *stack;
65 
66 	if (thread == NULL)
67 		return(EINVAL);
68 
69 	/*
70 	 * Locking functions in libc are required when there are
71 	 * threads other than the initial thread.
72 	 */
73 	__isthreaded = 1;
74 
75 	/* Allocate memory for the thread structure: */
76 	if ((new_thread = (pthread_t) malloc(sizeof(struct pthread))) == NULL) {
77 		/* Insufficient memory to create a thread: */
78 		ret = EAGAIN;
79 	} else {
80 		/* Check if default thread attributes are required: */
81 		if (attr == NULL || *attr == NULL) {
82 			/* Use the default thread attributes: */
83 			pattr = &pthread_attr_default;
84 		} else {
85 			pattr = *attr;
86 		}
87 		/* Check if a stack was specified in the thread attributes: */
88 		if ((stack = pattr->stackaddr_attr) != NULL) {
89 		}
90 		/* Allocate a stack: */
91 		else {
92 			stack = _thread_stack_alloc(pattr->stackaddr_attr,
93 			    pattr->stacksize_attr);
94 			if (stack == NULL) {
95 				ret = EAGAIN;
96 				free(new_thread);
97 			}
98 		}
99 
100 		/* Check for errors: */
101 		if (ret != 0) {
102 		} else {
103 			/* Initialise the thread structure: */
104 			memset(new_thread, 0, sizeof(struct pthread));
105 			_SPINLOCK_INIT(&new_thread->lock);
106 			new_thread->slice_usec = -1;
107 			new_thread->sig_saved = 0;
108 			new_thread->stack = stack;
109 			new_thread->start_routine = start_routine;
110 			new_thread->arg = arg;
111 
112 			new_thread->cancelflags = PTHREAD_CANCEL_ENABLE |
113 			    PTHREAD_CANCEL_DEFERRED;
114 
115 			/*
116 			 * Write a magic value to the thread structure
117 			 * to help identify valid ones:
118 			 */
119 			new_thread->magic = PTHREAD_MAGIC;
120 
121 			/* Initialise the thread for signals: */
122 			new_thread->sigmask = curthread->sigmask;
123 
124 			/*
125 			 * Set up new stack frame so that it 'returns' to
126 			 * the beginning of _thread_start() after it is
127 			 * switched to:
128 			 */
129 			_thread_machdep_init(&new_thread->_machdep,
130 			    stack->base, stack->size, _thread_start);
131 
132 			/* Copy the thread attributes: */
133 			memcpy(&new_thread->attr, pattr, sizeof(struct pthread_attr));
134 
135 			/*
136 			 * Check if this thread is to inherit the scheduling
137 			 * attributes from its parent:
138 			 */
139 			if (new_thread->attr.flags & PTHREAD_INHERIT_SCHED) {
140 				/* Copy the scheduling attributes: */
141 				new_thread->base_priority =
142 				    curthread->base_priority &
143 				    ~PTHREAD_SIGNAL_PRIORITY;
144 				new_thread->attr.prio =
145 				    curthread->base_priority &
146 				    ~PTHREAD_SIGNAL_PRIORITY;
147 				new_thread->attr.sched_policy =
148 				    curthread->attr.sched_policy;
149 			} else {
150 				/*
151 				 * Use just the thread priority, leaving the
152 				 * other scheduling attributes as their
153 				 * default values:
154 				 */
155 				new_thread->base_priority =
156 				    new_thread->attr.prio;
157 			}
158 			new_thread->active_priority = new_thread->base_priority;
159 			new_thread->inherited_priority = 0;
160 
161 			/* Initialize joiner to NULL (no joiner): */
162 			new_thread->joiner = NULL;
163 
164 			/* Initialize the mutex queue: */
165 			TAILQ_INIT(&new_thread->mutexq);
166 
167 			/* Initialise hooks in the thread structure: */
168 			new_thread->specific_data = NULL;
169 			new_thread->cleanup = NULL;
170 			new_thread->flags = 0;
171 			new_thread->poll_data.nfds = 0;
172 			new_thread->poll_data.fds = NULL;
173 			new_thread->continuation = NULL;
174 
175 			/*
176 			 * Defer signals to protect the scheduling queues
177 			 * from access by the signal handler:
178 			 */
179 			_thread_kern_sig_defer();
180 
181 			/*
182 			 * Check if the garbage collector thread
183 			 * needs to be started.
184 			 */
185 			f_gc = (TAILQ_FIRST(&_thread_list) == _thread_initial);
186 
187 			/* Add the thread to the linked list of all threads: */
188 			TAILQ_INSERT_HEAD(&_thread_list, new_thread, tle);
189 
190 			if (pattr->suspend == PTHREAD_CREATE_SUSPENDED)
191 				new_thread->state = PS_SUSPENDED;
192 			else {
193 				new_thread->state = PS_RUNNING;
194 				PTHREAD_PRIOQ_INSERT_TAIL(new_thread);
195 			}
196 
197 			/*
198 			 * Undefer and handle pending signals, yielding
199 			 * if necessary.
200 			 */
201 			_thread_kern_sig_undefer();
202 
203 			/* Return a pointer to the thread structure: */
204 			if (thread != NULL)
205 				(*thread) = new_thread;
206 
207 			if (f_gc != 0) {
208 				/* Install the scheduling timer: */
209 				itimer.it_interval.tv_sec = 0;
210 				itimer.it_interval.tv_usec = _clock_res_usec;
211 				itimer.it_value = itimer.it_interval;
212 				if (setitimer(_ITIMER_SCHED_TIMER, &itimer,
213 				    NULL) != 0)
214 					PANIC("Cannot set interval timer");
215 			}
216 
217 			/* Schedule the new user thread: */
218 			_thread_kern_sched(NULL);
219 
220 			/*
221 			 * Start a garbage collector thread
222 			 * if necessary.
223 			 */
224 			if (f_gc && pthread_create(&gc_thread,NULL,
225 				    _thread_gc,NULL) != 0)
226 				PANIC("Can't create gc thread");
227 
228 		}
229 	}
230 
231 	/* Return the status: */
232 	return (ret);
233 }
234 
235 void
_thread_start(void)236 _thread_start(void)
237 {
238 	struct pthread	*curthread = _get_curthread();
239 
240 	/* We just left the scheduler via longjmp: */
241 	_thread_kern_in_sched = 0;
242 
243 	/* Run the current thread's start routine with argument: */
244 	pthread_exit(curthread->start_routine(curthread->arg));
245 
246 	/* This point should never be reached. */
247 	PANIC("Thread has resumed after exit");
248 }
249 #endif
250