xref: /netbsd-src/lib/libpthread/pthread.c (revision 1296e8508f1aa028d27c049b7dbded8c5d739889)
1*1296e850Sad /*	$NetBSD: pthread.c,v 1.62 2007/02/21 22:31:38 ad Exp $	*/
2c62a74e6Sthorpej 
3c62a74e6Sthorpej /*-
4*1296e850Sad  * Copyright (c) 2001, 2002, 2003, 2006, 2007 The NetBSD Foundation, Inc.
5c62a74e6Sthorpej  * All rights reserved.
6c62a74e6Sthorpej  *
7c62a74e6Sthorpej  * This code is derived from software contributed to The NetBSD Foundation
81ac6a89bSad  * by Nathan J. Williams and Andrew Doran.
9c62a74e6Sthorpej  *
10c62a74e6Sthorpej  * Redistribution and use in source and binary forms, with or without
11c62a74e6Sthorpej  * modification, are permitted provided that the following conditions
12c62a74e6Sthorpej  * are met:
13c62a74e6Sthorpej  * 1. Redistributions of source code must retain the above copyright
14c62a74e6Sthorpej  *    notice, this list of conditions and the following disclaimer.
15c62a74e6Sthorpej  * 2. Redistributions in binary form must reproduce the above copyright
16c62a74e6Sthorpej  *    notice, this list of conditions and the following disclaimer in the
17c62a74e6Sthorpej  *    documentation and/or other materials provided with the distribution.
18c62a74e6Sthorpej  * 3. All advertising materials mentioning features or use of this software
19c62a74e6Sthorpej  *    must display the following acknowledgement:
20c62a74e6Sthorpej  *        This product includes software developed by the NetBSD
21c62a74e6Sthorpej  *        Foundation, Inc. and its contributors.
22c62a74e6Sthorpej  * 4. Neither the name of The NetBSD Foundation nor the names of its
23c62a74e6Sthorpej  *    contributors may be used to endorse or promote products derived
24c62a74e6Sthorpej  *    from this software without specific prior written permission.
25c62a74e6Sthorpej  *
26c62a74e6Sthorpej  * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
27c62a74e6Sthorpej  * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
28c62a74e6Sthorpej  * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
29c62a74e6Sthorpej  * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
30c62a74e6Sthorpej  * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
31c62a74e6Sthorpej  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
32c62a74e6Sthorpej  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
33c62a74e6Sthorpej  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
34c62a74e6Sthorpej  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
35c62a74e6Sthorpej  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
36c62a74e6Sthorpej  * POSSIBILITY OF SUCH DAMAGE.
37c62a74e6Sthorpej  */
38c62a74e6Sthorpej 
39f043c0fbSlukem #include <sys/cdefs.h>
40*1296e850Sad __RCSID("$NetBSD: pthread.c,v 1.62 2007/02/21 22:31:38 ad Exp $");
41f043c0fbSlukem 
42c62a74e6Sthorpej #include <err.h>
43c62a74e6Sthorpej #include <errno.h>
44c62a74e6Sthorpej #include <lwp.h>
45c62a74e6Sthorpej #include <signal.h>
468bcff70bSnathanw #include <stdio.h>
47c62a74e6Sthorpej #include <stdlib.h>
48c62a74e6Sthorpej #include <string.h>
490172694eSnathanw #include <syslog.h>
50c62a74e6Sthorpej #include <ucontext.h>
518bcff70bSnathanw #include <unistd.h>
52f2f10664Scl #include <sys/param.h>
53f2f10664Scl #include <sys/sysctl.h>
54cca94056Schristos #ifdef PTHREAD_MLOCK_KLUDGE
55cca94056Schristos #include <sys/mman.h>
56cca94056Schristos #endif
578bcff70bSnathanw 
58c62a74e6Sthorpej #include <sched.h>
59c62a74e6Sthorpej #include "pthread.h"
60c62a74e6Sthorpej #include "pthread_int.h"
61c62a74e6Sthorpej 
62c62a74e6Sthorpej #ifdef PTHREAD_MAIN_DEBUG
63c62a74e6Sthorpej #define SDPRINTF(x) DPRINTF(x)
64c62a74e6Sthorpej #else
65c62a74e6Sthorpej #define SDPRINTF(x)
66c62a74e6Sthorpej #endif
67c62a74e6Sthorpej 
68ded26025Sad /* Maximum number of LWPs to unpark in one operation. */
69ded26025Sad #define	PTHREAD__UNPARK_MAX	128
70ded26025Sad 
71ded26025Sad /* How many times to try acquiring spin locks on MP systems. */
72ded26025Sad #define	PTHREAD__NSPINS		1000
73ded26025Sad 
74c62a74e6Sthorpej static void	pthread__create_tramp(void *(*start)(void *), void *arg);
756b2b9c62Syamt static void	pthread__dead(pthread_t, pthread_t);
76c62a74e6Sthorpej 
77c62a74e6Sthorpej int pthread__started;
78c62a74e6Sthorpej 
7994a458ceSchs pthread_spin_t pthread__allqueue_lock = __SIMPLELOCK_UNLOCKED;
80c62a74e6Sthorpej struct pthread_queue_t pthread__allqueue;
81c62a74e6Sthorpej 
8294a458ceSchs pthread_spin_t pthread__deadqueue_lock = __SIMPLELOCK_UNLOCKED;
83c62a74e6Sthorpej struct pthread_queue_t pthread__deadqueue;
84f2f10664Scl struct pthread_queue_t *pthread__reidlequeue;
85c62a74e6Sthorpej 
86c62a74e6Sthorpej static int nthreads;
87c62a74e6Sthorpej static int nextthread;
8894a458ceSchs static pthread_spin_t nextthread_lock = __SIMPLELOCK_UNLOCKED;
89c62a74e6Sthorpej static pthread_attr_t pthread_default_attr;
90c62a74e6Sthorpej 
910172694eSnathanw enum {
920172694eSnathanw 	DIAGASSERT_ABORT =	1<<0,
930172694eSnathanw 	DIAGASSERT_STDERR =	1<<1,
940172694eSnathanw 	DIAGASSERT_SYSLOG =	1<<2
950172694eSnathanw };
96df277271Snathanw 
970172694eSnathanw static int pthread__diagassert = DIAGASSERT_ABORT | DIAGASSERT_STDERR;
98df277271Snathanw 
991ac6a89bSad #ifdef PTHREAD_SA
10094a458ceSchs pthread_spin_t pthread__runqueue_lock = __SIMPLELOCK_UNLOCKED;
101c62a74e6Sthorpej struct pthread_queue_t pthread__runqueue;
102c62a74e6Sthorpej struct pthread_queue_t pthread__idlequeue;
10338b1c6f4Schristos struct pthread_queue_t pthread__suspqueue;
104ded26025Sad #endif
105c62a74e6Sthorpej 
106ded26025Sad int pthread__concurrency, pthread__maxconcurrency, pthread__nspins;
107ded26025Sad int pthread__unpark_max = PTHREAD__UNPARK_MAX;
108f2f10664Scl 
109f782e995Sdrochner int _sys___sigprocmask14(int, const sigset_t *, sigset_t *);
110f782e995Sdrochner 
111c62a74e6Sthorpej __strong_alias(__libc_thr_self,pthread_self)
1127dc01dbfSthorpej __strong_alias(__libc_thr_create,pthread_create)
1137dc01dbfSthorpej __strong_alias(__libc_thr_exit,pthread_exit)
114c62a74e6Sthorpej __strong_alias(__libc_thr_errno,pthread__errno)
1159e5c8705Snathanw __strong_alias(__libc_thr_setcancelstate,pthread_setcancelstate)
116c62a74e6Sthorpej 
117c62a74e6Sthorpej /*
118c62a74e6Sthorpej  * Static library kludge.  Place a reference to a symbol any library
119c62a74e6Sthorpej  * file which does not already have a reference here.
120c62a74e6Sthorpej  */
121c62a74e6Sthorpej extern int pthread__cancel_stub_binder;
1221ac6a89bSad #ifdef PTHREAD_SA
123c62a74e6Sthorpej extern int pthread__sched_binder;
1248bcff70bSnathanw extern struct pthread_queue_t pthread__nanosleeping;
1251ac6a89bSad #endif
126c62a74e6Sthorpej 
127c62a74e6Sthorpej void *pthread__static_lib_binder[] = {
128c62a74e6Sthorpej 	&pthread__cancel_stub_binder,
129c62a74e6Sthorpej 	pthread_cond_init,
130c62a74e6Sthorpej 	pthread_mutex_init,
131c62a74e6Sthorpej 	pthread_rwlock_init,
132c62a74e6Sthorpej 	pthread_barrier_init,
133c62a74e6Sthorpej 	pthread_key_create,
134bd9a18b7Snathanw 	pthread_setspecific,
1351ac6a89bSad #ifdef PTHREAD_SA
136c62a74e6Sthorpej 	&pthread__sched_binder,
1378bcff70bSnathanw 	&pthread__nanosleeping
1381ac6a89bSad #endif
139c62a74e6Sthorpej };
140c62a74e6Sthorpej 
141c62a74e6Sthorpej /*
142c62a74e6Sthorpej  * This needs to be started by the library loading code, before main()
143c62a74e6Sthorpej  * gets to run, for various things that use the state of the initial thread
144c62a74e6Sthorpej  * to work properly (thread-specific data is an application-visible example;
145c62a74e6Sthorpej  * spinlock counts for mutexes is an internal example).
146c62a74e6Sthorpej  */
147c62a74e6Sthorpej void
148c62a74e6Sthorpej pthread_init(void)
149c62a74e6Sthorpej {
150c62a74e6Sthorpej 	pthread_t first;
1510172694eSnathanw 	char *p;
152ded26025Sad 	int i, mib[2], ncpu;
153f2f10664Scl 	size_t len;
154c62a74e6Sthorpej 	extern int __isthreaded;
155cca94056Schristos #ifdef PTHREAD_MLOCK_KLUDGE
156cca94056Schristos 	int ret;
157cca94056Schristos #endif
158c62a74e6Sthorpej 
159f2f10664Scl 	mib[0] = CTL_HW;
160f2f10664Scl 	mib[1] = HW_NCPU;
161f2f10664Scl 
162f2f10664Scl 	len = sizeof(ncpu);
163f2f10664Scl 	sysctl(mib, 2, &ncpu, &len, NULL, 0);
164f2f10664Scl 
165c62a74e6Sthorpej 	/* Initialize locks first; they're needed elsewhere. */
166f2f10664Scl 	pthread__lockprim_init(ncpu);
167f2f10664Scl 
1681ac6a89bSad #ifdef PTHREAD_SA
169f2f10664Scl 	/* Find out requested/possible concurrency */
170f2f10664Scl 	p = getenv("PTHREAD_CONCURRENCY");
171b35aef8dSchristos 	pthread__maxconcurrency = p ? atoi(p) : 1;
1723a610280Schristos 
173f2f10664Scl 	if (pthread__maxconcurrency < 1)
174f2f10664Scl 		pthread__maxconcurrency = 1;
175f2f10664Scl 	if (pthread__maxconcurrency > ncpu)
176f2f10664Scl 		pthread__maxconcurrency = ncpu;
177f2f10664Scl 
178f2f10664Scl 	/* Allocate data structures */
179f2f10664Scl 	pthread__reidlequeue = (struct pthread_queue_t *)malloc
180f2f10664Scl 		(pthread__maxconcurrency * sizeof(struct pthread_queue_t));
181f2f10664Scl 	if (pthread__reidlequeue == NULL)
182f2f10664Scl 		err(1, "Couldn't allocate memory for pthread__reidlequeue");
183ded26025Sad 
184ded26025Sad 	pthread__nspins = PTHREAD__NSPINS;
185ded26025Sad #else
186ded26025Sad 	/*
187ded26025Sad 	 * Get number of CPUs, and maximum number of LWPs that can be
188ded26025Sad 	 * unparked at once.
189ded26025Sad 	 */
190ded26025Sad 	if ((pthread__concurrency = ncpu) > 1)
191ded26025Sad 		pthread__nspins = PTHREAD__NSPINS;
192ded26025Sad 	else
193ded26025Sad 		pthread__nspins = 1;
1943247035dSad 	i = (int)_lwp_unpark_all(NULL, 0, NULL);
1953247035dSad 	if (i == -1)
1963247035dSad 		err(1, "_lwp_unpark_all");
197ded26025Sad 	if (i < pthread__unpark_max)
198ded26025Sad 		pthread__unpark_max = i;
1991ac6a89bSad #endif
200c62a74e6Sthorpej 
201c62a74e6Sthorpej 	/* Basic data structure setup */
202c62a74e6Sthorpej 	pthread_attr_init(&pthread_default_attr);
203c62a74e6Sthorpej 	PTQ_INIT(&pthread__allqueue);
204c62a74e6Sthorpej 	PTQ_INIT(&pthread__deadqueue);
205cca94056Schristos #ifdef PTHREAD_MLOCK_KLUDGE
206cca94056Schristos 	ret = mlock(&pthread__deadqueue, sizeof(pthread__deadqueue));
207cca94056Schristos 	pthread__assert(ret == 0);
208cca94056Schristos #endif
2091ac6a89bSad #ifdef PTHREAD_SA
210c62a74e6Sthorpej 	PTQ_INIT(&pthread__runqueue);
211c62a74e6Sthorpej 	PTQ_INIT(&pthread__idlequeue);
212f2f10664Scl 	for (i = 0; i < pthread__maxconcurrency; i++)
213f2f10664Scl 		PTQ_INIT(&pthread__reidlequeue[i]);
2141ac6a89bSad #endif
215ded26025Sad 	nthreads = 1;
216c62a74e6Sthorpej 	/* Create the thread structure corresponding to main() */
217c62a74e6Sthorpej 	pthread__initmain(&first);
218c62a74e6Sthorpej 	pthread__initthread(first, first);
2191ac6a89bSad 
220c62a74e6Sthorpej 	first->pt_state = PT_STATE_RUNNING;
2211ac6a89bSad #ifdef PTHREAD_SA
222f782e995Sdrochner 	_sys___sigprocmask14(0, NULL, &first->pt_sigmask);
2231ac6a89bSad #else
2241ac6a89bSad 	first->pt_lid = _lwp_self();
2251ac6a89bSad #endif
226c62a74e6Sthorpej 	PTQ_INSERT_HEAD(&pthread__allqueue, first, pt_allq);
227c62a74e6Sthorpej 
228c62a74e6Sthorpej 	/* Start subsystems */
2291ac6a89bSad #ifdef PTHREAD_SA
230c62a74e6Sthorpej 	pthread__signal_init();
2311ac6a89bSad #endif
232c62a74e6Sthorpej 	PTHREAD_MD_INIT
233c62a74e6Sthorpej #ifdef PTHREAD__DEBUG
234f2f10664Scl 	pthread__debug_init(ncpu);
235c62a74e6Sthorpej #endif
236c62a74e6Sthorpej 
2370172694eSnathanw 	for (p = getenv("PTHREAD_DIAGASSERT"); p && *p; p++) {
2380172694eSnathanw 		switch (*p) {
2390172694eSnathanw 		case 'a':
2400172694eSnathanw 			pthread__diagassert |= DIAGASSERT_ABORT;
2410172694eSnathanw 			break;
2420172694eSnathanw 		case 'A':
2430172694eSnathanw 			pthread__diagassert &= ~DIAGASSERT_ABORT;
2440172694eSnathanw 			break;
2450172694eSnathanw 		case 'e':
2460172694eSnathanw 			pthread__diagassert |= DIAGASSERT_STDERR;
2470172694eSnathanw 			break;
2480172694eSnathanw 		case 'E':
2490172694eSnathanw 			pthread__diagassert &= ~DIAGASSERT_STDERR;
2500172694eSnathanw 			break;
2510172694eSnathanw 		case 'l':
2520172694eSnathanw 			pthread__diagassert |= DIAGASSERT_SYSLOG;
2530172694eSnathanw 			break;
2540172694eSnathanw 		case 'L':
2550172694eSnathanw 			pthread__diagassert &= ~DIAGASSERT_SYSLOG;
2560172694eSnathanw 			break;
257df277271Snathanw 		}
2580172694eSnathanw 	}
2590172694eSnathanw 
260df277271Snathanw 
261c62a74e6Sthorpej 	/* Tell libc that we're here and it should role-play accordingly. */
262c62a74e6Sthorpej 	__isthreaded = 1;
263c62a74e6Sthorpej }
264c62a74e6Sthorpej 
2652a4cef11Snathanw static void
2662a4cef11Snathanw pthread__child_callback(void)
2672a4cef11Snathanw {
2682a4cef11Snathanw 	/*
2692a4cef11Snathanw 	 * Clean up data structures that a forked child process might
2702a4cef11Snathanw 	 * trip over. Note that if threads have been created (causing
2712a4cef11Snathanw 	 * this handler to be registered) the standards say that the
2722a4cef11Snathanw 	 * child will trigger undefined behavior if it makes any
2732a4cef11Snathanw 	 * pthread_* calls (or any other calls that aren't
2742a4cef11Snathanw 	 * async-signal-safe), so we don't really have to clean up
2752a4cef11Snathanw 	 * much. Anything that permits some pthread_* calls to work is
2762a4cef11Snathanw 	 * merely being polite.
2772a4cef11Snathanw 	 */
2782a4cef11Snathanw 	pthread__started = 0;
2792a4cef11Snathanw }
280c62a74e6Sthorpej 
2810e675542Schs static void
282c62a74e6Sthorpej pthread__start(void)
283c62a74e6Sthorpej {
2841ac6a89bSad 	pthread_t self;
2851ac6a89bSad #ifdef PTHREAD_SA
2861ac6a89bSad 	pthread_t idle;
287c62a74e6Sthorpej 	int i, ret;
2881ac6a89bSad #endif
289c62a74e6Sthorpej 
290c62a74e6Sthorpej 	self = pthread__self(); /* should be the "main()" thread */
291c62a74e6Sthorpej 
292ff14fbf2Snathanw 	/*
293ff14fbf2Snathanw 	 * Per-process timers are cleared by fork(); despite the
294ff14fbf2Snathanw 	 * various restrictions on fork() and threads, it's legal to
295ff14fbf2Snathanw 	 * fork() before creating any threads.
296ff14fbf2Snathanw 	 */
2971ac6a89bSad #ifdef PTHREAD_SA
298ff14fbf2Snathanw 	pthread__alarm_init();
299ff14fbf2Snathanw 
300916de878Snathanw 	pthread__signal_start();
3011ac6a89bSad #endif
302916de878Snathanw 
3032a4cef11Snathanw 	pthread_atfork(NULL, NULL, pthread__child_callback);
304c62a74e6Sthorpej 
3051ac6a89bSad #ifdef PTHREAD_SA
306f2f10664Scl 	/*
307f2f10664Scl 	 * Create idle threads
308f2f10664Scl 	 * XXX need to create more idle threads if concurrency > 3
309f2f10664Scl 	 */
310c62a74e6Sthorpej 	for (i = 0; i < NIDLETHREADS; i++) {
311c62a74e6Sthorpej 		ret = pthread__stackalloc(&idle);
312c62a74e6Sthorpej 		if (ret != 0)
313c62a74e6Sthorpej 			err(1, "Couldn't allocate stack for idle thread!");
314c62a74e6Sthorpej 		pthread__initthread(self, idle);
315c62a74e6Sthorpej 		sigfillset(&idle->pt_sigmask);
316c62a74e6Sthorpej 		idle->pt_type = PT_THREAD_IDLE;
317c62a74e6Sthorpej 		PTQ_INSERT_HEAD(&pthread__allqueue, idle, pt_allq);
318c62a74e6Sthorpej 		pthread__sched_idle(self, idle);
319c62a74e6Sthorpej 	}
320c62a74e6Sthorpej 
321c62a74e6Sthorpej 	/* Start up the SA subsystem */
322c62a74e6Sthorpej 	pthread__sa_start();
3231ac6a89bSad #endif
3241ac6a89bSad 
325c62a74e6Sthorpej 	SDPRINTF(("(pthread__start %p) Started.\n", self));
326c62a74e6Sthorpej }
327c62a74e6Sthorpej 
328c62a74e6Sthorpej 
329c62a74e6Sthorpej /* General-purpose thread data structure sanitization. */
330c62a74e6Sthorpej void
331c62a74e6Sthorpej pthread__initthread(pthread_t self, pthread_t t)
332c62a74e6Sthorpej {
333c62a74e6Sthorpej 	int id;
334c62a74e6Sthorpej 
335c62a74e6Sthorpej 	pthread_spinlock(self, &nextthread_lock);
336c62a74e6Sthorpej 	id = nextthread;
337c62a74e6Sthorpej 	nextthread++;
338c62a74e6Sthorpej 	pthread_spinunlock(self, &nextthread_lock);
339c62a74e6Sthorpej 	t->pt_num = id;
340c62a74e6Sthorpej 
341c62a74e6Sthorpej 	t->pt_magic = PT_MAGIC;
3420878df5dSnathanw 	pthread_lockinit(&t->pt_flaglock);
343c62a74e6Sthorpej 	t->pt_spinlocks = 0;
344c62a74e6Sthorpej 	t->pt_exitval = NULL;
345c62a74e6Sthorpej 	t->pt_flags = 0;
346c62a74e6Sthorpej 	t->pt_cancel = 0;
347c62a74e6Sthorpej 	t->pt_errno = 0;
3481ac6a89bSad 
3491ac6a89bSad #ifdef PTHREAD_SA
3501ac6a89bSad 	t->pt_type = PT_THREAD_NORMAL;
3511ac6a89bSad 	t->pt_state = PT_STATE_RUNNABLE;
352c62a74e6Sthorpej 	t->pt_heldlock = NULL;
3531ac6a89bSad 	t->pt_next = NULL;
3541ac6a89bSad 	t->pt_parent = NULL;
355c62a74e6Sthorpej 	t->pt_switchto = NULL;
356487eb7e1Snathanw 	t->pt_trapuc = NULL;
357c62a74e6Sthorpej 	sigemptyset(&t->pt_siglist);
358c62a74e6Sthorpej 	sigemptyset(&t->pt_sigmask);
359c62a74e6Sthorpej 	pthread_lockinit(&t->pt_siglock);
3601ac6a89bSad #else
3611ac6a89bSad 	t->pt_state = PT_STATE_RUNNING;
3621ac6a89bSad #endif
3631ac6a89bSad 
3641ac6a89bSad 	pthread_lockinit(&t->pt_statelock);
3651ac6a89bSad 
366c62a74e6Sthorpej 	PTQ_INIT(&t->pt_joiners);
367c62a74e6Sthorpej 	pthread_lockinit(&t->pt_join_lock);
368c62a74e6Sthorpej 	PTQ_INIT(&t->pt_cleanup_stack);
369c62a74e6Sthorpej 	memset(&t->pt_specific, 0, sizeof(int) * PTHREAD_KEYS_MAX);
370b33971b9Sthorpej 	t->pt_name = NULL;
3711ac6a89bSad 
3721ac6a89bSad #if defined(PTHREAD__DEBUG) && defined(PTHREAD_SA)
373c62a74e6Sthorpej 	t->blocks = 0;
374c62a74e6Sthorpej 	t->preempts = 0;
375c62a74e6Sthorpej 	t->rescheds = 0;
376c62a74e6Sthorpej #endif
377c62a74e6Sthorpej }
378c62a74e6Sthorpej 
379c62a74e6Sthorpej 
380c62a74e6Sthorpej int
381c62a74e6Sthorpej pthread_create(pthread_t *thread, const pthread_attr_t *attr,
382c62a74e6Sthorpej 	    void *(*startfunc)(void *), void *arg)
383c62a74e6Sthorpej {
384c62a74e6Sthorpej 	pthread_t self, newthread;
385c62a74e6Sthorpej 	pthread_attr_t nattr;
386b33971b9Sthorpej 	struct pthread_attr_private *p;
3873ca3d0b1Schristos 	char * volatile name;
388c62a74e6Sthorpej 	int ret;
3891ac6a89bSad #ifndef PTHREAD_SA
3901ac6a89bSad 	int flag;
3911ac6a89bSad #endif
392c62a74e6Sthorpej 
393c62a74e6Sthorpej 	PTHREADD_ADD(PTHREADD_CREATE);
394c62a74e6Sthorpej 
395c62a74e6Sthorpej 	/*
396c62a74e6Sthorpej 	 * It's okay to check this without a lock because there can
397c62a74e6Sthorpej 	 * only be one thread before it becomes true.
398c62a74e6Sthorpej 	 */
399c62a74e6Sthorpej 	if (pthread__started == 0) {
400c62a74e6Sthorpej 		pthread__start();
401c62a74e6Sthorpej 		pthread__started = 1;
402c62a74e6Sthorpej 	}
403c62a74e6Sthorpej 
404c62a74e6Sthorpej 	if (attr == NULL)
405c62a74e6Sthorpej 		nattr = pthread_default_attr;
406e81f9f17Sdrochner 	else if (attr->pta_magic == PT_ATTR_MAGIC)
407c62a74e6Sthorpej 		nattr = *attr;
408c62a74e6Sthorpej 	else
409c62a74e6Sthorpej 		return EINVAL;
410c62a74e6Sthorpej 
411b33971b9Sthorpej 	/* Fetch misc. attributes from the attr structure. */
412508a50acSnathanw 	name = NULL;
413508a50acSnathanw 	if ((p = nattr.pta_private) != NULL)
414508a50acSnathanw 		if (p->ptap_name[0] != '\0')
415b33971b9Sthorpej 			if ((name = strdup(p->ptap_name)) == NULL)
416b33971b9Sthorpej 				return ENOMEM;
417c62a74e6Sthorpej 
418c62a74e6Sthorpej 	self = pthread__self();
419c62a74e6Sthorpej 
420c62a74e6Sthorpej 	pthread_spinlock(self, &pthread__deadqueue_lock);
421c62a74e6Sthorpej 	newthread = PTQ_FIRST(&pthread__deadqueue);
4224cdc2ed8Syamt 	if (newthread != NULL) {
4234cdc2ed8Syamt #ifndef PTHREAD_SA
424dacd4bd9Sad 		if ((newthread->pt_flags & PT_FLAG_DETACHED) != 0 &&
425dacd4bd9Sad 		    (_lwp_kill(newthread->pt_lid, 0) == 0 || errno != ESRCH))
4264cdc2ed8Syamt 			newthread = NULL;
4274cdc2ed8Syamt 		else
4284cdc2ed8Syamt #endif
429c62a74e6Sthorpej 			PTQ_REMOVE(&pthread__deadqueue, newthread, pt_allq);
4304cdc2ed8Syamt 	}
431c62a74e6Sthorpej 	pthread_spinunlock(self, &pthread__deadqueue_lock);
4324cdc2ed8Syamt 	if (newthread == NULL) {
433c62a74e6Sthorpej 		/* Set up a stack and allocate space for a pthread_st. */
434c62a74e6Sthorpej 		ret = pthread__stackalloc(&newthread);
435b7559f85Schristos 		if (ret != 0) {
436b7559f85Schristos 			if (name)
437b7559f85Schristos 				free(name);
438c62a74e6Sthorpej 			return ret;
439c62a74e6Sthorpej 		}
440b7559f85Schristos 	}
441c62a74e6Sthorpej 
442c62a74e6Sthorpej 	/* 2. Set up state. */
443c62a74e6Sthorpej 	pthread__initthread(self, newthread);
444c62a74e6Sthorpej 	newthread->pt_flags = nattr.pta_flags;
4451ac6a89bSad #ifdef PTHREAD_SA
446c62a74e6Sthorpej 	newthread->pt_sigmask = self->pt_sigmask;
4471ac6a89bSad #endif
448c62a74e6Sthorpej 
449b33971b9Sthorpej 	/* 3. Set up misc. attributes. */
450b33971b9Sthorpej 	newthread->pt_name = name;
451b33971b9Sthorpej 
452c62a74e6Sthorpej 	/*
453b33971b9Sthorpej 	 * 4. Set up context.
454c62a74e6Sthorpej 	 *
455c62a74e6Sthorpej 	 * The pt_uc pointer points to a location safely below the
456c62a74e6Sthorpej 	 * stack start; this is arranged by pthread__stackalloc().
457c62a74e6Sthorpej 	 */
458c62a74e6Sthorpej 	_INITCONTEXT_U(newthread->pt_uc);
459877f8985Snathanw #ifdef PTHREAD_MACHINE_HAS_ID_REGISTER
460877f8985Snathanw 	pthread__uc_id(newthread->pt_uc) = newthread;
461877f8985Snathanw #endif
462c62a74e6Sthorpej 	newthread->pt_uc->uc_stack = newthread->pt_stack;
463c62a74e6Sthorpej 	newthread->pt_uc->uc_link = NULL;
464c62a74e6Sthorpej 	makecontext(newthread->pt_uc, pthread__create_tramp, 2,
465c62a74e6Sthorpej 	    startfunc, arg);
466c62a74e6Sthorpej 
467efb1fc06Sad 	/* 5. Add to list of all threads. */
468efb1fc06Sad 	pthread_spinlock(self, &pthread__allqueue_lock);
469efb1fc06Sad 	PTQ_INSERT_HEAD(&pthread__allqueue, newthread, pt_allq);
470efb1fc06Sad 	nthreads++;
471efb1fc06Sad 	pthread_spinunlock(self, &pthread__allqueue_lock);
472efb1fc06Sad 
4731ac6a89bSad #ifndef PTHREAD_SA
474efb1fc06Sad 	/* 5a. Create the new LWP. */
4757630e387Sad 	newthread->pt_sleeponq = 0;
476ded26025Sad 	flag = 0;
477ded26025Sad 	if ((newthread->pt_flags & PT_FLAG_SUSPENDED) != 0)
478ded26025Sad 		flag |= LWP_SUSPENDED;
479ded26025Sad 	if ((newthread->pt_flags & PT_FLAG_DETACHED) != 0)
480ded26025Sad 		flag |= LWP_DETACHED;
4811ac6a89bSad 	ret = _lwp_create(newthread->pt_uc, (u_long)flag, &newthread->pt_lid);
4821ac6a89bSad 	if (ret != 0) {
4831ac6a89bSad 		SDPRINTF(("(pthread_create %p) _lwp_create: %s\n",
4841ac6a89bSad 		    strerror(errno)));
4851ac6a89bSad 		free(name);
486efb1fc06Sad 		pthread_spinlock(self, &pthread__allqueue_lock);
487efb1fc06Sad 		PTQ_REMOVE(&pthread__allqueue, newthread, pt_allq);
488efb1fc06Sad 		nthreads--;
489efb1fc06Sad 		pthread_spinunlock(self, &pthread__allqueue_lock);
490efb1fc06Sad 		pthread_spinlock(self, &pthread__deadqueue_lock);
491efb1fc06Sad 		PTQ_INSERT_HEAD(&pthread__deadqueue, newthread, pt_allq);
492efb1fc06Sad 		pthread_spinunlock(self, &pthread__deadqueue_lock);
4931ac6a89bSad 		return ret;
4941ac6a89bSad 	}
4951ac6a89bSad #endif
4961ac6a89bSad 
4971ac6a89bSad #ifdef PTHREAD_SA
498ba70e96aSchs 	SDPRINTF(("(pthread_create %p) new thread %p (name pointer %p).\n",
499ba70e96aSchs 		  self, newthread, newthread->pt_name));
50038b1c6f4Schristos 	/* 6. Put on appropriate queue. */
50138b1c6f4Schristos 	if (newthread->pt_flags & PT_FLAG_SUSPENDED) {
50238b1c6f4Schristos 		pthread_spinlock(self, &newthread->pt_statelock);
50338b1c6f4Schristos 		pthread__suspend(self, newthread);
50438b1c6f4Schristos 		pthread_spinunlock(self, &newthread->pt_statelock);
50538b1c6f4Schristos 	} else
506c62a74e6Sthorpej 		pthread__sched(self, newthread);
5071ac6a89bSad #else
5081ac6a89bSad 	SDPRINTF(("(pthread_create %p) new thread %p (name %p, lid %d).\n",
5091ac6a89bSad 		  self, newthread, newthread->pt_name,
5101ac6a89bSad 		  (int)newthread->pt_lid));
5111ac6a89bSad #endif
512c62a74e6Sthorpej 
513c62a74e6Sthorpej 	*thread = newthread;
514c62a74e6Sthorpej 
515c62a74e6Sthorpej 	return 0;
516c62a74e6Sthorpej }
517c62a74e6Sthorpej 
518c62a74e6Sthorpej 
519c62a74e6Sthorpej static void
520c62a74e6Sthorpej pthread__create_tramp(void *(*start)(void *), void *arg)
521c62a74e6Sthorpej {
522c62a74e6Sthorpej 	void *retval;
523c62a74e6Sthorpej 
52494a458ceSchs 	retval = (*start)(arg);
525c62a74e6Sthorpej 
526c62a74e6Sthorpej 	pthread_exit(retval);
527c62a74e6Sthorpej 
528143f5a27Schristos 	/*NOTREACHED*/
529143f5a27Schristos 	pthread__abort();
530c62a74e6Sthorpej }
531c62a74e6Sthorpej 
53238b1c6f4Schristos int
53338b1c6f4Schristos pthread_suspend_np(pthread_t thread)
53438b1c6f4Schristos {
535ba70e96aSchs 	pthread_t self;
536ba70e96aSchs 
537ba70e96aSchs 	self = pthread__self();
53838b1c6f4Schristos 	if (self == thread) {
53938b1c6f4Schristos 		return EDEADLK;
54038b1c6f4Schristos 	}
541ba70e96aSchs #ifdef ERRORCHECK
542ba70e96aSchs 	if (pthread__find(self, thread) != 0)
543ba70e96aSchs 		return ESRCH;
544ba70e96aSchs #endif
5451ac6a89bSad #ifdef PTHREAD_SA
54638b1c6f4Schristos 	SDPRINTF(("(pthread_suspend_np %p) Suspend thread %p (state %d).\n",
54738b1c6f4Schristos 		     self, thread, thread->pt_state));
54838b1c6f4Schristos 	pthread_spinlock(self, &thread->pt_statelock);
54982b6b2dbScl 	if (thread->pt_blockgen != thread->pt_unblockgen) {
55082b6b2dbScl 		/* XXX flaglock? */
55182b6b2dbScl 		thread->pt_flags |= PT_FLAG_SUSPENDED;
55282b6b2dbScl 		pthread_spinunlock(self, &thread->pt_statelock);
55382b6b2dbScl 		return 0;
55482b6b2dbScl 	}
55538b1c6f4Schristos 	switch (thread->pt_state) {
55638b1c6f4Schristos 	case PT_STATE_RUNNING:
55738b1c6f4Schristos 		pthread__abort();	/* XXX */
55838b1c6f4Schristos 		break;
55938b1c6f4Schristos 	case PT_STATE_SUSPENDED:
56038b1c6f4Schristos 		pthread_spinunlock(self, &thread->pt_statelock);
56138b1c6f4Schristos 		return 0;
56238b1c6f4Schristos 	case PT_STATE_RUNNABLE:
56338b1c6f4Schristos 		pthread_spinlock(self, &pthread__runqueue_lock);
56438b1c6f4Schristos 		PTQ_REMOVE(&pthread__runqueue, thread, pt_runq);
56538b1c6f4Schristos 		pthread_spinunlock(self, &pthread__runqueue_lock);
56638b1c6f4Schristos 		break;
56738b1c6f4Schristos 	case PT_STATE_BLOCKED_QUEUE:
56838b1c6f4Schristos 		pthread_spinlock(self, thread->pt_sleeplock);
56938b1c6f4Schristos 		PTQ_REMOVE(thread->pt_sleepq, thread, pt_sleep);
57038b1c6f4Schristos 		pthread_spinunlock(self, thread->pt_sleeplock);
57138b1c6f4Schristos 		break;
572ba70e96aSchs 	case PT_STATE_ZOMBIE:
573ba70e96aSchs 		goto out;
57438b1c6f4Schristos 	default:
57538b1c6f4Schristos 		break;			/* XXX */
57638b1c6f4Schristos 	}
57738b1c6f4Schristos 	pthread__suspend(self, thread);
578ba70e96aSchs 
579ba70e96aSchs out:
58038b1c6f4Schristos 	pthread_spinunlock(self, &thread->pt_statelock);
58138b1c6f4Schristos 	return 0;
5821ac6a89bSad #else
5831ac6a89bSad 	SDPRINTF(("(pthread_suspend_np %p) Suspend thread %p.\n",
5841ac6a89bSad 		     self, thread));
5851ac6a89bSad 	return _lwp_suspend(thread->pt_lid);
5861ac6a89bSad #endif
58738b1c6f4Schristos }
58838b1c6f4Schristos 
58938b1c6f4Schristos int
59038b1c6f4Schristos pthread_resume_np(pthread_t thread)
59138b1c6f4Schristos {
592ba70e96aSchs 	pthread_t self;
59338b1c6f4Schristos 
594ba70e96aSchs 	self = pthread__self();
595ba70e96aSchs #ifdef ERRORCHECK
596ba70e96aSchs 	if (pthread__find(self, thread) != 0)
597ba70e96aSchs 		return ESRCH;
598ba70e96aSchs #endif
5991ac6a89bSad #ifdef PTHREAD_SA
60038b1c6f4Schristos 	SDPRINTF(("(pthread_resume_np %p) Resume thread %p (state %d).\n",
60138b1c6f4Schristos 		     self, thread, thread->pt_state));
60238b1c6f4Schristos 	pthread_spinlock(self, &thread->pt_statelock);
60338b1c6f4Schristos 	/* XXX flaglock? */
60438b1c6f4Schristos 	thread->pt_flags &= ~PT_FLAG_SUSPENDED;
60538b1c6f4Schristos 	if (thread->pt_state == PT_STATE_SUSPENDED) {
60638b1c6f4Schristos 		pthread_spinlock(self, &pthread__runqueue_lock);
60738b1c6f4Schristos 		PTQ_REMOVE(&pthread__suspqueue, thread, pt_runq);
60838b1c6f4Schristos 		pthread_spinunlock(self, &pthread__runqueue_lock);
60938b1c6f4Schristos 		pthread__sched(self, thread);
61038b1c6f4Schristos 	}
61138b1c6f4Schristos 	pthread_spinunlock(self, &thread->pt_statelock);
61238b1c6f4Schristos 	return 0;
6131ac6a89bSad #else
6141ac6a89bSad 	SDPRINTF(("(pthread_resume_np %p) Resume thread %p.\n",
6151ac6a89bSad 		     self, thread));
6161ac6a89bSad 	return _lwp_continue(thread->pt_lid);
6171ac6a89bSad #endif
61838b1c6f4Schristos }
61938b1c6f4Schristos 
6201ac6a89bSad #ifdef PTHREAD_SA
621c62a74e6Sthorpej /*
622c62a74e6Sthorpej  * Other threads will switch to the idle thread so that they
623c62a74e6Sthorpej  * can dispose of any awkward locks or recycle upcall state.
624c62a74e6Sthorpej  */
625c62a74e6Sthorpej void
626c62a74e6Sthorpej pthread__idle(void)
627c62a74e6Sthorpej {
628c62a74e6Sthorpej 	pthread_t self;
629c62a74e6Sthorpej 
630c62a74e6Sthorpej 	PTHREADD_ADD(PTHREADD_IDLE);
631c62a74e6Sthorpej 	self = pthread__self();
632c62a74e6Sthorpej 	SDPRINTF(("(pthread__idle %p).\n", self));
633c62a74e6Sthorpej 
634c62a74e6Sthorpej 	/*
635c62a74e6Sthorpej 	 * The drill here is that we want to yield the processor,
636c62a74e6Sthorpej 	 * but for the thread itself to be recovered, we need to be on
637c62a74e6Sthorpej 	 * a list somewhere for the thread system to know about us.
638c62a74e6Sthorpej 	 */
639c62a74e6Sthorpej 	pthread_spinlock(self, &pthread__deadqueue_lock);
640f2f10664Scl 	PTQ_INSERT_TAIL(&pthread__reidlequeue[self->pt_vpid], self, pt_runq);
641f2f10664Scl 	pthread__concurrency--;
642f2f10664Scl 	SDPRINTF(("(yield %p concurrency) now %d\n", self,
643f2f10664Scl 		     pthread__concurrency));
6440878df5dSnathanw 	/* Don't need a flag lock; nothing else has a handle on this thread */
645c62a74e6Sthorpej 	self->pt_flags |= PT_FLAG_IDLED;
646c62a74e6Sthorpej 	pthread_spinunlock(self, &pthread__deadqueue_lock);
647c62a74e6Sthorpej 
648c62a74e6Sthorpej 	/*
649c62a74e6Sthorpej 	 * If we get to run this, then no preemption has happened
650c62a74e6Sthorpej 	 * (because the upcall handler will not continue an idle thread with
651c62a74e6Sthorpej 	 * PT_FLAG_IDLED set), and so we can yield the processor safely.
652c62a74e6Sthorpej 	 */
653c62a74e6Sthorpej 	SDPRINTF(("(pthread__idle %p) yielding.\n", self));
654c62a74e6Sthorpej 	sa_yield();
655c62a74e6Sthorpej 
656c62a74e6Sthorpej 	/* NOTREACHED */
657c62a74e6Sthorpej 	self->pt_spinlocks++; /* XXX make sure we get to finish the assert! */
658c62a74e6Sthorpej 	SDPRINTF(("(pthread__idle %p) Returned! Error.\n", self));
659143f5a27Schristos 	pthread__abort();
660c62a74e6Sthorpej }
6611ac6a89bSad #endif
662c62a74e6Sthorpej 
663c62a74e6Sthorpej 
664c62a74e6Sthorpej void
665c62a74e6Sthorpej pthread_exit(void *retval)
666c62a74e6Sthorpej {
66796b5a26dSnathanw 	pthread_t self;
668c62a74e6Sthorpej 	struct pt_clean_t *cleanup;
669b33971b9Sthorpej 	char *name;
6706b2b9c62Syamt 	int nt;
671c62a74e6Sthorpej 
672c62a74e6Sthorpej 	self = pthread__self();
673ba70e96aSchs 	SDPRINTF(("(pthread_exit %p) status %p, flags %x, cancel %d\n",
674ba70e96aSchs 		  self, retval, self->pt_flags, self->pt_cancel));
675c62a74e6Sthorpej 
676c62a74e6Sthorpej 	/* Disable cancellability. */
6770878df5dSnathanw 	pthread_spinlock(self, &self->pt_flaglock);
678c62a74e6Sthorpej 	self->pt_flags |= PT_FLAG_CS_DISABLED;
67966fcc1ceSnathanw 	self->pt_cancel = 0;
6800878df5dSnathanw 	pthread_spinunlock(self, &self->pt_flaglock);
681c62a74e6Sthorpej 
682c62a74e6Sthorpej 	/* Call any cancellation cleanup handlers */
683c62a74e6Sthorpej 	while (!PTQ_EMPTY(&self->pt_cleanup_stack)) {
684c62a74e6Sthorpej 		cleanup = PTQ_FIRST(&self->pt_cleanup_stack);
685c62a74e6Sthorpej 		PTQ_REMOVE(&self->pt_cleanup_stack, cleanup, ptc_next);
686c62a74e6Sthorpej 		(*cleanup->ptc_cleanup)(cleanup->ptc_arg);
687c62a74e6Sthorpej 	}
688c62a74e6Sthorpej 
689c62a74e6Sthorpej 	/* Perform cleanup of thread-specific data */
690c62a74e6Sthorpej 	pthread__destroy_tsd(self);
691c62a74e6Sthorpej 
692c62a74e6Sthorpej 	self->pt_exitval = retval;
693c62a74e6Sthorpej 
6946b2b9c62Syamt 	/*
6956b2b9c62Syamt 	 * it's safe to check PT_FLAG_DETACHED without pt_flaglock
6966b2b9c62Syamt 	 * because it's only set by pthread_detach with pt_join_lock held.
6976b2b9c62Syamt 	 */
6986b2b9c62Syamt 	pthread_spinlock(self, &self->pt_join_lock);
6996b2b9c62Syamt 	if (self->pt_flags & PT_FLAG_DETACHED) {
7006b2b9c62Syamt 		self->pt_state = PT_STATE_DEAD;
7016b2b9c62Syamt 		pthread_spinunlock(self, &self->pt_join_lock);
702b33971b9Sthorpej 		name = self->pt_name;
703b33971b9Sthorpej 		self->pt_name = NULL;
704c62a74e6Sthorpej 
705b33971b9Sthorpej 		if (name != NULL)
706b33971b9Sthorpej 			free(name);
707b33971b9Sthorpej 
708c62a74e6Sthorpej 		pthread_spinlock(self, &pthread__allqueue_lock);
709c62a74e6Sthorpej 		PTQ_REMOVE(&pthread__allqueue, self, pt_allq);
710c62a74e6Sthorpej 		nthreads--;
711c62a74e6Sthorpej 		nt = nthreads;
712c62a74e6Sthorpej 		pthread_spinunlock(self, &pthread__allqueue_lock);
713c62a74e6Sthorpej 
714c62a74e6Sthorpej 		if (nt == 0) {
715c62a74e6Sthorpej 			/* Whoah, we're the last one. Time to go. */
716c62a74e6Sthorpej 			exit(0);
717c62a74e6Sthorpej 		}
718c62a74e6Sthorpej 
719c62a74e6Sthorpej 		/* Yeah, yeah, doing work while we're dead is tacky. */
720c62a74e6Sthorpej 		pthread_spinlock(self, &pthread__deadqueue_lock);
721*1296e850Sad 		PTQ_INSERT_TAIL(&pthread__deadqueue, self, pt_allq);
722ded26025Sad 
723ded26025Sad #ifdef PTHREAD_SA
724c62a74e6Sthorpej 		pthread__block(self, &pthread__deadqueue_lock);
725ba70e96aSchs 		SDPRINTF(("(pthread_exit %p) walking dead\n", self));
7261ac6a89bSad 		pthread_spinunlock(self, &pthread__allqueue_lock);
727ded26025Sad #else
728ded26025Sad 		pthread_spinunlock(self, &pthread__deadqueue_lock);
7291ac6a89bSad 		_lwp_exit();
7301ac6a89bSad #endif
731c62a74e6Sthorpej 	} else {
7326b2b9c62Syamt 		self->pt_state = PT_STATE_ZOMBIE;
7331ac6a89bSad 
734b33971b9Sthorpej 		/* Note: name will be freed by the joiner. */
735c62a74e6Sthorpej 		pthread_spinlock(self, &pthread__allqueue_lock);
736c62a74e6Sthorpej 		nthreads--;
737c62a74e6Sthorpej 		nt = nthreads;
738c62a74e6Sthorpej 		pthread_spinunlock(self, &pthread__allqueue_lock);
739c62a74e6Sthorpej 		if (nt == 0) {
740c62a74e6Sthorpej 			/* Whoah, we're the last one. Time to go. */
741c62a74e6Sthorpej 			exit(0);
742c62a74e6Sthorpej 		}
743ded26025Sad 
744ded26025Sad #ifdef PTHREAD_SA
74596b5a26dSnathanw 		/*
74696b5a26dSnathanw 		 * Wake up all the potential joiners. Only one can win.
747c62a74e6Sthorpej 		 * (Can you say "Thundering Herd"? I knew you could.)
748c62a74e6Sthorpej 		 */
74996b5a26dSnathanw 		pthread__sched_sleepers(self, &self->pt_joiners);
750c62a74e6Sthorpej 		pthread__block(self, &self->pt_join_lock);
751ba70e96aSchs 		SDPRINTF(("(pthread_exit %p) walking zombie\n", self));
7521ac6a89bSad #else
7531ac6a89bSad 		pthread_spinunlock(self, &self->pt_join_lock);
7541ac6a89bSad 		_lwp_exit();
7551ac6a89bSad #endif
756c62a74e6Sthorpej 	}
757c62a74e6Sthorpej 
758143f5a27Schristos 	/*NOTREACHED*/
759143f5a27Schristos 	pthread__abort();
760c62a74e6Sthorpej 	exit(1);
761c62a74e6Sthorpej }
762c62a74e6Sthorpej 
763c62a74e6Sthorpej 
764c62a74e6Sthorpej int
765c62a74e6Sthorpej pthread_join(pthread_t thread, void **valptr)
766c62a74e6Sthorpej {
767c62a74e6Sthorpej 	pthread_t self;
768b33971b9Sthorpej 	char *name;
7691ac6a89bSad 	int num, retval;
770c62a74e6Sthorpej 
771c62a74e6Sthorpej 	self = pthread__self();
772c62a74e6Sthorpej 	SDPRINTF(("(pthread_join %p) Joining %p.\n", self, thread));
773c62a74e6Sthorpej 
774c62a74e6Sthorpej 	if (pthread__find(self, thread) != 0)
775c62a74e6Sthorpej 		return ESRCH;
776c62a74e6Sthorpej 
777c62a74e6Sthorpej 	if (thread->pt_magic != PT_MAGIC)
778c62a74e6Sthorpej 		return EINVAL;
779c62a74e6Sthorpej 
780c62a74e6Sthorpej 	if (thread == self)
781c62a74e6Sthorpej 		return EDEADLK;
782c62a74e6Sthorpej 
7831ac6a89bSad #ifdef PTHREAD_SA
7840878df5dSnathanw 	pthread_spinlock(self, &thread->pt_flaglock);
785c62a74e6Sthorpej 
786c62a74e6Sthorpej 	if (thread->pt_flags & PT_FLAG_DETACHED) {
7870878df5dSnathanw 		pthread_spinunlock(self, &thread->pt_flaglock);
788c62a74e6Sthorpej 		return EINVAL;
789c62a74e6Sthorpej 	}
790c62a74e6Sthorpej 
791564fe117Snathanw 	num = thread->pt_num;
7920878df5dSnathanw 	pthread_spinlock(self, &thread->pt_join_lock);
793564fe117Snathanw 	while (thread->pt_state != PT_STATE_ZOMBIE) {
794564fe117Snathanw 		if ((thread->pt_state == PT_STATE_DEAD) ||
795564fe117Snathanw 		    (thread->pt_flags & PT_FLAG_DETACHED) ||
796564fe117Snathanw 		    (thread->pt_num != num)) {
797564fe117Snathanw 			/*
798564fe117Snathanw 			 * Another thread beat us to the join, or called
799564fe117Snathanw 			 * pthread_detach(). If num didn't match, the
800564fe117Snathanw 			 * thread died and was recycled before we got
801564fe117Snathanw 			 * another chance to run.
802564fe117Snathanw 			 */
803564fe117Snathanw 			pthread_spinunlock(self, &thread->pt_join_lock);
8040878df5dSnathanw 			pthread_spinunlock(self, &thread->pt_flaglock);
805564fe117Snathanw 			return ESRCH;
806564fe117Snathanw 		}
807c62a74e6Sthorpej 		/*
808c62a74e6Sthorpej 		 * "I'm not dead yet!"
809c62a74e6Sthorpej 		 * "You will be soon enough."
810c62a74e6Sthorpej 		 */
8110878df5dSnathanw 		pthread_spinunlock(self, &thread->pt_flaglock);
812c62a74e6Sthorpej 		pthread_spinlock(self, &self->pt_statelock);
813c62a74e6Sthorpej 		if (self->pt_cancel) {
814c62a74e6Sthorpej 			pthread_spinunlock(self, &self->pt_statelock);
815c62a74e6Sthorpej 			pthread_spinunlock(self, &thread->pt_join_lock);
816c62a74e6Sthorpej 			pthread_exit(PTHREAD_CANCELED);
817c62a74e6Sthorpej 		}
818c62a74e6Sthorpej 		self->pt_state = PT_STATE_BLOCKED_QUEUE;
819c62a74e6Sthorpej 		self->pt_sleepobj = thread;
820c62a74e6Sthorpej 		self->pt_sleepq = &thread->pt_joiners;
821c62a74e6Sthorpej 		self->pt_sleeplock = &thread->pt_join_lock;
822c62a74e6Sthorpej 		pthread_spinunlock(self, &self->pt_statelock);
823c62a74e6Sthorpej 
824c62a74e6Sthorpej 		PTQ_INSERT_TAIL(&thread->pt_joiners, self, pt_sleep);
825c62a74e6Sthorpej 		pthread__block(self, &thread->pt_join_lock);
8260878df5dSnathanw 		pthread_spinlock(self, &thread->pt_flaglock);
827c62a74e6Sthorpej 		pthread_spinlock(self, &thread->pt_join_lock);
828c62a74e6Sthorpej 	}
829c62a74e6Sthorpej 
830c62a74e6Sthorpej 	/* All ours. */
831c62a74e6Sthorpej 	thread->pt_state = PT_STATE_DEAD;
832b33971b9Sthorpej 	name = thread->pt_name;
833b33971b9Sthorpej 	thread->pt_name = NULL;
834c62a74e6Sthorpej 	pthread_spinunlock(self, &thread->pt_join_lock);
8350878df5dSnathanw 	pthread_spinunlock(self, &thread->pt_flaglock);
836c62a74e6Sthorpej 
837c62a74e6Sthorpej 	if (valptr != NULL)
838c62a74e6Sthorpej 		*valptr = thread->pt_exitval;
839c62a74e6Sthorpej 
8401ac6a89bSad 	retval = 0;
8411ac6a89bSad #else	/* PTHREAD_SA */
8421ac6a89bSad 	retval = 0;
8431ac6a89bSad 	name = NULL;
8441ac6a89bSad  again:
8451ac6a89bSad  	pthread_spinlock(self, &thread->pt_join_lock);
8461ac6a89bSad 	switch (thread->pt_state) {
8471ac6a89bSad 	case PT_STATE_RUNNING:
8481ac6a89bSad 		pthread_spinunlock(self, &thread->pt_join_lock);
849ded26025Sad 
850ded26025Sad 		/*
851ded26025Sad 		 * IEEE Std 1003.1, 2004 Edition:
852ded26025Sad 		 *
853ded26025Sad 		 * "The pthread_join() function shall not
854ded26025Sad 		 * return an error code of [EINTR]."
855ded26025Sad 		 */
856ded26025Sad 		if (_lwp_wait(thread->pt_lid, &num) != 0 && errno != EINTR)
857ded26025Sad 			return errno;
8581ac6a89bSad 		goto again;
8591ac6a89bSad 	case PT_STATE_ZOMBIE:
8601ac6a89bSad 		if (valptr != NULL)
861ded26025Sad 			*valptr = thread->pt_exitval;
8621ac6a89bSad 		if (retval == 0) {
8631ac6a89bSad 			name = thread->pt_name;
8641ac6a89bSad 			thread->pt_name = NULL;
8651ac6a89bSad 		}
8661ac6a89bSad 		thread->pt_state = PT_STATE_DEAD;
8671ac6a89bSad 		pthread_spinunlock(self, &thread->pt_join_lock);
868b8daad98Sad 		(void)_lwp_detach(thread->pt_lid);
8691ac6a89bSad 		break;
8701ac6a89bSad 	default:
8711ac6a89bSad 		pthread_spinunlock(self, &thread->pt_join_lock);
8721ac6a89bSad 		return EINVAL;
8731ac6a89bSad 	}
8741ac6a89bSad #endif	/* PTHREAD_SA */
8751ac6a89bSad 
876c62a74e6Sthorpej 	SDPRINTF(("(pthread_join %p) Joined %p.\n", self, thread));
877c62a74e6Sthorpej 
8786b2b9c62Syamt 	pthread__dead(self, thread);
879c62a74e6Sthorpej 
880b33971b9Sthorpej 	if (name != NULL)
881b33971b9Sthorpej 		free(name);
882b33971b9Sthorpej 
8831ac6a89bSad 	return retval;
884c62a74e6Sthorpej }
885c62a74e6Sthorpej 
886c62a74e6Sthorpej 
887c62a74e6Sthorpej int
888c62a74e6Sthorpej pthread_equal(pthread_t t1, pthread_t t2)
889c62a74e6Sthorpej {
890c62a74e6Sthorpej 
891c62a74e6Sthorpej 	/* Nothing special here. */
892c62a74e6Sthorpej 	return (t1 == t2);
893c62a74e6Sthorpej }
894c62a74e6Sthorpej 
895c62a74e6Sthorpej 
896c62a74e6Sthorpej int
897c62a74e6Sthorpej pthread_detach(pthread_t thread)
898c62a74e6Sthorpej {
89996b5a26dSnathanw 	pthread_t self;
9001ac6a89bSad #ifdef PTHREAD_SA
9016b2b9c62Syamt 	int doreclaim = 0;
9026b2b9c62Syamt 	char *name = NULL;
9031ac6a89bSad #endif
904c62a74e6Sthorpej 
905c62a74e6Sthorpej 	self = pthread__self();
906c62a74e6Sthorpej 
907c62a74e6Sthorpej 	if (pthread__find(self, thread) != 0)
908c62a74e6Sthorpej 		return ESRCH;
909c62a74e6Sthorpej 
910c62a74e6Sthorpej 	if (thread->pt_magic != PT_MAGIC)
911c62a74e6Sthorpej 		return EINVAL;
912c62a74e6Sthorpej 
9131ac6a89bSad #ifdef PTHREAD_SA
9140878df5dSnathanw 	pthread_spinlock(self, &thread->pt_flaglock);
915c62a74e6Sthorpej 	pthread_spinlock(self, &thread->pt_join_lock);
916c62a74e6Sthorpej 
917c62a74e6Sthorpej 	if (thread->pt_flags & PT_FLAG_DETACHED) {
918c62a74e6Sthorpej 		pthread_spinunlock(self, &thread->pt_join_lock);
9190878df5dSnathanw 		pthread_spinunlock(self, &thread->pt_flaglock);
920c62a74e6Sthorpej 		return EINVAL;
921c62a74e6Sthorpej 	}
922c62a74e6Sthorpej 
923c62a74e6Sthorpej 	thread->pt_flags |= PT_FLAG_DETACHED;
924c62a74e6Sthorpej 
925c62a74e6Sthorpej 	/* Any joiners have to be punted now. */
92696b5a26dSnathanw 	pthread__sched_sleepers(self, &thread->pt_joiners);
927c62a74e6Sthorpej 
9286b2b9c62Syamt 	if (thread->pt_state == PT_STATE_ZOMBIE) {
9296b2b9c62Syamt 		thread->pt_state = PT_STATE_DEAD;
9306b2b9c62Syamt 		name = thread->pt_name;
9316b2b9c62Syamt 		thread->pt_name = NULL;
9326b2b9c62Syamt 		doreclaim = 1;
9336b2b9c62Syamt 	}
9346b2b9c62Syamt 
935c62a74e6Sthorpej 	pthread_spinunlock(self, &thread->pt_join_lock);
9360878df5dSnathanw 	pthread_spinunlock(self, &thread->pt_flaglock);
937c62a74e6Sthorpej 
9386b2b9c62Syamt 	if (doreclaim) {
9396b2b9c62Syamt 		pthread__dead(self, thread);
9406b2b9c62Syamt 		if (name != NULL)
9416b2b9c62Syamt 			free(name);
9426b2b9c62Syamt 	}
9436b2b9c62Syamt 
944c62a74e6Sthorpej 	return 0;
9451ac6a89bSad #else
946*1296e850Sad 	thread->pt_flags |= PT_FLAG_DETACHED;
9471ac6a89bSad 	return _lwp_detach(thread->pt_lid);
9481ac6a89bSad #endif
949c62a74e6Sthorpej }
950c62a74e6Sthorpej 
951c62a74e6Sthorpej 
9526b2b9c62Syamt static void
9536b2b9c62Syamt pthread__dead(pthread_t self, pthread_t thread)
9546b2b9c62Syamt {
9556b2b9c62Syamt 
9566b2b9c62Syamt 	SDPRINTF(("(pthread__dead %p) Reclaimed %p.\n", self, thread));
957ded26025Sad #ifdef PTHREAD_SA
9586b2b9c62Syamt 	pthread__assert(thread != self);
959ded26025Sad #endif
9606b2b9c62Syamt 	pthread__assert(thread->pt_state == PT_STATE_DEAD);
9616b2b9c62Syamt 	pthread__assert(thread->pt_name == NULL);
9626b2b9c62Syamt 
9636b2b9c62Syamt 	/* Cleanup time. Move the dead thread from allqueue to the deadqueue */
9646b2b9c62Syamt 	pthread_spinlock(self, &pthread__allqueue_lock);
9656b2b9c62Syamt 	PTQ_REMOVE(&pthread__allqueue, thread, pt_allq);
9666b2b9c62Syamt 	pthread_spinunlock(self, &pthread__allqueue_lock);
9676b2b9c62Syamt 
9686b2b9c62Syamt 	pthread_spinlock(self, &pthread__deadqueue_lock);
9696b2b9c62Syamt 	PTQ_INSERT_HEAD(&pthread__deadqueue, thread, pt_allq);
9706b2b9c62Syamt 	pthread_spinunlock(self, &pthread__deadqueue_lock);
9716b2b9c62Syamt }
9726b2b9c62Syamt 
9736b2b9c62Syamt 
974c62a74e6Sthorpej int
975b33971b9Sthorpej pthread_getname_np(pthread_t thread, char *name, size_t len)
976c62a74e6Sthorpej {
977b33971b9Sthorpej 	pthread_t self;
978c62a74e6Sthorpej 
979b33971b9Sthorpej 	self = pthread__self();
980b33971b9Sthorpej 
981b33971b9Sthorpej 	if (pthread__find(self, thread) != 0)
982b33971b9Sthorpej 		return ESRCH;
983b33971b9Sthorpej 
984b33971b9Sthorpej 	if (thread->pt_magic != PT_MAGIC)
985b33971b9Sthorpej 		return EINVAL;
986b33971b9Sthorpej 
987b33971b9Sthorpej 	pthread_spinlock(self, &thread->pt_join_lock);
988b33971b9Sthorpej 	if (thread->pt_name == NULL)
989b33971b9Sthorpej 		name[0] = '\0';
990b33971b9Sthorpej 	else
991b33971b9Sthorpej 		strlcpy(name, thread->pt_name, len);
992b33971b9Sthorpej 	pthread_spinunlock(self, &thread->pt_join_lock);
993c62a74e6Sthorpej 
994c62a74e6Sthorpej 	return 0;
995c62a74e6Sthorpej }
996c62a74e6Sthorpej 
997c62a74e6Sthorpej 
998c62a74e6Sthorpej int
999b33971b9Sthorpej pthread_setname_np(pthread_t thread, const char *name, void *arg)
1000b33971b9Sthorpej {
1001ba70e96aSchs 	pthread_t self;
1002b33971b9Sthorpej 	char *oldname, *cp, newname[PTHREAD_MAX_NAMELEN_NP];
1003b33971b9Sthorpej 	int namelen;
1004b33971b9Sthorpej 
1005ba70e96aSchs 	self = pthread__self();
1006b33971b9Sthorpej 	if (pthread__find(self, thread) != 0)
1007b33971b9Sthorpej 		return ESRCH;
1008b33971b9Sthorpej 
1009b33971b9Sthorpej 	if (thread->pt_magic != PT_MAGIC)
1010b33971b9Sthorpej 		return EINVAL;
1011b33971b9Sthorpej 
1012b33971b9Sthorpej 	namelen = snprintf(newname, sizeof(newname), name, arg);
1013b33971b9Sthorpej 	if (namelen >= PTHREAD_MAX_NAMELEN_NP)
1014b33971b9Sthorpej 		return EINVAL;
1015b33971b9Sthorpej 
1016b33971b9Sthorpej 	cp = strdup(newname);
1017b33971b9Sthorpej 	if (cp == NULL)
1018b33971b9Sthorpej 		return ENOMEM;
1019b33971b9Sthorpej 
1020b33971b9Sthorpej 	pthread_spinlock(self, &thread->pt_join_lock);
1021b33971b9Sthorpej 
10221ac6a89bSad #ifdef PTHREAD_SA
1023b33971b9Sthorpej 	if (thread->pt_state == PT_STATE_DEAD) {
1024b33971b9Sthorpej 		pthread_spinunlock(self, &thread->pt_join_lock);
1025b33971b9Sthorpej 		free(cp);
1026b33971b9Sthorpej 		return EINVAL;
1027b33971b9Sthorpej 	}
10281ac6a89bSad #endif
1029b33971b9Sthorpej 
1030b33971b9Sthorpej 	oldname = thread->pt_name;
1031b33971b9Sthorpej 	thread->pt_name = cp;
1032b33971b9Sthorpej 
1033b33971b9Sthorpej 	pthread_spinunlock(self, &thread->pt_join_lock);
1034b33971b9Sthorpej 
1035b33971b9Sthorpej 	if (oldname != NULL)
1036b33971b9Sthorpej 		free(oldname);
1037b33971b9Sthorpej 
1038b33971b9Sthorpej 	return 0;
1039b33971b9Sthorpej }
1040b33971b9Sthorpej 
1041b33971b9Sthorpej 
1042b33971b9Sthorpej 
1043c62a74e6Sthorpej /*
1044c62a74e6Sthorpej  * XXX There should be a way for applications to use the efficent
1045c62a74e6Sthorpej  *  inline version, but there are opacity/namespace issues.
1046c62a74e6Sthorpej  */
1047c62a74e6Sthorpej pthread_t
1048c62a74e6Sthorpej pthread_self(void)
1049c62a74e6Sthorpej {
1050c62a74e6Sthorpej 
1051c62a74e6Sthorpej 	return pthread__self();
1052c62a74e6Sthorpej }
1053c62a74e6Sthorpej 
1054c62a74e6Sthorpej 
1055c62a74e6Sthorpej int
1056c62a74e6Sthorpej pthread_cancel(pthread_t thread)
1057c62a74e6Sthorpej {
1058c62a74e6Sthorpej 	pthread_t self;
1059c62a74e6Sthorpej 
1060ba70e96aSchs 	self = pthread__self();
1061ba70e96aSchs #ifdef ERRORCHECK
1062ba70e96aSchs 	if (pthread__find(self, thread) != 0)
1063ba70e96aSchs 		return ESRCH;
1064ba70e96aSchs #endif
10651ac6a89bSad #ifdef PTHREAD_SA
1066c62a74e6Sthorpej 	if (!(thread->pt_state == PT_STATE_RUNNING ||
1067c62a74e6Sthorpej 	    thread->pt_state == PT_STATE_RUNNABLE ||
106882b6b2dbScl 	    thread->pt_state == PT_STATE_BLOCKED_QUEUE))
1069c62a74e6Sthorpej 		return ESRCH;
1070c62a74e6Sthorpej 
10710878df5dSnathanw 	pthread_spinlock(self, &thread->pt_flaglock);
10720878df5dSnathanw 	thread->pt_flags |= PT_FLAG_CS_PENDING;
10730878df5dSnathanw 	if ((thread->pt_flags & PT_FLAG_CS_DISABLED) == 0) {
1074c62a74e6Sthorpej 		thread->pt_cancel = 1;
10750878df5dSnathanw 		pthread_spinunlock(self, &thread->pt_flaglock);
1076c62a74e6Sthorpej 		pthread_spinlock(self, &thread->pt_statelock);
107782b6b2dbScl 		if (thread->pt_blockgen != thread->pt_unblockgen) {
1078c62a74e6Sthorpej 			/*
1079c62a74e6Sthorpej 			 * It's sleeping in the kernel. If we can wake
1080c62a74e6Sthorpej 			 * it up, it will notice the cancellation when
1081c62a74e6Sthorpej 			 * it returns. If it doesn't wake up when we
1082c62a74e6Sthorpej 			 * make this call, then it's blocked
1083c62a74e6Sthorpej 			 * uninterruptably in the kernel, and there's
1084c62a74e6Sthorpej 			 * not much to be done about it.
1085c62a74e6Sthorpej 			 */
1086c62a74e6Sthorpej 			_lwp_wakeup(thread->pt_blockedlwp);
1087c62a74e6Sthorpej 		} else if (thread->pt_state == PT_STATE_BLOCKED_QUEUE) {
1088c62a74e6Sthorpej 			/*
1089c62a74e6Sthorpej 			 * We're blocked somewhere (pthread__block()
10908bcff70bSnathanw 			 * was called). Cause it to wake up; it will
10918bcff70bSnathanw 			 * check for the cancellation if the routine
10928bcff70bSnathanw 			 * is a cancellation point, and loop and reblock
10938bcff70bSnathanw 			 * otherwise.
1094c62a74e6Sthorpej 			 */
1095c62a74e6Sthorpej 			pthread_spinlock(self, thread->pt_sleeplock);
1096c62a74e6Sthorpej 			PTQ_REMOVE(thread->pt_sleepq, thread,
1097c62a74e6Sthorpej 			    pt_sleep);
1098c62a74e6Sthorpej 			pthread_spinunlock(self, thread->pt_sleeplock);
1099c62a74e6Sthorpej 			pthread__sched(self, thread);
1100c62a74e6Sthorpej 		} else {
1101c62a74e6Sthorpej 			/*
1102c62a74e6Sthorpej 			 * Nothing. The target thread is running and will
1103c62a74e6Sthorpej 			 * notice at the next deferred cancellation point.
1104c62a74e6Sthorpej 			 */
1105c62a74e6Sthorpej 		}
1106c62a74e6Sthorpej 		pthread_spinunlock(self, &thread->pt_statelock);
11070878df5dSnathanw 	} else
11080878df5dSnathanw 		pthread_spinunlock(self, &thread->pt_flaglock);
11091ac6a89bSad #else
11101ac6a89bSad 	pthread_spinlock(self, &thread->pt_flaglock);
11111ac6a89bSad 	thread->pt_flags |= PT_FLAG_CS_PENDING;
11121ac6a89bSad 	if ((thread->pt_flags & PT_FLAG_CS_DISABLED) == 0) {
11131ac6a89bSad 		thread->pt_cancel = 1;
11141ac6a89bSad 		pthread_spinunlock(self, &thread->pt_flaglock);
11151ac6a89bSad 		_lwp_wakeup(thread->pt_lid);
11161ac6a89bSad 	} else
11171ac6a89bSad 		pthread_spinunlock(self, &thread->pt_flaglock);
11181ac6a89bSad #endif
1119c62a74e6Sthorpej 
1120c62a74e6Sthorpej 	return 0;
1121c62a74e6Sthorpej }
1122c62a74e6Sthorpej 
1123c62a74e6Sthorpej 
1124c62a74e6Sthorpej int
1125c62a74e6Sthorpej pthread_setcancelstate(int state, int *oldstate)
1126c62a74e6Sthorpej {
1127c62a74e6Sthorpej 	pthread_t self;
11280878df5dSnathanw 	int retval;
1129c62a74e6Sthorpej 
1130c62a74e6Sthorpej 	self = pthread__self();
11310878df5dSnathanw 	retval = 0;
1132c62a74e6Sthorpej 
11330878df5dSnathanw 	pthread_spinlock(self, &self->pt_flaglock);
1134c62a74e6Sthorpej 	if (oldstate != NULL) {
11350878df5dSnathanw 		if (self->pt_flags & PT_FLAG_CS_DISABLED)
1136c62a74e6Sthorpej 			*oldstate = PTHREAD_CANCEL_DISABLE;
1137c62a74e6Sthorpej 		else
1138c62a74e6Sthorpej 			*oldstate = PTHREAD_CANCEL_ENABLE;
1139c62a74e6Sthorpej 	}
1140c62a74e6Sthorpej 
11410878df5dSnathanw 	if (state == PTHREAD_CANCEL_DISABLE) {
11420878df5dSnathanw 		self->pt_flags |= PT_FLAG_CS_DISABLED;
11430878df5dSnathanw 		if (self->pt_cancel) {
11440878df5dSnathanw 			self->pt_flags |= PT_FLAG_CS_PENDING;
11450878df5dSnathanw 			self->pt_cancel = 0;
11460878df5dSnathanw 		}
11470878df5dSnathanw 	} else if (state == PTHREAD_CANCEL_ENABLE) {
11480878df5dSnathanw 		self->pt_flags &= ~PT_FLAG_CS_DISABLED;
1149c62a74e6Sthorpej 		/*
1150c62a74e6Sthorpej 		 * If a cancellation was requested while cancellation
1151c62a74e6Sthorpej 		 * was disabled, note that fact for future
1152c62a74e6Sthorpej 		 * cancellation tests.
1153c62a74e6Sthorpej 		 */
11540878df5dSnathanw 		if (self->pt_flags & PT_FLAG_CS_PENDING) {
1155c62a74e6Sthorpej 			self->pt_cancel = 1;
1156c62a74e6Sthorpej 			/* This is not a deferred cancellation point. */
11570878df5dSnathanw 			if (self->pt_flags & PT_FLAG_CS_ASYNC) {
11580878df5dSnathanw 				pthread_spinunlock(self, &self->pt_flaglock);
1159c62a74e6Sthorpej 				pthread_exit(PTHREAD_CANCELED);
1160c62a74e6Sthorpej 			}
11610878df5dSnathanw 		}
1162c62a74e6Sthorpej 	} else
11630878df5dSnathanw 		retval = EINVAL;
1164c62a74e6Sthorpej 
11650878df5dSnathanw 	pthread_spinunlock(self, &self->pt_flaglock);
11660878df5dSnathanw 	return retval;
1167c62a74e6Sthorpej }
1168c62a74e6Sthorpej 
1169c62a74e6Sthorpej 
1170c62a74e6Sthorpej int
1171c62a74e6Sthorpej pthread_setcanceltype(int type, int *oldtype)
1172c62a74e6Sthorpej {
1173c62a74e6Sthorpej 	pthread_t self;
11740878df5dSnathanw 	int retval;
1175c62a74e6Sthorpej 
1176c62a74e6Sthorpej 	self = pthread__self();
11770878df5dSnathanw 	retval = 0;
11780878df5dSnathanw 
11790878df5dSnathanw 	pthread_spinlock(self, &self->pt_flaglock);
1180c62a74e6Sthorpej 
1181c62a74e6Sthorpej 	if (oldtype != NULL) {
11820878df5dSnathanw 		if (self->pt_flags & PT_FLAG_CS_ASYNC)
1183c62a74e6Sthorpej 			*oldtype = PTHREAD_CANCEL_ASYNCHRONOUS;
1184c62a74e6Sthorpej 		else
1185c62a74e6Sthorpej 			*oldtype = PTHREAD_CANCEL_DEFERRED;
1186c62a74e6Sthorpej 	}
1187c62a74e6Sthorpej 
1188c62a74e6Sthorpej 	if (type == PTHREAD_CANCEL_ASYNCHRONOUS) {
11890878df5dSnathanw 		self->pt_flags |= PT_FLAG_CS_ASYNC;
11900878df5dSnathanw 		if (self->pt_cancel) {
11910878df5dSnathanw 			pthread_spinunlock(self, &self->pt_flaglock);
1192c62a74e6Sthorpej 			pthread_exit(PTHREAD_CANCELED);
11930878df5dSnathanw 		}
1194c62a74e6Sthorpej 	} else if (type == PTHREAD_CANCEL_DEFERRED)
11950878df5dSnathanw 		self->pt_flags &= ~PT_FLAG_CS_ASYNC;
1196c62a74e6Sthorpej 	else
11970878df5dSnathanw 		retval = EINVAL;
1198c62a74e6Sthorpej 
11990878df5dSnathanw 	pthread_spinunlock(self, &self->pt_flaglock);
12000878df5dSnathanw 	return retval;
1201c62a74e6Sthorpej }
1202c62a74e6Sthorpej 
1203c62a74e6Sthorpej 
1204c62a74e6Sthorpej void
1205c62a74e6Sthorpej pthread_testcancel()
1206c62a74e6Sthorpej {
1207c62a74e6Sthorpej 	pthread_t self;
1208c62a74e6Sthorpej 
1209c62a74e6Sthorpej 	self = pthread__self();
1210c62a74e6Sthorpej 	if (self->pt_cancel)
1211c62a74e6Sthorpej 		pthread_exit(PTHREAD_CANCELED);
1212c62a74e6Sthorpej }
1213c62a74e6Sthorpej 
1214c62a74e6Sthorpej 
1215c62a74e6Sthorpej /*
1216c62a74e6Sthorpej  * POSIX requires that certain functions return an error rather than
1217c62a74e6Sthorpej  * invoking undefined behavior even when handed completely bogus
1218c62a74e6Sthorpej  * pthread_t values, e.g. stack garbage or (pthread_t)666. This
1219c62a74e6Sthorpej  * utility routine searches the list of threads for the pthread_t
1220c62a74e6Sthorpej  * value without dereferencing it.
1221c62a74e6Sthorpej  */
1222c62a74e6Sthorpej int
1223c62a74e6Sthorpej pthread__find(pthread_t self, pthread_t id)
1224c62a74e6Sthorpej {
1225c62a74e6Sthorpej 	pthread_t target;
1226c62a74e6Sthorpej 
1227c62a74e6Sthorpej 	pthread_spinlock(self, &pthread__allqueue_lock);
1228c62a74e6Sthorpej 	PTQ_FOREACH(target, &pthread__allqueue, pt_allq)
1229c62a74e6Sthorpej 	    if (target == id)
1230c62a74e6Sthorpej 		    break;
1231c62a74e6Sthorpej 	pthread_spinunlock(self, &pthread__allqueue_lock);
1232c62a74e6Sthorpej 
1233c62a74e6Sthorpej 	if (target == NULL)
1234c62a74e6Sthorpej 		return ESRCH;
1235c62a74e6Sthorpej 
1236c62a74e6Sthorpej 	return 0;
1237c62a74e6Sthorpej }
1238c62a74e6Sthorpej 
1239c62a74e6Sthorpej 
1240c62a74e6Sthorpej void
1241c62a74e6Sthorpej pthread__testcancel(pthread_t self)
1242c62a74e6Sthorpej {
1243c62a74e6Sthorpej 
1244c62a74e6Sthorpej 	if (self->pt_cancel)
1245c62a74e6Sthorpej 		pthread_exit(PTHREAD_CANCELED);
1246c62a74e6Sthorpej }
1247c62a74e6Sthorpej 
1248c62a74e6Sthorpej 
1249c62a74e6Sthorpej void
1250c62a74e6Sthorpej pthread__cleanup_push(void (*cleanup)(void *), void *arg, void *store)
1251c62a74e6Sthorpej {
1252c62a74e6Sthorpej 	pthread_t self;
1253c62a74e6Sthorpej 	struct pt_clean_t *entry;
1254c62a74e6Sthorpej 
1255c62a74e6Sthorpej 	self = pthread__self();
1256c62a74e6Sthorpej 	entry = store;
1257c62a74e6Sthorpej 	entry->ptc_cleanup = cleanup;
1258c62a74e6Sthorpej 	entry->ptc_arg = arg;
1259c62a74e6Sthorpej 	PTQ_INSERT_HEAD(&self->pt_cleanup_stack, entry, ptc_next);
1260c62a74e6Sthorpej }
1261c62a74e6Sthorpej 
1262c62a74e6Sthorpej 
1263c62a74e6Sthorpej void
1264c62a74e6Sthorpej pthread__cleanup_pop(int ex, void *store)
1265c62a74e6Sthorpej {
1266c62a74e6Sthorpej 	pthread_t self;
1267c62a74e6Sthorpej 	struct pt_clean_t *entry;
1268c62a74e6Sthorpej 
1269c62a74e6Sthorpej 	self = pthread__self();
1270c62a74e6Sthorpej 	entry = store;
1271c62a74e6Sthorpej 
1272c62a74e6Sthorpej 	PTQ_REMOVE(&self->pt_cleanup_stack, entry, ptc_next);
1273c62a74e6Sthorpej 	if (ex)
1274c62a74e6Sthorpej 		(*entry->ptc_cleanup)(entry->ptc_arg);
1275c62a74e6Sthorpej }
1276c62a74e6Sthorpej 
1277c62a74e6Sthorpej 
1278c62a74e6Sthorpej int *
1279c62a74e6Sthorpej pthread__errno(void)
1280c62a74e6Sthorpej {
1281c62a74e6Sthorpej 	pthread_t self;
1282c62a74e6Sthorpej 
1283c62a74e6Sthorpej 	self = pthread__self();
1284c62a74e6Sthorpej 
1285c62a74e6Sthorpej 	return &(self->pt_errno);
1286c62a74e6Sthorpej }
12878bcff70bSnathanw 
12880c967901Snathanw ssize_t	_sys_write(int, const void *, size_t);
12890c967901Snathanw 
12908bcff70bSnathanw void
12910e6c93b9Sdrochner pthread__assertfunc(const char *file, int line, const char *function,
12920e6c93b9Sdrochner 		    const char *expr)
12938bcff70bSnathanw {
12948bcff70bSnathanw 	char buf[1024];
12958bcff70bSnathanw 	int len;
12968bcff70bSnathanw 
129775a94788Smycroft 	SDPRINTF(("(af)\n"));
129875a94788Smycroft 
12998bcff70bSnathanw 	/*
13008bcff70bSnathanw 	 * snprintf should not acquire any locks, or we could
13018bcff70bSnathanw 	 * end up deadlocked if the assert caller held locks.
13028bcff70bSnathanw 	 */
13038bcff70bSnathanw 	len = snprintf(buf, 1024,
13048bcff70bSnathanw 	    "assertion \"%s\" failed: file \"%s\", line %d%s%s%s\n",
13058bcff70bSnathanw 	    expr, file, line,
13068bcff70bSnathanw 	    function ? ", function \"" : "",
13078bcff70bSnathanw 	    function ? function : "",
13088bcff70bSnathanw 	    function ? "\"" : "");
13098bcff70bSnathanw 
13100c967901Snathanw 	_sys_write(STDERR_FILENO, buf, (size_t)len);
13118bcff70bSnathanw 	(void)kill(getpid(), SIGABRT);
13128bcff70bSnathanw 
13138bcff70bSnathanw 	_exit(1);
13148bcff70bSnathanw }
1315df277271Snathanw 
1316df277271Snathanw 
1317df277271Snathanw void
13180e6c93b9Sdrochner pthread__errorfunc(const char *file, int line, const char *function,
13190e6c93b9Sdrochner 		   const char *msg)
1320df277271Snathanw {
1321df277271Snathanw 	char buf[1024];
13220172694eSnathanw 	size_t len;
1323df277271Snathanw 
13240172694eSnathanw 	if (pthread__diagassert == 0)
1325df277271Snathanw 		return;
1326df277271Snathanw 
1327df277271Snathanw 	/*
1328df277271Snathanw 	 * snprintf should not acquire any locks, or we could
1329df277271Snathanw 	 * end up deadlocked if the assert caller held locks.
1330df277271Snathanw 	 */
1331df277271Snathanw 	len = snprintf(buf, 1024,
13320172694eSnathanw 	    "%s: Error detected by libpthread: %s.\n"
13330172694eSnathanw 	    "Detected by file \"%s\", line %d%s%s%s.\n"
13340172694eSnathanw 	    "See pthread(3) for information.\n",
13350172694eSnathanw 	    getprogname(), msg, file, line,
1336df277271Snathanw 	    function ? ", function \"" : "",
1337df277271Snathanw 	    function ? function : "",
13380172694eSnathanw 	    function ? "\"" : "");
1339df277271Snathanw 
13400172694eSnathanw 	if (pthread__diagassert & DIAGASSERT_STDERR)
13410c967901Snathanw 		_sys_write(STDERR_FILENO, buf, len);
13420172694eSnathanw 
13430172694eSnathanw 	if (pthread__diagassert & DIAGASSERT_SYSLOG)
13440172694eSnathanw 		syslog(LOG_DEBUG | LOG_USER, "%s", buf);
13450172694eSnathanw 
13460172694eSnathanw 	if (pthread__diagassert & DIAGASSERT_ABORT) {
1347df277271Snathanw 		(void)kill(getpid(), SIGABRT);
1348df277271Snathanw 		_exit(1);
1349df277271Snathanw 	}
1350df277271Snathanw }
13511ac6a89bSad 
13521ac6a89bSad #ifndef PTHREAD_SA
13531ac6a89bSad 
1354fe9718acSad /*
1355ded26025Sad  * Thread park/unpark operations.  The kernel operations are
1356ded26025Sad  * modelled after a brief description from "Multithreading in
1357ded26025Sad  * the Solaris Operating Environment":
1358fe9718acSad  *
1359fe9718acSad  * http://www.sun.com/software/whitepapers/solaris9/multithread.pdf
1360fe9718acSad  */
1361fe9718acSad 
13621ac6a89bSad #define	OOPS(msg)			\
1363858097f9Schristos     pthread__errorfunc(__FILE__, __LINE__, __func__, msg)
13641ac6a89bSad 
13651ac6a89bSad int
13661ac6a89bSad pthread__park(pthread_t self, pthread_spin_t *lock,
13671ac6a89bSad 	      void *obj, struct pthread_queue_t *queue,
1368ded26025Sad 	      const struct timespec *abstime, int tail,
1369ded26025Sad 	      int cancelpt)
13701ac6a89bSad {
13711ac6a89bSad 	int rv;
13721ac6a89bSad 
13731ac6a89bSad 	SDPRINTF(("(pthread__park %p) obj %p enter\n", self, obj));
13741ac6a89bSad 
1375ded26025Sad 	/*
1376ded26025Sad 	 * Enter the object's queue.
1377ded26025Sad 	 */
13781ac6a89bSad 	if (queue != NULL) {
13791ac6a89bSad 		if (tail)
13801ac6a89bSad 			PTQ_INSERT_TAIL(queue, self, pt_sleep);
13811ac6a89bSad 		else
13821ac6a89bSad 			PTQ_INSERT_HEAD(queue, self, pt_sleep);
1383ded26025Sad 		self->pt_sleeponq = 1;
13841ac6a89bSad 	}
13851ac6a89bSad 	self->pt_sleepobj = obj;
13861ac6a89bSad 
1387ded26025Sad 	/*
1388ded26025Sad 	 * Wait until we are awoken by a pending unpark operation,
1389ded26025Sad 	 * a signal, an unpark posted after we have gone asleep,
1390ded26025Sad 	 * or an expired timeout.
1391ded26025Sad 	 */
1392ded26025Sad 	rv = 0;
13931ac6a89bSad 	do {
13941ac6a89bSad 		pthread_spinunlock(self, lock);
139539aa27f5Sad 		if (_lwp_park(abstime, NULL, obj) != 0) {
1396ded26025Sad 			switch (rv = errno) {
13971ac6a89bSad 			case EINTR:
1398ded26025Sad 				/* Check for cancellation. */
1399ded26025Sad 				if (cancelpt && self->pt_cancel)
1400ded26025Sad 					break;
1401ded26025Sad 				/* FALLTHROUGH */
14021ac6a89bSad 			case EALREADY:
1403ded26025Sad 				rv = 0;
1404ded26025Sad 				break;
1405ded26025Sad 			case ETIMEDOUT:
14061ac6a89bSad 				break;
14071ac6a89bSad 			default:
14081ac6a89bSad 				OOPS("_lwp_park failed");
14091ac6a89bSad 				SDPRINTF(("(pthread__park %p) syscall rv=%d\n",
14101ac6a89bSad 				    self, rv));
14111ac6a89bSad 				break;
14121ac6a89bSad 			}
1413ded26025Sad 		}
14141ac6a89bSad 		pthread_spinlock(self, lock);
1415ded26025Sad 	} while (self->pt_sleepobj != NULL && rv == 0);
14161ac6a89bSad 
1417ded26025Sad 	/*
1418ded26025Sad 	 * If we have been awoken early but are still on the queue,
1419ded26025Sad 	 * then remove ourself.
1420ded26025Sad 	 */
1421ded26025Sad 	if (queue != NULL && self->pt_sleeponq)
14221ac6a89bSad 		PTQ_REMOVE(queue, self, pt_sleep);
14231ac6a89bSad 	self->pt_sleepobj = NULL;
1424ded26025Sad 	self->pt_sleeponq = 0;
14251ac6a89bSad 
14261ac6a89bSad 	SDPRINTF(("(pthread__park %p) obj %p exit\n", self, obj));
14271ac6a89bSad 
14281ac6a89bSad 	return rv;
14291ac6a89bSad }
14301ac6a89bSad 
14311ac6a89bSad void
14321ac6a89bSad pthread__unpark(pthread_t self, pthread_spin_t *lock, void *obj,
14331ac6a89bSad 		pthread_t target)
14341ac6a89bSad {
14351ac6a89bSad 	int rv;
14361ac6a89bSad 
14371ac6a89bSad 	if (target != NULL) {
14381ac6a89bSad 		SDPRINTF(("(pthread__unpark %p) obj %p target %p\n", self, obj,
14391ac6a89bSad 		    target));
14401ac6a89bSad 
1441ded26025Sad 		/*
1442ded26025Sad 		 * Easy: the thread has already been removed from
1443ded26025Sad 		 * the queue, so just awaken it.
1444ded26025Sad 		 */
14451ac6a89bSad 		target->pt_sleepobj = NULL;
1446ded26025Sad 		target->pt_sleeponq = 0;
14471ac6a89bSad 		pthread_spinunlock(self, lock);
144839aa27f5Sad 		rv = _lwp_unpark(target->pt_lid, obj);
14491ac6a89bSad 
14501ac6a89bSad 		if (rv != 0 && errno != EALREADY && errno != EINTR) {
14511ac6a89bSad 			SDPRINTF(("(pthread__unpark %p) syscall rv=%d\n",
14521ac6a89bSad 			    self, rv));
14531ac6a89bSad 			OOPS("_lwp_unpark failed");
14541ac6a89bSad 		}
14551ac6a89bSad 	} else
14561ac6a89bSad 		pthread_spinunlock(self, lock);
14571ac6a89bSad }
14581ac6a89bSad 
14591ac6a89bSad void
14601ac6a89bSad pthread__unpark_all(pthread_t self, pthread_spin_t *lock, void *obj,
14611ac6a89bSad 		    struct pthread_queue_t *queue)
14621ac6a89bSad {
1463ded26025Sad 	lwpid_t waiters[PTHREAD__UNPARK_MAX];
1464ded26025Sad 	int n, rv;
1465ded26025Sad 	pthread_t thread, next;
1466ded26025Sad 
1467ded26025Sad 	if (PTQ_EMPTY(queue)) {
1468ded26025Sad 		pthread_spinunlock(self, lock);
1469ded26025Sad 		return;
1470ded26025Sad 	}
1471ded26025Sad 
1472ded26025Sad 	/*
1473ded26025Sad 	 * First, clear all sleepobj pointers, since we can release the
1474ded26025Sad 	 * spin lock before awkening everybody, and must synchronise with
1475ded26025Sad 	 * pthread__park().
1476ded26025Sad 	 */
1477ded26025Sad 	PTQ_FOREACH(thread, queue, pt_sleep) {
1478ded26025Sad 		thread->pt_sleepobj = NULL;
1479ded26025Sad 	}
14801ac6a89bSad 
14811ac6a89bSad 	for (;;) {
1482ded26025Sad 		thread = PTQ_FIRST(queue);
1483ded26025Sad 		for (n = 0; n < pthread__unpark_max && thread != NULL;
1484ded26025Sad 		    thread = next) {
1485ded26025Sad 			/*
1486ded26025Sad 			 * If the sleepobj pointer is non-NULL, it
1487ded26025Sad 			 * means one of two things:
1488ded26025Sad 			 *
1489ded26025Sad 			 * o The thread has awoken early, spun
1490ded26025Sad 			 *   through application code and is
1491ded26025Sad 			 *   once more asleep on this object.
1492ded26025Sad 			 *
1493ded26025Sad 			 * o This is a new thread that has blocked
1494ded26025Sad 			 *   on the object after we have released
1495ded26025Sad 			 *   the interlock in this loop.
1496ded26025Sad 			 *
1497ded26025Sad 			 * In both cases we shouldn't remove the
1498ded26025Sad 			 * thread from the queue.
1499ded26025Sad 			 *
1500ded26025Sad 			 * XXXLWP basic fairness issues here.
1501ded26025Sad 			 */
1502ded26025Sad 			next = PTQ_NEXT(thread, pt_sleep);
1503ded26025Sad 			if (thread->pt_sleepobj != NULL)
1504ded26025Sad 			    	continue;
1505ded26025Sad 			thread->pt_sleeponq = 0;
1506ded26025Sad 			waiters[n++] = thread->pt_lid;
15071ac6a89bSad 			PTQ_REMOVE(queue, thread, pt_sleep);
15081ac6a89bSad 			SDPRINTF(("(pthread__unpark_all %p) obj %p "
15091ac6a89bSad 			    "unpark %p\n", self, obj, thread));
15101ac6a89bSad 		}
1511ded26025Sad 
15121ac6a89bSad 		pthread_spinunlock(self, lock);
1513ded26025Sad 		switch (n) {
15141ac6a89bSad 		case 0:
15151ac6a89bSad 			return;
15161ac6a89bSad 		case 1:
151739aa27f5Sad 			rv = _lwp_unpark(waiters[0], obj);
15181ac6a89bSad 			if (rv != 0 && errno != EALREADY && errno != EINTR) {
15191ac6a89bSad 				OOPS("_lwp_unpark failed");
15201ac6a89bSad 				SDPRINTF(("(pthread__unpark_all %p) "
15211ac6a89bSad 				    "syscall rv=%d\n", self, rv));
15221ac6a89bSad 			}
15231ac6a89bSad 			return;
15241ac6a89bSad 		default:
152539aa27f5Sad 			rv = _lwp_unpark_all(waiters, n, obj);
15261ac6a89bSad 			if (rv != 0 && errno != EINTR) {
15271ac6a89bSad 				OOPS("_lwp_unpark_all failed");
15281ac6a89bSad 				SDPRINTF(("(pthread__unpark_all %p) "
15291ac6a89bSad 				    "syscall rv=%d\n", self, rv));
15301ac6a89bSad 			}
15311ac6a89bSad 			break;
15321ac6a89bSad 		}
15331ac6a89bSad 		pthread_spinlock(self, lock);
15341ac6a89bSad 	}
15351ac6a89bSad }
15361ac6a89bSad 
15371ac6a89bSad #undef	OOPS
15381ac6a89bSad 
15391ac6a89bSad #endif	/* !PTHREAD_SA */
1540