thr_create.c revision 113658
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: head/lib/libkse/thread/thr_create.c 113658 2003-04-18 05:04:16Z deischen $
33 */
34#include <errno.h>
35#include <stdlib.h>
36#include <string.h>
37#include <fcntl.h>
38#include <unistd.h>
39#include <stddef.h>
40#include <sys/time.h>
41#include <machine/reg.h>
42#include <pthread.h>
43#include "thr_private.h"
44#include "libc_private.h"
45
46static u_int64_t next_uniqueid = 1;
47
48#define OFF(f)	offsetof(struct pthread, f)
49int _thread_next_offset			= OFF(tle.tqe_next);
50int _thread_uniqueid_offset		= OFF(uniqueid);
51int _thread_state_offset		= OFF(state);
52int _thread_name_offset			= OFF(name);
53int _thread_ctx_offset			= OFF(tmbx.tm_context);
54#undef OFF
55
56int _thread_PS_RUNNING_value		= PS_RUNNING;
57int _thread_PS_DEAD_value		= PS_DEAD;
58
59static int  create_stack(struct pthread_attr *pattr);
60static void thread_start(struct pthread *curthread,
61		void *(*start_routine) (void *), void *arg);
62
63__weak_reference(_pthread_create, pthread_create);
64
65/*
66 * Some notes on new thread creation and first time initializion
67 * to enable multi-threading.
68 *
69 * There are basically two things that need to be done.
70 *
71 *   1) The internal library variables must be initialized.
72 *   2) Upcalls need to be enabled to allow multiple threads
73 *      to be run.
74 *
75 * The first may be done as a result of other pthread functions
76 * being called.  When _thr_initial is null, _libpthread_init is
77 * called to initialize the internal variables; this also creates
78 * or sets the initial thread.  It'd be nice to automatically
79 * have _libpthread_init called on program execution so we don't
80 * have to have checks throughout the library.
81 *
82 * The second part is only triggered by the creation of the first
83 * thread (other than the initial/main thread).  If the thread
84 * being created is a scope system thread, then a new KSE/KSEG
85 * pair needs to be allocated.  Also, if upcalls haven't been
86 * enabled on the initial thread's KSE, they must be now that
87 * there is more than one thread; this could be delayed until
88 * the initial KSEG has more than one thread.
89 */
90int
91_pthread_create(pthread_t * thread, const pthread_attr_t * attr,
92	       void *(*start_routine) (void *), void *arg)
93{
94	struct kse *curkse;
95	struct pthread *curthread, *new_thread;
96	struct kse *kse = NULL;
97	struct kse_group *kseg = NULL;
98	kse_critical_t crit;
99	int i;
100	int ret = 0;
101
102	if (_thr_initial == NULL)
103		_libpthread_init(NULL);
104
105	crit = _kse_critical_enter();
106	curthread = _get_curthread();
107	curkse = curthread->kse;
108
109	/* Allocate memory for the thread structure: */
110	if ((new_thread = _thr_alloc(curkse)) == NULL) {
111		/* Insufficient memory to create a thread: */
112		ret = EAGAIN;
113	} else {
114		/* Initialize the thread structure: */
115		memset(new_thread, 0, sizeof(struct pthread));
116
117		/* Check if default thread attributes are required: */
118		if (attr == NULL || *attr == NULL)
119			/* Use the default thread attributes: */
120			new_thread->attr = _pthread_attr_default;
121		else
122			new_thread->attr = *(*attr);
123
124		if (create_stack(&new_thread->attr) != 0) {
125			/* Insufficient memory to create a stack: */
126			ret = EAGAIN;
127			_thr_free(curkse, new_thread);
128		}
129		else if (((new_thread->attr.flags & PTHREAD_SCOPE_SYSTEM) != 0) &&
130		    (((kse = _kse_alloc(curkse)) == NULL)
131		    || ((kseg = _kseg_alloc(curkse)) == NULL))) {
132			/* Insufficient memory to create a new KSE/KSEG: */
133			ret = EAGAIN;
134			if (kse != NULL)
135				_kse_free(curkse, kse);
136			if ((new_thread->attr.flags & THR_STACK_USER) == 0) {
137				KSE_LOCK_ACQUIRE(curkse, &_thread_list_lock);
138				_thr_stack_free(&new_thread->attr);
139				KSE_LOCK_RELEASE(curkse, &_thread_list_lock);
140			}
141			_thr_free(curkse, new_thread);
142		}
143		else {
144			if (kseg != NULL) {
145				/* Add the KSE to the KSEG's list of KSEs. */
146				TAILQ_INSERT_HEAD(&kseg->kg_kseq, kse, k_qe);
147				kse->k_kseg = kseg;
148				kse->k_schedq = &kseg->kg_schedq;
149			}
150			/*
151			 * Write a magic value to the thread structure
152			 * to help identify valid ones:
153			 */
154			new_thread->magic = THR_MAGIC;
155
156			new_thread->slice_usec = -1;
157			new_thread->start_routine = start_routine;
158			new_thread->arg = arg;
159			new_thread->cancelflags = PTHREAD_CANCEL_ENABLE |
160			    PTHREAD_CANCEL_DEFERRED;
161
162			/* Initialize the thread for signals: */
163			new_thread->sigmask = curthread->sigmask;
164
165			/* No thread is wanting to join to this one: */
166			new_thread->joiner = NULL;
167
168			/* Initialize the signal frame: */
169			new_thread->curframe = NULL;
170
171			/* Initialize the machine context: */
172			THR_GETCONTEXT(&new_thread->tmbx.tm_context);
173			new_thread->tmbx.tm_udata = new_thread;
174			new_thread->tmbx.tm_context.uc_sigmask =
175			    new_thread->sigmask;
176			new_thread->tmbx.tm_context.uc_stack.ss_size =
177			    new_thread->attr.stacksize_attr;
178			new_thread->tmbx.tm_context.uc_stack.ss_sp =
179			    new_thread->attr.stackaddr_attr;
180
181			makecontext(&new_thread->tmbx.tm_context,
182			    (void (*)(void))thread_start, 4, new_thread,
183			    start_routine, arg);
184
185			/*
186			 * Check if this thread is to inherit the scheduling
187			 * attributes from its parent:
188			 */
189			if ((new_thread->attr.flags & PTHREAD_INHERIT_SCHED) != 0) {
190				/* Copy the scheduling attributes: */
191				new_thread->base_priority =
192				    curthread->base_priority &
193				    ~THR_SIGNAL_PRIORITY;
194				new_thread->attr.prio =
195				    curthread->base_priority &
196				    ~THR_SIGNAL_PRIORITY;
197				new_thread->attr.sched_policy =
198				    curthread->attr.sched_policy;
199			} else {
200				/*
201				 * Use just the thread priority, leaving the
202				 * other scheduling attributes as their
203				 * default values:
204				 */
205				new_thread->base_priority =
206				    new_thread->attr.prio;
207			}
208			new_thread->active_priority = new_thread->base_priority;
209			new_thread->inherited_priority = 0;
210
211			/* Initialize the mutex queue: */
212			TAILQ_INIT(&new_thread->mutexq);
213
214			/* Initialize thread locking. */
215			if (_lock_init(&new_thread->lock, LCK_ADAPTIVE,
216			    _thr_lock_wait, _thr_lock_wakeup) != 0)
217				PANIC("Cannot initialize thread lock");
218			for (i = 0; i < MAX_THR_LOCKLEVEL; i++) {
219				_lockuser_init(&new_thread->lockusers[i],
220				    (void *)new_thread);
221				_LCK_SET_PRIVATE2(&new_thread->lockusers[i],
222				    (void *)new_thread);
223			}
224
225			/* Initialise hooks in the thread structure: */
226			new_thread->specific = NULL;
227			new_thread->cleanup = NULL;
228			new_thread->flags = 0;
229			new_thread->continuation = NULL;
230
231			if (new_thread->attr.suspend == THR_CREATE_SUSPENDED)
232				new_thread->state = PS_SUSPENDED;
233			else
234				new_thread->state = PS_RUNNING;
235
236			/*
237			 * System scope threads have their own kse and
238			 * kseg.  Process scope threads are all hung
239			 * off the main process kseg.
240			 */
241			if ((new_thread->attr.flags & PTHREAD_SCOPE_SYSTEM) == 0) {
242				new_thread->kseg = _kse_initial->k_kseg;
243				new_thread->kse = _kse_initial;
244			}
245			else {
246				kse->k_curthread = NULL;
247				kse->k_kseg->kg_flags |= KGF_SINGLE_THREAD;
248				new_thread->kse = kse;
249				new_thread->kseg = kse->k_kseg;
250				kse->k_mbx.km_udata = kse;
251				kse->k_mbx.km_curthread = NULL;
252			}
253			KSE_LOCK_ACQUIRE(curthread->kse, &_thread_list_lock);
254
255			/*
256			 * Initialise the unique id which GDB uses to
257			 * track threads.
258			 */
259			new_thread->uniqueid = next_uniqueid++;
260
261			/* Add the thread to the linked list of all threads: */
262			THR_LIST_ADD(new_thread);
263
264			KSE_LOCK_RELEASE(curthread->kse, &_thread_list_lock);
265
266			/*
267			 * Schedule the new thread starting a new KSEG/KSE
268			 * pair if necessary.
269			 */
270			_thr_schedule_add(curthread, new_thread);
271
272			/* Return a pointer to the thread structure: */
273			(*thread) = new_thread;
274		}
275	}
276	_kse_critical_leave(crit);
277
278	if ((ret == 0) && (_kse_isthreaded() == 0))
279		_kse_setthreaded(1);
280
281	/* Return the status: */
282	return (ret);
283}
284
285static int
286create_stack(struct pthread_attr *pattr)
287{
288	int ret;
289
290	/* Check if a stack was specified in the thread attributes: */
291	if ((pattr->stackaddr_attr) != NULL) {
292		pattr->guardsize_attr = 0;
293		pattr->flags = THR_STACK_USER;
294		ret = 0;
295	}
296	else
297		ret = _thr_stack_alloc(pattr);
298	return (ret);
299}
300
301
302static void
303thread_start(struct pthread *curthread, void *(*start_routine) (void *),
304    void *arg)
305{
306	/* Run the current thread's start routine with argument: */
307	pthread_exit(start_routine(arg));
308
309	/* This point should never be reached. */
310	PANIC("Thread has resumed after exit");
311}
312