thr_create.c revision 106191
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 106191 2002-10-30 06:07:18Z mini $
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(mailbox.tm_context);
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 machine context: */
125			getcontext(&new_thread->mailbox.tm_context);
126			new_thread->mailbox.tm_context.uc_stack.ss_sp =
127			    new_thread->stack;
128			new_thread->mailbox.tm_context.uc_stack.ss_size =
129			    pattr->stacksize_attr;
130			makecontext(&new_thread->mailbox.tm_context,
131			    _thread_start, 1);
132			new_thread->mailbox.tm_udata = (void *)new_thread;
133
134			/* Copy the thread attributes: */
135			memcpy(&new_thread->attr, pattr, sizeof(struct pthread_attr));
136
137			/*
138			 * Check if this thread is to inherit the scheduling
139			 * attributes from its parent:
140			 */
141			if (new_thread->attr.flags & PTHREAD_INHERIT_SCHED) {
142				/* Copy the scheduling attributes: */
143				new_thread->base_priority =
144				    curthread->base_priority &
145				    ~PTHREAD_SIGNAL_PRIORITY;
146				new_thread->attr.prio =
147				    curthread->base_priority &
148				    ~PTHREAD_SIGNAL_PRIORITY;
149				new_thread->attr.sched_policy =
150				    curthread->attr.sched_policy;
151			} else {
152				/*
153				 * Use just the thread priority, leaving the
154				 * other scheduling attributes as their
155				 * default values:
156				 */
157				new_thread->base_priority =
158				    new_thread->attr.prio;
159			}
160			new_thread->active_priority = new_thread->base_priority;
161			new_thread->inherited_priority = 0;
162
163			/* Initialize joiner to NULL (no joiner): */
164			new_thread->joiner = NULL;
165
166			/* Initialize the mutex queue: */
167			TAILQ_INIT(&new_thread->mutexq);
168
169			/* Initialise hooks in the thread structure: */
170			new_thread->specific = NULL;
171			new_thread->cleanup = NULL;
172			new_thread->flags = 0;
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			 * Initialise the unique id which GDB uses to
183			 * track threads.
184			 */
185			new_thread->uniqueid = next_uniqueid++;
186
187			/*
188			 * Check if the garbage collector thread
189			 * needs to be started.
190			 */
191			f_gc = (TAILQ_FIRST(&_thread_list) == _thread_initial);
192
193			/* Add the thread to the linked list of all threads: */
194			TAILQ_INSERT_HEAD(&_thread_list, new_thread, tle);
195
196			if (pattr->suspend == PTHREAD_CREATE_SUSPENDED) {
197				new_thread->flags |= PTHREAD_FLAGS_SUSPENDED;
198				new_thread->state = PS_SUSPENDED;
199			} else {
200				new_thread->state = PS_RUNNING;
201				PTHREAD_PRIOQ_INSERT_TAIL(new_thread);
202			}
203
204			/*
205			 * Undefer and handle pending signals, yielding
206			 * if necessary.
207			 */
208			_thread_kern_sig_undefer();
209
210			/* Return a pointer to the thread structure: */
211			(*thread) = new_thread;
212
213			/* Schedule the new user thread: */
214			_thread_kern_sched();
215
216			/*
217			 * Start a garbage collector thread
218			 * if necessary.
219			 */
220			if (f_gc && pthread_create(&gc_thread,NULL,
221				    _thread_gc,NULL) != 0)
222				PANIC("Can't create gc thread");
223
224		}
225	}
226
227	/* Return the status: */
228	return (ret);
229}
230
231void
232_thread_start(void)
233{
234	struct pthread	*curthread = _get_curthread();
235
236	/* Run the current thread's start routine with argument: */
237	pthread_exit(curthread->start_routine(curthread->arg));
238
239	/* This point should never be reached. */
240	PANIC("Thread has resumed after exit");
241}
242