thr_create.c revision 92730
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 92730 2002-03-19 22:58:56Z 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 "pthread_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(ctx);
54#undef OFF
55
56int _thread_PS_RUNNING_value		= PS_RUNNING;
57int _thread_PS_DEAD_value		= PS_DEAD;
58
59__weak_reference(_pthread_create, pthread_create);
60
61int
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
74	/*
75	 * Locking functions in libc are required when there are
76	 * threads other than the initial thread.
77	 */
78	__isthreaded = 1;
79
80	/* Allocate memory for the thread structure: */
81	if ((new_thread = (pthread_t) malloc(sizeof(struct pthread))) == NULL) {
82		/* Insufficient memory to create a thread: */
83		ret = EAGAIN;
84	} else {
85		/* Check if default thread attributes are required: */
86		if (attr == NULL || *attr == NULL) {
87			/* Use the default thread attributes: */
88			pattr = &pthread_attr_default;
89		} else {
90			pattr = *attr;
91		}
92		/* Check if a stack was specified in the thread attributes: */
93		if ((stack = pattr->stackaddr_attr) != NULL) {
94		}
95		/* Allocate a stack: */
96		else {
97			stack = _thread_stack_alloc(pattr->stacksize_attr,
98			    pattr->guardsize_attr);
99			if (stack == NULL) {
100				ret = EAGAIN;
101				free(new_thread);
102			}
103		}
104
105		/* Check for errors: */
106		if (ret != 0) {
107		} else {
108			/* Initialise the thread structure: */
109			memset(new_thread, 0, sizeof(struct pthread));
110			new_thread->slice_usec = -1;
111			new_thread->stack = stack;
112			new_thread->start_routine = start_routine;
113			new_thread->arg = arg;
114
115			new_thread->cancelflags = PTHREAD_CANCEL_ENABLE |
116			    PTHREAD_CANCEL_DEFERRED;
117
118			/*
119			 * Write a magic value to the thread structure
120			 * to help identify valid ones:
121			 */
122			new_thread->magic = PTHREAD_MAGIC;
123
124			/* Initialise the thread for signals: */
125			new_thread->sigmask = curthread->sigmask;
126			new_thread->sigmask_seqno = 0;
127
128			/* Initialize the signal frame: */
129			new_thread->curframe = NULL;
130
131			/* Initialise the jump buffer: */
132			_setjmp(new_thread->ctx.jb);
133
134			/*
135			 * Set up new stack frame so that it looks like it
136			 * returned from a longjmp() to the beginning of
137			 * _thread_start().
138			 */
139			SET_RETURN_ADDR_JB(new_thread->ctx.jb, _thread_start);
140
141			/* The stack starts high and builds down: */
142			SET_STACK_JB(new_thread->ctx.jb,
143			    (long)new_thread->stack + pattr->stacksize_attr
144			    - sizeof(double));
145
146			/* Copy the thread attributes: */
147			memcpy(&new_thread->attr, pattr, sizeof(struct pthread_attr));
148
149			/*
150			 * Check if this thread is to inherit the scheduling
151			 * attributes from its parent:
152			 */
153			if (new_thread->attr.flags & PTHREAD_INHERIT_SCHED) {
154				/* Copy the scheduling attributes: */
155				new_thread->base_priority =
156				    curthread->base_priority &
157				    ~PTHREAD_SIGNAL_PRIORITY;
158				new_thread->attr.prio =
159				    curthread->base_priority &
160				    ~PTHREAD_SIGNAL_PRIORITY;
161				new_thread->attr.sched_policy =
162				    curthread->attr.sched_policy;
163			} else {
164				/*
165				 * Use just the thread priority, leaving the
166				 * other scheduling attributes as their
167				 * default values:
168				 */
169				new_thread->base_priority =
170				    new_thread->attr.prio;
171			}
172			new_thread->active_priority = new_thread->base_priority;
173			new_thread->inherited_priority = 0;
174
175			/* Initialize joiner to NULL (no joiner): */
176			new_thread->joiner = NULL;
177
178			/* Initialize the mutex queue: */
179			TAILQ_INIT(&new_thread->mutexq);
180
181			/* Initialise hooks in the thread structure: */
182			new_thread->specific = NULL;
183			new_thread->cleanup = NULL;
184			new_thread->flags = 0;
185			new_thread->poll_data.nfds = 0;
186			new_thread->poll_data.fds = NULL;
187			new_thread->continuation = NULL;
188
189			/*
190			 * Defer signals to protect the scheduling queues
191			 * from access by the signal handler:
192			 */
193			_thread_kern_sig_defer();
194
195			/*
196			 * Initialise the unique id which GDB uses to
197			 * track threads.
198			 */
199			new_thread->uniqueid = next_uniqueid++;
200
201			/*
202			 * Check if the garbage collector thread
203			 * needs to be started.
204			 */
205			f_gc = (TAILQ_FIRST(&_thread_list) == _thread_initial);
206
207			/* Add the thread to the linked list of all threads: */
208			TAILQ_INSERT_HEAD(&_thread_list, new_thread, tle);
209
210			if (pattr->suspend == PTHREAD_CREATE_SUSPENDED)
211				new_thread->state = PS_SUSPENDED;
212			else {
213				new_thread->state = PS_RUNNING;
214				PTHREAD_PRIOQ_INSERT_TAIL(new_thread);
215			}
216
217			/*
218			 * Undefer and handle pending signals, yielding
219			 * if necessary.
220			 */
221			_thread_kern_sig_undefer();
222
223			/* Return a pointer to the thread structure: */
224			(*thread) = new_thread;
225
226			if (f_gc != 0) {
227				/* Install the scheduling timer: */
228				itimer.it_interval.tv_sec = 0;
229				itimer.it_interval.tv_usec = _clock_res_usec;
230				itimer.it_value = itimer.it_interval;
231				if (setitimer(_ITIMER_SCHED_TIMER, &itimer,
232				    NULL) != 0)
233					PANIC("Cannot set interval timer");
234			}
235
236			/* Schedule the new user thread: */
237			_thread_kern_sched(NULL);
238
239			/*
240			 * Start a garbage collector thread
241			 * if necessary.
242			 */
243			if (f_gc && pthread_create(&gc_thread,NULL,
244				    _thread_gc,NULL) != 0)
245				PANIC("Can't create gc thread");
246
247		}
248	}
249
250	/* Return the status: */
251	return (ret);
252}
253
254void
255_thread_start(void)
256{
257	struct pthread	*curthread = _get_curthread();
258
259	/* We just left the scheduler via longjmp: */
260	_thread_kern_in_sched = 0;
261
262	/* Run the current thread's start routine with argument: */
263	pthread_exit(curthread->start_routine(curthread->arg));
264
265	/* This point should never be reached. */
266	PANIC("Thread has resumed after exit");
267}
268