thr_create.c revision 160321
1186545Srwatson/*
2186545Srwatson * Copyright (c) 2003 Daniel M. Eischen <deischen@gdeb.com>
3186545Srwatson * Copyright (c) 2005, David Xu <davidxu@freebsd.org>
4186545Srwatson * All rights reserved.
5186545Srwatson *
6186545Srwatson * Redistribution and use in source and binary forms, with or without
7186545Srwatson * modification, are permitted provided that the following conditions
8186545Srwatson * are met:
9186545Srwatson * 1. Redistributions of source code must retain the above copyright
10186545Srwatson *    notice unmodified, this list of conditions, and the following
11186545Srwatson *    disclaimer.
12186545Srwatson * 2. Redistributions in binary form must reproduce the above copyright
13186545Srwatson *    notice, this list of conditions and the following disclaimer in the
14186545Srwatson *    documentation and/or other materials provided with the distribution.
15186545Srwatson *
16186545Srwatson * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
17186545Srwatson * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
18186545Srwatson * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
19186545Srwatson * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
20186545Srwatson * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
21186545Srwatson * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
22186545Srwatson * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
23186545Srwatson * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
24186545Srwatson * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
25186545Srwatson * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
26186545Srwatson *
27186545Srwatson * $FreeBSD: head/lib/libthr/thread/thr_create.c 160321 2006-07-13 06:35:43Z davidxu $
28186545Srwatson */
29186545Srwatson
30186545Srwatson#include "namespace.h"
31186545Srwatson#include <sys/types.h>
32186545Srwatson#include <sys/signalvar.h>
33186545Srwatson#include <errno.h>
34186545Srwatson#include <stdlib.h>
35186545Srwatson#include <string.h>
36186545Srwatson#include <stddef.h>
37186545Srwatson#include <pthread.h>
38186545Srwatson#include "un-namespace.h"
39186545Srwatson
40186545Srwatson#include "thr_private.h"
41186545Srwatson
42186545Srwatsonstatic int  create_stack(struct pthread_attr *pattr);
43186545Srwatsonstatic void thread_start(struct pthread *curthread);
44186545Srwatson
45186545Srwatson__weak_reference(_pthread_create, pthread_create);
46186545Srwatson
47186545Srwatsonint
48186545Srwatson_pthread_create(pthread_t * thread, const pthread_attr_t * attr,
49186545Srwatson	       void *(*start_routine) (void *), void *arg)
50186545Srwatson{
51186545Srwatson	struct pthread *curthread, *new_thread;
52186545Srwatson	struct thr_param param;
53186545Srwatson	struct thr_sched_param sched_param;
54186545Srwatson	int ret = 0, locked, create_suspended;
55186545Srwatson	sigset_t set, oset;
56186545Srwatson
57186545Srwatson	_thr_check_init();
58186545Srwatson
59186545Srwatson	/*
60186545Srwatson	 * Tell libc and others now they need lock to protect their data.
61186545Srwatson	 */
62186545Srwatson	if (_thr_isthreaded() == 0 && _thr_setthreaded(1))
63186545Srwatson		return (EAGAIN);
64186545Srwatson
65186545Srwatson	curthread = _get_curthread();
66186545Srwatson	if ((new_thread = _thr_alloc(curthread)) == NULL)
67186545Srwatson		return (EAGAIN);
68186545Srwatson
69186545Srwatson	memset(&param, 0, sizeof(param));
70186545Srwatson
71186545Srwatson	if (attr == NULL || *attr == NULL)
72186545Srwatson		/* Use the default thread attributes: */
73186545Srwatson		new_thread->attr = _pthread_attr_default;
74186545Srwatson	else
75186545Srwatson		new_thread->attr = *(*attr);
76186545Srwatson	if (new_thread->attr.sched_inherit == PTHREAD_INHERIT_SCHED) {
77186545Srwatson		/* inherit scheduling contention scope */
78186545Srwatson		if (curthread->attr.flags & PTHREAD_SCOPE_SYSTEM)
79186545Srwatson			new_thread->attr.flags |= PTHREAD_SCOPE_SYSTEM;
80186545Srwatson		else
81186545Srwatson			new_thread->attr.flags &= ~PTHREAD_SCOPE_SYSTEM;
82186545Srwatson		/*
83186545Srwatson		 * scheduling policy and scheduling parameters will be
84186545Srwatson		 * inherited in following code.
85186545Srwatson		 */
86186545Srwatson	}
87186545Srwatson
88186545Srwatson	if (_thr_scope_system > 0)
89186545Srwatson		new_thread->attr.flags |= PTHREAD_SCOPE_SYSTEM;
90186545Srwatson	else if (_thr_scope_system < 0)
91186545Srwatson		new_thread->attr.flags &= ~PTHREAD_SCOPE_SYSTEM;
92186545Srwatson
93186545Srwatson	new_thread->tid = TID_TERMINATED;
94186545Srwatson
95186545Srwatson	if (create_stack(&new_thread->attr) != 0) {
96186545Srwatson		/* Insufficient memory to create a stack: */
97186545Srwatson		_thr_free(curthread, new_thread);
98186545Srwatson		return (EAGAIN);
99186545Srwatson	}
100186545Srwatson	/*
101186545Srwatson	 * Write a magic value to the thread structure
102186545Srwatson	 * to help identify valid ones:
103186545Srwatson	 */
104186545Srwatson	new_thread->magic = THR_MAGIC;
105186545Srwatson	new_thread->start_routine = start_routine;
106186545Srwatson	new_thread->arg = arg;
107186545Srwatson	new_thread->cancelflags = PTHREAD_CANCEL_ENABLE |
108186545Srwatson	    PTHREAD_CANCEL_DEFERRED;
109186545Srwatson	/* Initialize the mutex queue: */
110186545Srwatson	TAILQ_INIT(&new_thread->mutexq);
111186545Srwatson
112186545Srwatson	/* Initialise hooks in the thread structure: */
113186545Srwatson	if (new_thread->attr.suspend == THR_CREATE_SUSPENDED) {
114186545Srwatson		new_thread->flags = THR_FLAGS_NEED_SUSPEND;
115186545Srwatson		create_suspended = 1;
116186545Srwatson	} else {
117186545Srwatson		create_suspended = 0;
118186545Srwatson	}
119186545Srwatson
120186545Srwatson	new_thread->state = PS_RUNNING;
121186545Srwatson
122186545Srwatson	if (new_thread->attr.flags & PTHREAD_CREATE_DETACHED)
123186545Srwatson		new_thread->tlflags |= TLFLAGS_DETACHED;
124186545Srwatson
125186545Srwatson	/* Add the new thread. */
126186545Srwatson	new_thread->refcount = 1;
127186545Srwatson	_thr_link(curthread, new_thread);
128186545Srwatson	/* Return thread pointer eariler so that new thread can use it. */
129186545Srwatson	(*thread) = new_thread;
130186545Srwatson	if (SHOULD_REPORT_EVENT(curthread, TD_CREATE)) {
131186545Srwatson		THR_THREAD_LOCK(curthread, new_thread);
132186545Srwatson		locked = 1;
133186545Srwatson	} else
134186545Srwatson		locked = 0;
135186545Srwatson	param.start_func = (void (*)(void *)) thread_start;
136186545Srwatson	param.arg = new_thread;
137186545Srwatson	param.stack_base = new_thread->attr.stackaddr_attr;
138186545Srwatson	param.stack_size = new_thread->attr.stacksize_attr;
139186545Srwatson	param.tls_base = (char *)new_thread->tcb;
140186545Srwatson	param.tls_size = sizeof(struct tcb);
141186545Srwatson	param.child_tid = &new_thread->tid;
142186545Srwatson	param.parent_tid = &new_thread->tid;
143186545Srwatson	param.flags = 0;
144186545Srwatson	if (new_thread->attr.flags & PTHREAD_SCOPE_SYSTEM)
145186545Srwatson		param.flags |= THR_SYSTEM_SCOPE;
146186545Srwatson	if (new_thread->attr.sched_inherit == PTHREAD_INHERIT_SCHED)
147186545Srwatson		param.sched_param = NULL;
148186545Srwatson	else {
149186545Srwatson		param.sched_param = &sched_param;
150186545Srwatson		param.sched_param_size = sizeof(sched_param);
151186545Srwatson		sched_param.policy = new_thread->attr.sched_policy;
152186545Srwatson		sched_param.param.sched_priority = new_thread->attr.prio;
153186545Srwatson	}
154186545Srwatson
155186545Srwatson	/* Schedule the new thread. */
156186545Srwatson	if (create_suspended) {
157186545Srwatson		SIGFILLSET(set);
158186545Srwatson		SIGDELSET(set, SIGTRAP);
159186545Srwatson		__sys_sigprocmask(SIG_SETMASK, &set, &oset);
160186545Srwatson		new_thread->sigmask = oset;
161186545Srwatson	}
162186545Srwatson
163186545Srwatson	ret = thr_new(&param, sizeof(param));
164186545Srwatson
165186545Srwatson	if (ret != 0) {
166186545Srwatson		ret = errno;
167186545Srwatson		/*
168186545Srwatson		 * Translate EPROCLIM into well-known POSIX code EAGAIN.
169186545Srwatson		 */
170186545Srwatson		if (ret == EPROCLIM)
171186545Srwatson			ret = EAGAIN;
172186545Srwatson	}
173186545Srwatson
174186545Srwatson	if (create_suspended)
175186545Srwatson		__sys_sigprocmask(SIG_SETMASK, &oset, NULL);
176186545Srwatson
177186545Srwatson	if (ret != 0) {
178186545Srwatson		if (!locked)
179186545Srwatson			THR_THREAD_LOCK(curthread, new_thread);
180186545Srwatson		new_thread->state = PS_DEAD;
181186545Srwatson		new_thread->tid = TID_TERMINATED;
182186545Srwatson		if (new_thread->flags & THR_FLAGS_NEED_SUSPEND) {
183186545Srwatson			new_thread->cycle++;
184186545Srwatson			_thr_umtx_wake(&new_thread->cycle, INT_MAX);
185186545Srwatson		}
186186545Srwatson		THR_THREAD_UNLOCK(curthread, new_thread);
187186545Srwatson		THREAD_LIST_LOCK(curthread);
188186545Srwatson		_thread_active_threads--;
189186545Srwatson		new_thread->tlflags |= TLFLAGS_DETACHED;
190186545Srwatson		_thr_ref_delete_unlocked(curthread, new_thread);
191186545Srwatson		THREAD_LIST_UNLOCK(curthread);
192186545Srwatson		(*thread) = 0;
193186545Srwatson	} else if (locked) {
194186545Srwatson		_thr_report_creation(curthread, new_thread);
195186545Srwatson		THR_THREAD_UNLOCK(curthread, new_thread);
196186545Srwatson	}
197186545Srwatson	return (ret);
198186545Srwatson}
199186545Srwatson
200186545Srwatsonstatic int
201186545Srwatsoncreate_stack(struct pthread_attr *pattr)
202186545Srwatson{
203186545Srwatson	int ret;
204186545Srwatson
205186545Srwatson	/* Check if a stack was specified in the thread attributes: */
206186545Srwatson	if ((pattr->stackaddr_attr) != NULL) {
207186545Srwatson		pattr->guardsize_attr = 0;
208186545Srwatson		pattr->flags |= THR_STACK_USER;
209186545Srwatson		ret = 0;
210186545Srwatson	}
211186545Srwatson	else
212186545Srwatson		ret = _thr_stack_alloc(pattr);
213186545Srwatson	return (ret);
214186545Srwatson}
215186545Srwatson
216186545Srwatsonstatic void
217186545Srwatsonthread_start(struct pthread *curthread)
218186545Srwatson{
219186545Srwatson	if (curthread->attr.suspend == THR_CREATE_SUSPENDED) {
220186545Srwatson		sigset_t set = curthread->sigmask;
221186545Srwatson
222186545Srwatson		_thr_ast(curthread);
223186545Srwatson
224186545Srwatson		/*
225186545Srwatson		 * Parent thread have stored signal mask for us,
226186545Srwatson		 * we should restore it now.
227186545Srwatson		 */
228186545Srwatson		sigprocmask(SIG_SETMASK, &set, NULL);
229186545Srwatson	}
230186545Srwatson
231186545Srwatson	/*
232186545Srwatson	 * This is used as a serialization point to allow parent
233186545Srwatson	 * to report 'new thread' event to debugger before the thread
234186545Srwatson	 * does real work.
235186545Srwatson	 */
236186545Srwatson	THR_LOCK(curthread);
237186545Srwatson	THR_UNLOCK(curthread);
238186545Srwatson
239186545Srwatson	/* Run the current thread's start routine with argument: */
240186545Srwatson	_pthread_exit(curthread->start_routine(curthread->arg));
241186545Srwatson
242186545Srwatson	/* This point should never be reached. */
243186545Srwatson	PANIC("Thread has resumed after exit");
244186545Srwatson}
245186545Srwatson