xref: /netbsd-src/lib/libpthread/pthread.c (revision c3f8e2ee5591d3f39aa0d01836fa8be176025b29)
1*c3f8e2eeSad /*	$NetBSD: pthread.c,v 1.72 2007/08/07 19:04:21 ad Exp $	*/
2c62a74e6Sthorpej 
3c62a74e6Sthorpej /*-
41296e850Sad  * 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*c3f8e2eeSad __RCSID("$NetBSD: pthread.c,v 1.72 2007/08/07 19:04:21 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>
548bcff70bSnathanw 
55c62a74e6Sthorpej #include <sched.h>
56c62a74e6Sthorpej #include "pthread.h"
57c62a74e6Sthorpej #include "pthread_int.h"
58c62a74e6Sthorpej 
59c62a74e6Sthorpej #ifdef PTHREAD_MAIN_DEBUG
60c62a74e6Sthorpej #define SDPRINTF(x) DPRINTF(x)
61c62a74e6Sthorpej #else
62c62a74e6Sthorpej #define SDPRINTF(x)
63c62a74e6Sthorpej #endif
64c62a74e6Sthorpej 
65ded26025Sad /* Maximum number of LWPs to unpark in one operation. */
66ded26025Sad #define	PTHREAD__UNPARK_MAX	128
67ded26025Sad 
68ded26025Sad /* How many times to try acquiring spin locks on MP systems. */
69dc39f9ecSad #define	PTHREAD__NSPINS		1024
70ded26025Sad 
7150fa8db4Sad static void	pthread__create_tramp(void *(*)(void *), void *);
7250fa8db4Sad static void	pthread__initthread(pthread_t);
73c62a74e6Sthorpej 
74c62a74e6Sthorpej int pthread__started;
75c62a74e6Sthorpej 
7650fa8db4Sad pthread_spin_t pthread__queue_lock = __SIMPLELOCK_UNLOCKED;
7750fa8db4Sad pthread_queue_t pthread__allqueue;
7850fa8db4Sad pthread_queue_t pthread__deadqueue;
79c62a74e6Sthorpej 
80c62a74e6Sthorpej static pthread_attr_t pthread_default_attr;
81c62a74e6Sthorpej 
820172694eSnathanw enum {
830172694eSnathanw 	DIAGASSERT_ABORT =	1<<0,
840172694eSnathanw 	DIAGASSERT_STDERR =	1<<1,
850172694eSnathanw 	DIAGASSERT_SYSLOG =	1<<2
860172694eSnathanw };
87df277271Snathanw 
880172694eSnathanw static int pthread__diagassert = DIAGASSERT_ABORT | DIAGASSERT_STDERR;
89df277271Snathanw 
90ded26025Sad int pthread__concurrency, pthread__maxconcurrency, pthread__nspins;
91ded26025Sad int pthread__unpark_max = PTHREAD__UNPARK_MAX;
92*c3f8e2eeSad int pthread__osrevision;
93f2f10664Scl 
94f782e995Sdrochner int _sys___sigprocmask14(int, const sigset_t *, sigset_t *);
95f782e995Sdrochner 
96c62a74e6Sthorpej __strong_alias(__libc_thr_self,pthread_self)
977dc01dbfSthorpej __strong_alias(__libc_thr_create,pthread_create)
987dc01dbfSthorpej __strong_alias(__libc_thr_exit,pthread_exit)
99c62a74e6Sthorpej __strong_alias(__libc_thr_errno,pthread__errno)
1009e5c8705Snathanw __strong_alias(__libc_thr_setcancelstate,pthread_setcancelstate)
101c62a74e6Sthorpej 
102c62a74e6Sthorpej /*
103c62a74e6Sthorpej  * Static library kludge.  Place a reference to a symbol any library
104c62a74e6Sthorpej  * file which does not already have a reference here.
105c62a74e6Sthorpej  */
106c62a74e6Sthorpej extern int pthread__cancel_stub_binder;
107c62a74e6Sthorpej 
108c62a74e6Sthorpej void *pthread__static_lib_binder[] = {
109c62a74e6Sthorpej 	&pthread__cancel_stub_binder,
110c62a74e6Sthorpej 	pthread_cond_init,
111c62a74e6Sthorpej 	pthread_mutex_init,
112c62a74e6Sthorpej 	pthread_rwlock_init,
113c62a74e6Sthorpej 	pthread_barrier_init,
114c62a74e6Sthorpej 	pthread_key_create,
115bd9a18b7Snathanw 	pthread_setspecific,
116c62a74e6Sthorpej };
117c62a74e6Sthorpej 
118c62a74e6Sthorpej /*
119c62a74e6Sthorpej  * This needs to be started by the library loading code, before main()
120c62a74e6Sthorpej  * gets to run, for various things that use the state of the initial thread
121c62a74e6Sthorpej  * to work properly (thread-specific data is an application-visible example;
122c62a74e6Sthorpej  * spinlock counts for mutexes is an internal example).
123c62a74e6Sthorpej  */
124c62a74e6Sthorpej void
125c62a74e6Sthorpej pthread_init(void)
126c62a74e6Sthorpej {
127c62a74e6Sthorpej 	pthread_t first;
1280172694eSnathanw 	char *p;
129ded26025Sad 	int i, mib[2], ncpu;
130f2f10664Scl 	size_t len;
131c62a74e6Sthorpej 	extern int __isthreaded;
132c62a74e6Sthorpej 
133f2f10664Scl 	mib[0] = CTL_HW;
134f2f10664Scl 	mib[1] = HW_NCPU;
135f2f10664Scl 
136f2f10664Scl 	len = sizeof(ncpu);
137792cc0e1Sad 	if (sysctl(mib, 2, &ncpu, &len, NULL, 0) == -1)
138792cc0e1Sad 		err(1, "sysctl(hw.ncpu");
139f2f10664Scl 
140*c3f8e2eeSad 	mib[0] = CTL_KERN;
141*c3f8e2eeSad 	mib[1] = KERN_OSREV;
142*c3f8e2eeSad 
143*c3f8e2eeSad 	len = sizeof(pthread__osrev);
144*c3f8e2eeSad 	if (sysctl(mib, 2, &pthread__osrev, &len, NULL, 0) == -1)
145*c3f8e2eeSad 		err(1, "sysctl(hw.osrevision");
146*c3f8e2eeSad 
147c62a74e6Sthorpej 	/* Initialize locks first; they're needed elsewhere. */
148f2f10664Scl 	pthread__lockprim_init(ncpu);
149f2f10664Scl 
150ded26025Sad 	/*
151ded26025Sad 	 * Get number of CPUs, and maximum number of LWPs that can be
152ded26025Sad 	 * unparked at once.
153ded26025Sad 	 */
154ded26025Sad 	if ((pthread__concurrency = ncpu) > 1)
155ded26025Sad 		pthread__nspins = PTHREAD__NSPINS;
156ded26025Sad 	else
157ded26025Sad 		pthread__nspins = 1;
15850fa8db4Sad 	if ((p = getenv("PTHREAD_NSPINS")) != NULL)
15950fa8db4Sad 		pthread__nspins = atoi(p);
1603247035dSad 	i = (int)_lwp_unpark_all(NULL, 0, NULL);
1613247035dSad 	if (i == -1)
1623247035dSad 		err(1, "_lwp_unpark_all");
163ded26025Sad 	if (i < pthread__unpark_max)
164ded26025Sad 		pthread__unpark_max = i;
165c62a74e6Sthorpej 
166c62a74e6Sthorpej 	/* Basic data structure setup */
167c62a74e6Sthorpej 	pthread_attr_init(&pthread_default_attr);
168c62a74e6Sthorpej 	PTQ_INIT(&pthread__allqueue);
169c62a74e6Sthorpej 	PTQ_INIT(&pthread__deadqueue);
170c62a74e6Sthorpej 	/* Create the thread structure corresponding to main() */
171c62a74e6Sthorpej 	pthread__initmain(&first);
17250fa8db4Sad 	pthread__initthread(first);
1731ac6a89bSad 
174c62a74e6Sthorpej 	first->pt_state = PT_STATE_RUNNING;
1751ac6a89bSad 	first->pt_lid = _lwp_self();
176c62a74e6Sthorpej 	PTQ_INSERT_HEAD(&pthread__allqueue, first, pt_allq);
177c62a74e6Sthorpej 
178c62a74e6Sthorpej 	/* Start subsystems */
179c62a74e6Sthorpej 	PTHREAD_MD_INIT
180c62a74e6Sthorpej #ifdef PTHREAD__DEBUG
181f2f10664Scl 	pthread__debug_init(ncpu);
182c62a74e6Sthorpej #endif
183c62a74e6Sthorpej 
1840172694eSnathanw 	for (p = getenv("PTHREAD_DIAGASSERT"); p && *p; p++) {
1850172694eSnathanw 		switch (*p) {
1860172694eSnathanw 		case 'a':
1870172694eSnathanw 			pthread__diagassert |= DIAGASSERT_ABORT;
1880172694eSnathanw 			break;
1890172694eSnathanw 		case 'A':
1900172694eSnathanw 			pthread__diagassert &= ~DIAGASSERT_ABORT;
1910172694eSnathanw 			break;
1920172694eSnathanw 		case 'e':
1930172694eSnathanw 			pthread__diagassert |= DIAGASSERT_STDERR;
1940172694eSnathanw 			break;
1950172694eSnathanw 		case 'E':
1960172694eSnathanw 			pthread__diagassert &= ~DIAGASSERT_STDERR;
1970172694eSnathanw 			break;
1980172694eSnathanw 		case 'l':
1990172694eSnathanw 			pthread__diagassert |= DIAGASSERT_SYSLOG;
2000172694eSnathanw 			break;
2010172694eSnathanw 		case 'L':
2020172694eSnathanw 			pthread__diagassert &= ~DIAGASSERT_SYSLOG;
2030172694eSnathanw 			break;
204df277271Snathanw 		}
2050172694eSnathanw 	}
2060172694eSnathanw 
207df277271Snathanw 
208c62a74e6Sthorpej 	/* Tell libc that we're here and it should role-play accordingly. */
209c62a74e6Sthorpej 	__isthreaded = 1;
210c62a74e6Sthorpej }
211c62a74e6Sthorpej 
2122a4cef11Snathanw static void
2132a4cef11Snathanw pthread__child_callback(void)
2142a4cef11Snathanw {
2152a4cef11Snathanw 	/*
2162a4cef11Snathanw 	 * Clean up data structures that a forked child process might
2172a4cef11Snathanw 	 * trip over. Note that if threads have been created (causing
2182a4cef11Snathanw 	 * this handler to be registered) the standards say that the
2192a4cef11Snathanw 	 * child will trigger undefined behavior if it makes any
2202a4cef11Snathanw 	 * pthread_* calls (or any other calls that aren't
2212a4cef11Snathanw 	 * async-signal-safe), so we don't really have to clean up
2222a4cef11Snathanw 	 * much. Anything that permits some pthread_* calls to work is
2232a4cef11Snathanw 	 * merely being polite.
2242a4cef11Snathanw 	 */
2252a4cef11Snathanw 	pthread__started = 0;
2262a4cef11Snathanw }
227c62a74e6Sthorpej 
2280e675542Schs static void
229c62a74e6Sthorpej pthread__start(void)
230c62a74e6Sthorpej {
2311ac6a89bSad 	pthread_t self;
232c62a74e6Sthorpej 
233c62a74e6Sthorpej 	self = pthread__self(); /* should be the "main()" thread */
234c62a74e6Sthorpej 
235ff14fbf2Snathanw 	/*
236ff14fbf2Snathanw 	 * Per-process timers are cleared by fork(); despite the
237ff14fbf2Snathanw 	 * various restrictions on fork() and threads, it's legal to
238ff14fbf2Snathanw 	 * fork() before creating any threads.
239ff14fbf2Snathanw 	 */
2402a4cef11Snathanw 	pthread_atfork(NULL, NULL, pthread__child_callback);
241c62a74e6Sthorpej 	SDPRINTF(("(pthread__start %p) Started.\n", self));
242c62a74e6Sthorpej }
243c62a74e6Sthorpej 
244c62a74e6Sthorpej 
245c62a74e6Sthorpej /* General-purpose thread data structure sanitization. */
24650fa8db4Sad /* ARGSUSED */
24750fa8db4Sad static void
24850fa8db4Sad pthread__initthread(pthread_t t)
249c62a74e6Sthorpej {
250c62a74e6Sthorpej 
251c62a74e6Sthorpej 	t->pt_magic = PT_MAGIC;
252*c3f8e2eeSad 	t->pt_state = PT_STATE_RUNNING;
253c62a74e6Sthorpej 	t->pt_spinlocks = 0;
254c62a74e6Sthorpej 	t->pt_exitval = NULL;
255c62a74e6Sthorpej 	t->pt_flags = 0;
256c62a74e6Sthorpej 	t->pt_cancel = 0;
257c62a74e6Sthorpej 	t->pt_errno = 0;
258*c3f8e2eeSad 	t->pt_name = NULL;
259*c3f8e2eeSad 	t->pt_willpark = 0;
260*c3f8e2eeSad 	t->pt_unpark = 0;
261*c3f8e2eeSad 	t->pt_sleeponq = 0;
262*c3f8e2eeSad 	t->pt_sleepobj = NULL;
263*c3f8e2eeSad 	t->pt_signalled = 0;
264*c3f8e2eeSad 	t->pt_sleepq = NULL;
2651ac6a89bSad 
26650fa8db4Sad 	pthread_lockinit(&t->pt_lock);
267c62a74e6Sthorpej 	PTQ_INIT(&t->pt_cleanup_stack);
2687bf06aa7Sad 	PTQ_INIT(&t->pt_joiners);
269c62a74e6Sthorpej 	memset(&t->pt_specific, 0, sizeof(int) * PTHREAD_KEYS_MAX);
270c62a74e6Sthorpej }
271c62a74e6Sthorpej 
272c62a74e6Sthorpej 
273c62a74e6Sthorpej int
274c62a74e6Sthorpej pthread_create(pthread_t *thread, const pthread_attr_t *attr,
275c62a74e6Sthorpej 	    void *(*startfunc)(void *), void *arg)
276c62a74e6Sthorpej {
277c62a74e6Sthorpej 	pthread_t self, newthread;
278c62a74e6Sthorpej 	pthread_attr_t nattr;
279b33971b9Sthorpej 	struct pthread_attr_private *p;
2803ca3d0b1Schristos 	char * volatile name;
281de213816Sad 	int ret, flag;
282c62a74e6Sthorpej 
283c62a74e6Sthorpej 	PTHREADD_ADD(PTHREADD_CREATE);
284c62a74e6Sthorpej 
285c62a74e6Sthorpej 	/*
286c62a74e6Sthorpej 	 * It's okay to check this without a lock because there can
287c62a74e6Sthorpej 	 * only be one thread before it becomes true.
288c62a74e6Sthorpej 	 */
289c62a74e6Sthorpej 	if (pthread__started == 0) {
290c62a74e6Sthorpej 		pthread__start();
291c62a74e6Sthorpej 		pthread__started = 1;
292c62a74e6Sthorpej 	}
293c62a74e6Sthorpej 
294c62a74e6Sthorpej 	if (attr == NULL)
295c62a74e6Sthorpej 		nattr = pthread_default_attr;
296e81f9f17Sdrochner 	else if (attr->pta_magic == PT_ATTR_MAGIC)
297c62a74e6Sthorpej 		nattr = *attr;
298c62a74e6Sthorpej 	else
299c62a74e6Sthorpej 		return EINVAL;
300c62a74e6Sthorpej 
301b33971b9Sthorpej 	/* Fetch misc. attributes from the attr structure. */
302508a50acSnathanw 	name = NULL;
303508a50acSnathanw 	if ((p = nattr.pta_private) != NULL)
304508a50acSnathanw 		if (p->ptap_name[0] != '\0')
305b33971b9Sthorpej 			if ((name = strdup(p->ptap_name)) == NULL)
306b33971b9Sthorpej 				return ENOMEM;
307c62a74e6Sthorpej 
308c62a74e6Sthorpej 	self = pthread__self();
309a014cf23Sad 	newthread = NULL;
310c62a74e6Sthorpej 
311a014cf23Sad 	if (!PTQ_EMPTY(&pthread__deadqueue)) {
31250fa8db4Sad 		pthread_spinlock(self, &pthread__queue_lock);
313c62a74e6Sthorpej 		newthread = PTQ_FIRST(&pthread__deadqueue);
3144cdc2ed8Syamt 		if (newthread != NULL) {
31550fa8db4Sad 			PTQ_REMOVE(&pthread__deadqueue, newthread, pt_allq);
31650fa8db4Sad 			pthread_spinunlock(self, &pthread__queue_lock);
317a014cf23Sad 			if ((newthread->pt_flags & PT_FLAG_DETACHED) != 0) {
318a014cf23Sad 				/* Still running? */
31950fa8db4Sad 				if (_lwp_kill(newthread->pt_lid, 0) == 0 ||
32050fa8db4Sad 				    errno != ESRCH) {
321a014cf23Sad 					pthread_spinlock(self,
322a014cf23Sad 					    &pthread__queue_lock);
32350fa8db4Sad 					PTQ_INSERT_TAIL(&pthread__deadqueue,
32450fa8db4Sad 					    newthread, pt_allq);
325a014cf23Sad 					pthread_spinunlock(self,
326a014cf23Sad 					    &pthread__queue_lock);
3274cdc2ed8Syamt 					newthread = NULL;
32850fa8db4Sad 				}
3294cdc2ed8Syamt 			}
330a014cf23Sad 		} else
33150fa8db4Sad 			pthread_spinunlock(self, &pthread__queue_lock);
332a014cf23Sad 	}
333a014cf23Sad 
3344cdc2ed8Syamt 	if (newthread == NULL) {
335c62a74e6Sthorpej 		/* Set up a stack and allocate space for a pthread_st. */
336c62a74e6Sthorpej 		ret = pthread__stackalloc(&newthread);
337b7559f85Schristos 		if (ret != 0) {
338b7559f85Schristos 			if (name)
339b7559f85Schristos 				free(name);
340c62a74e6Sthorpej 			return ret;
341c62a74e6Sthorpej 		}
342b7559f85Schristos 	}
343c62a74e6Sthorpej 
344c62a74e6Sthorpej 	/* 2. Set up state. */
34550fa8db4Sad 	pthread__initthread(newthread);
346c62a74e6Sthorpej 	newthread->pt_flags = nattr.pta_flags;
347c62a74e6Sthorpej 
348b33971b9Sthorpej 	/* 3. Set up misc. attributes. */
349b33971b9Sthorpej 	newthread->pt_name = name;
350b33971b9Sthorpej 
351c62a74e6Sthorpej 	/*
352b33971b9Sthorpej 	 * 4. Set up context.
353c62a74e6Sthorpej 	 *
354c62a74e6Sthorpej 	 * The pt_uc pointer points to a location safely below the
355c62a74e6Sthorpej 	 * stack start; this is arranged by pthread__stackalloc().
356c62a74e6Sthorpej 	 */
357c62a74e6Sthorpej 	_INITCONTEXT_U(newthread->pt_uc);
358877f8985Snathanw #ifdef PTHREAD_MACHINE_HAS_ID_REGISTER
359877f8985Snathanw 	pthread__uc_id(newthread->pt_uc) = newthread;
360877f8985Snathanw #endif
361c62a74e6Sthorpej 	newthread->pt_uc->uc_stack = newthread->pt_stack;
362c62a74e6Sthorpej 	newthread->pt_uc->uc_link = NULL;
363c62a74e6Sthorpej 	makecontext(newthread->pt_uc, pthread__create_tramp, 2,
364c62a74e6Sthorpej 	    startfunc, arg);
365c62a74e6Sthorpej 
366efb1fc06Sad 	/* 5. Add to list of all threads. */
36750fa8db4Sad 	pthread_spinlock(self, &pthread__queue_lock);
368efb1fc06Sad 	PTQ_INSERT_HEAD(&pthread__allqueue, newthread, pt_allq);
36950fa8db4Sad 	pthread_spinunlock(self, &pthread__queue_lock);
370efb1fc06Sad 
371efb1fc06Sad 	/* 5a. Create the new LWP. */
3727630e387Sad 	newthread->pt_sleeponq = 0;
373ded26025Sad 	flag = 0;
374ded26025Sad 	if ((newthread->pt_flags & PT_FLAG_SUSPENDED) != 0)
375ded26025Sad 		flag |= LWP_SUSPENDED;
376ded26025Sad 	if ((newthread->pt_flags & PT_FLAG_DETACHED) != 0)
377ded26025Sad 		flag |= LWP_DETACHED;
3781ac6a89bSad 	ret = _lwp_create(newthread->pt_uc, (u_long)flag, &newthread->pt_lid);
3791ac6a89bSad 	if (ret != 0) {
3801ac6a89bSad 		SDPRINTF(("(pthread_create %p) _lwp_create: %s\n",
3811ac6a89bSad 		    strerror(errno)));
3821ac6a89bSad 		free(name);
38350fa8db4Sad 		pthread_spinlock(self, &pthread__queue_lock);
384efb1fc06Sad 		PTQ_REMOVE(&pthread__allqueue, newthread, pt_allq);
385efb1fc06Sad 		PTQ_INSERT_HEAD(&pthread__deadqueue, newthread, pt_allq);
38650fa8db4Sad 		pthread_spinunlock(self, &pthread__queue_lock);
3871ac6a89bSad 		return ret;
3881ac6a89bSad 	}
3891ac6a89bSad 
39050fa8db4Sad 	/* XXX must die */
39150fa8db4Sad 	newthread->pt_num = newthread->pt_lid;
39250fa8db4Sad 
3931ac6a89bSad 	SDPRINTF(("(pthread_create %p) new thread %p (name %p, lid %d).\n",
3941ac6a89bSad 		  self, newthread, newthread->pt_name,
3951ac6a89bSad 		  (int)newthread->pt_lid));
396c62a74e6Sthorpej 
397c62a74e6Sthorpej 	*thread = newthread;
398c62a74e6Sthorpej 
399c62a74e6Sthorpej 	return 0;
400c62a74e6Sthorpej }
401c62a74e6Sthorpej 
402c62a74e6Sthorpej 
403c62a74e6Sthorpej static void
404c62a74e6Sthorpej pthread__create_tramp(void *(*start)(void *), void *arg)
405c62a74e6Sthorpej {
406c62a74e6Sthorpej 	void *retval;
407c62a74e6Sthorpej 
40850fa8db4Sad 	/*
40950fa8db4Sad 	 * Throw away some stack in a feeble attempt to reduce cache
41050fa8db4Sad 	 * thrash.  May help for SMT processors.  XXX We should not
41150fa8db4Sad 	 * be allocating stacks on fixed 2MB boundaries.  Needs a
41250fa8db4Sad 	 * thread register or decent thread local storage.
41350fa8db4Sad 	 */
41450fa8db4Sad 	(void)alloca(((unsigned)pthread__self()->pt_lid & 7) << 8);
41550fa8db4Sad 
41694a458ceSchs 	retval = (*start)(arg);
417c62a74e6Sthorpej 
418c62a74e6Sthorpej 	pthread_exit(retval);
419c62a74e6Sthorpej 
420143f5a27Schristos 	/*NOTREACHED*/
421143f5a27Schristos 	pthread__abort();
422c62a74e6Sthorpej }
423c62a74e6Sthorpej 
42438b1c6f4Schristos int
42538b1c6f4Schristos pthread_suspend_np(pthread_t thread)
42638b1c6f4Schristos {
427ba70e96aSchs 	pthread_t self;
428ba70e96aSchs 
429ba70e96aSchs 	self = pthread__self();
43038b1c6f4Schristos 	if (self == thread) {
43138b1c6f4Schristos 		return EDEADLK;
43238b1c6f4Schristos 	}
433ba70e96aSchs #ifdef ERRORCHECK
434ba70e96aSchs 	if (pthread__find(self, thread) != 0)
435ba70e96aSchs 		return ESRCH;
436ba70e96aSchs #endif
4371ac6a89bSad 	SDPRINTF(("(pthread_suspend_np %p) Suspend thread %p.\n",
4381ac6a89bSad 		     self, thread));
4391ac6a89bSad 	return _lwp_suspend(thread->pt_lid);
44038b1c6f4Schristos }
44138b1c6f4Schristos 
44238b1c6f4Schristos int
44338b1c6f4Schristos pthread_resume_np(pthread_t thread)
44438b1c6f4Schristos {
445ba70e96aSchs 	pthread_t self;
44638b1c6f4Schristos 
447ba70e96aSchs 	self = pthread__self();
448ba70e96aSchs #ifdef ERRORCHECK
449ba70e96aSchs 	if (pthread__find(self, thread) != 0)
450ba70e96aSchs 		return ESRCH;
451ba70e96aSchs #endif
4521ac6a89bSad 	SDPRINTF(("(pthread_resume_np %p) Resume thread %p.\n",
4531ac6a89bSad 		     self, thread));
4541ac6a89bSad 	return _lwp_continue(thread->pt_lid);
45538b1c6f4Schristos }
45638b1c6f4Schristos 
457c62a74e6Sthorpej void
458c62a74e6Sthorpej pthread_exit(void *retval)
459c62a74e6Sthorpej {
46096b5a26dSnathanw 	pthread_t self;
461c62a74e6Sthorpej 	struct pt_clean_t *cleanup;
462b33971b9Sthorpej 	char *name;
463c62a74e6Sthorpej 
464c62a74e6Sthorpej 	self = pthread__self();
465ba70e96aSchs 	SDPRINTF(("(pthread_exit %p) status %p, flags %x, cancel %d\n",
466ba70e96aSchs 		  self, retval, self->pt_flags, self->pt_cancel));
467c62a74e6Sthorpej 
468c62a74e6Sthorpej 	/* Disable cancellability. */
46950fa8db4Sad 	pthread_spinlock(self, &self->pt_lock);
470c62a74e6Sthorpej 	self->pt_flags |= PT_FLAG_CS_DISABLED;
47166fcc1ceSnathanw 	self->pt_cancel = 0;
47250fa8db4Sad 	pthread_spinunlock(self, &self->pt_lock);
473c62a74e6Sthorpej 
474c62a74e6Sthorpej 	/* Call any cancellation cleanup handlers */
475c62a74e6Sthorpej 	while (!PTQ_EMPTY(&self->pt_cleanup_stack)) {
476c62a74e6Sthorpej 		cleanup = PTQ_FIRST(&self->pt_cleanup_stack);
477c62a74e6Sthorpej 		PTQ_REMOVE(&self->pt_cleanup_stack, cleanup, ptc_next);
478c62a74e6Sthorpej 		(*cleanup->ptc_cleanup)(cleanup->ptc_arg);
479c62a74e6Sthorpej 	}
480c62a74e6Sthorpej 
481c62a74e6Sthorpej 	/* Perform cleanup of thread-specific data */
482c62a74e6Sthorpej 	pthread__destroy_tsd(self);
483c62a74e6Sthorpej 
484c62a74e6Sthorpej 	self->pt_exitval = retval;
485c62a74e6Sthorpej 
48650fa8db4Sad 	pthread_spinlock(self, &self->pt_lock);
4876b2b9c62Syamt 	if (self->pt_flags & PT_FLAG_DETACHED) {
4886b2b9c62Syamt 		self->pt_state = PT_STATE_DEAD;
489b33971b9Sthorpej 		name = self->pt_name;
490b33971b9Sthorpej 		self->pt_name = NULL;
49150fa8db4Sad 		pthread_spinlock(self, &pthread__queue_lock);
49250fa8db4Sad 		PTQ_REMOVE(&pthread__allqueue, self, pt_allq);
49350fa8db4Sad 		PTQ_INSERT_TAIL(&pthread__deadqueue, self, pt_allq);
49450fa8db4Sad 		pthread_spinunlock(self, &pthread__queue_lock);
49550fa8db4Sad 		pthread_spinunlock(self, &self->pt_lock);
496b33971b9Sthorpej 		if (name != NULL)
497b33971b9Sthorpej 			free(name);
4981ac6a89bSad 		_lwp_exit();
499c62a74e6Sthorpej 	} else {
5006b2b9c62Syamt 		self->pt_state = PT_STATE_ZOMBIE;
50150fa8db4Sad 		pthread_spinunlock(self, &self->pt_lock);
502b33971b9Sthorpej 		/* Note: name will be freed by the joiner. */
5031ac6a89bSad 		_lwp_exit();
504c62a74e6Sthorpej 	}
505c62a74e6Sthorpej 
506143f5a27Schristos 	/*NOTREACHED*/
507143f5a27Schristos 	pthread__abort();
508c62a74e6Sthorpej 	exit(1);
509c62a74e6Sthorpej }
510c62a74e6Sthorpej 
511c62a74e6Sthorpej 
512c62a74e6Sthorpej int
513c62a74e6Sthorpej pthread_join(pthread_t thread, void **valptr)
514c62a74e6Sthorpej {
515c62a74e6Sthorpej 	pthread_t self;
516b33971b9Sthorpej 	char *name;
5171ac6a89bSad 	int num, retval;
518c62a74e6Sthorpej 
519c62a74e6Sthorpej 	self = pthread__self();
520c62a74e6Sthorpej 	SDPRINTF(("(pthread_join %p) Joining %p.\n", self, thread));
521c62a74e6Sthorpej 
522c62a74e6Sthorpej 	if (pthread__find(self, thread) != 0)
523c62a74e6Sthorpej 		return ESRCH;
524c62a74e6Sthorpej 
525c62a74e6Sthorpej 	if (thread->pt_magic != PT_MAGIC)
526c62a74e6Sthorpej 		return EINVAL;
527c62a74e6Sthorpej 
528c62a74e6Sthorpej 	if (thread == self)
529c62a74e6Sthorpej 		return EDEADLK;
530c62a74e6Sthorpej 
5311ac6a89bSad 	retval = 0;
5321ac6a89bSad 	name = NULL;
5331ac6a89bSad  again:
53450fa8db4Sad  	pthread_spinlock(self, &thread->pt_lock);
5351ac6a89bSad 	switch (thread->pt_state) {
5361ac6a89bSad 	case PT_STATE_RUNNING:
53750fa8db4Sad 		pthread_spinunlock(self, &thread->pt_lock);
538ded26025Sad 
539ded26025Sad 		/*
540ded26025Sad 		 * IEEE Std 1003.1, 2004 Edition:
541ded26025Sad 		 *
542ded26025Sad 		 * "The pthread_join() function shall not
543ded26025Sad 		 * return an error code of [EINTR]."
544ded26025Sad 		 */
545ded26025Sad 		if (_lwp_wait(thread->pt_lid, &num) != 0 && errno != EINTR)
546ded26025Sad 			return errno;
5471ac6a89bSad 		goto again;
5481ac6a89bSad 	case PT_STATE_ZOMBIE:
5491ac6a89bSad 		if (valptr != NULL)
550ded26025Sad 			*valptr = thread->pt_exitval;
5511ac6a89bSad 		if (retval == 0) {
5521ac6a89bSad 			name = thread->pt_name;
5531ac6a89bSad 			thread->pt_name = NULL;
5541ac6a89bSad 		}
5551ac6a89bSad 		thread->pt_state = PT_STATE_DEAD;
55650fa8db4Sad 		pthread_spinlock(self, &pthread__queue_lock);
55750fa8db4Sad 		PTQ_REMOVE(&pthread__allqueue, thread, pt_allq);
55850fa8db4Sad 		PTQ_INSERT_HEAD(&pthread__deadqueue, thread, pt_allq);
55950fa8db4Sad 		pthread_spinunlock(self, &pthread__queue_lock);
56050fa8db4Sad 		pthread_spinunlock(self, &thread->pt_lock);
56150fa8db4Sad 		SDPRINTF(("(pthread_join %p) Joined %p.\n", self, thread));
56250fa8db4Sad 		if (name != NULL)
56350fa8db4Sad 			free(name);
564b8daad98Sad 		(void)_lwp_detach(thread->pt_lid);
56550fa8db4Sad 		return retval;
5661ac6a89bSad 	default:
56750fa8db4Sad 		pthread_spinunlock(self, &thread->pt_lock);
5681ac6a89bSad 		return EINVAL;
5691ac6a89bSad 	}
5701ac6a89bSad 
571c62a74e6Sthorpej }
572c62a74e6Sthorpej 
573c62a74e6Sthorpej 
574c62a74e6Sthorpej int
575c62a74e6Sthorpej pthread_equal(pthread_t t1, pthread_t t2)
576c62a74e6Sthorpej {
577c62a74e6Sthorpej 
578c62a74e6Sthorpej 	/* Nothing special here. */
579c62a74e6Sthorpej 	return (t1 == t2);
580c62a74e6Sthorpej }
581c62a74e6Sthorpej 
582c62a74e6Sthorpej 
583c62a74e6Sthorpej int
584c62a74e6Sthorpej pthread_detach(pthread_t thread)
585c62a74e6Sthorpej {
58696b5a26dSnathanw 	pthread_t self;
587c62a74e6Sthorpej 
588c62a74e6Sthorpej 	self = pthread__self();
589c62a74e6Sthorpej 
590c62a74e6Sthorpej 	if (pthread__find(self, thread) != 0)
591c62a74e6Sthorpej 		return ESRCH;
592c62a74e6Sthorpej 
593c62a74e6Sthorpej 	if (thread->pt_magic != PT_MAGIC)
594c62a74e6Sthorpej 		return EINVAL;
595c62a74e6Sthorpej 
59650fa8db4Sad 	pthread_spinlock(self, &self->pt_lock);
5971296e850Sad 	thread->pt_flags |= PT_FLAG_DETACHED;
59850fa8db4Sad 	pthread_spinunlock(self, &self->pt_lock);
599de213816Sad 
6001ac6a89bSad 	return _lwp_detach(thread->pt_lid);
601c62a74e6Sthorpej }
602c62a74e6Sthorpej 
603c62a74e6Sthorpej 
604c62a74e6Sthorpej int
605b33971b9Sthorpej pthread_getname_np(pthread_t thread, char *name, size_t len)
606c62a74e6Sthorpej {
607b33971b9Sthorpej 	pthread_t self;
608c62a74e6Sthorpej 
609b33971b9Sthorpej 	self = pthread__self();
610b33971b9Sthorpej 
611b33971b9Sthorpej 	if (pthread__find(self, thread) != 0)
612b33971b9Sthorpej 		return ESRCH;
613b33971b9Sthorpej 
614b33971b9Sthorpej 	if (thread->pt_magic != PT_MAGIC)
615b33971b9Sthorpej 		return EINVAL;
616b33971b9Sthorpej 
61750fa8db4Sad 	pthread_spinlock(self, &thread->pt_lock);
618b33971b9Sthorpej 	if (thread->pt_name == NULL)
619b33971b9Sthorpej 		name[0] = '\0';
620b33971b9Sthorpej 	else
621b33971b9Sthorpej 		strlcpy(name, thread->pt_name, len);
62250fa8db4Sad 	pthread_spinunlock(self, &thread->pt_lock);
623c62a74e6Sthorpej 
624c62a74e6Sthorpej 	return 0;
625c62a74e6Sthorpej }
626c62a74e6Sthorpej 
627c62a74e6Sthorpej 
628c62a74e6Sthorpej int
629b33971b9Sthorpej pthread_setname_np(pthread_t thread, const char *name, void *arg)
630b33971b9Sthorpej {
631ba70e96aSchs 	pthread_t self;
632b33971b9Sthorpej 	char *oldname, *cp, newname[PTHREAD_MAX_NAMELEN_NP];
633b33971b9Sthorpej 	int namelen;
634b33971b9Sthorpej 
635ba70e96aSchs 	self = pthread__self();
636b33971b9Sthorpej 	if (pthread__find(self, thread) != 0)
637b33971b9Sthorpej 		return ESRCH;
638b33971b9Sthorpej 
639b33971b9Sthorpej 	if (thread->pt_magic != PT_MAGIC)
640b33971b9Sthorpej 		return EINVAL;
641b33971b9Sthorpej 
642b33971b9Sthorpej 	namelen = snprintf(newname, sizeof(newname), name, arg);
643b33971b9Sthorpej 	if (namelen >= PTHREAD_MAX_NAMELEN_NP)
644b33971b9Sthorpej 		return EINVAL;
645b33971b9Sthorpej 
646b33971b9Sthorpej 	cp = strdup(newname);
647b33971b9Sthorpej 	if (cp == NULL)
648b33971b9Sthorpej 		return ENOMEM;
649b33971b9Sthorpej 
65050fa8db4Sad 	pthread_spinlock(self, &thread->pt_lock);
651b33971b9Sthorpej 	oldname = thread->pt_name;
652b33971b9Sthorpej 	thread->pt_name = cp;
65350fa8db4Sad 	pthread_spinunlock(self, &thread->pt_lock);
654b33971b9Sthorpej 
655b33971b9Sthorpej 	if (oldname != NULL)
656b33971b9Sthorpej 		free(oldname);
657b33971b9Sthorpej 
658b33971b9Sthorpej 	return 0;
659b33971b9Sthorpej }
660b33971b9Sthorpej 
661b33971b9Sthorpej 
662b33971b9Sthorpej 
663c62a74e6Sthorpej /*
664c62a74e6Sthorpej  * XXX There should be a way for applications to use the efficent
665c62a74e6Sthorpej  *  inline version, but there are opacity/namespace issues.
666c62a74e6Sthorpej  */
667c62a74e6Sthorpej pthread_t
668c62a74e6Sthorpej pthread_self(void)
669c62a74e6Sthorpej {
670c62a74e6Sthorpej 
671c62a74e6Sthorpej 	return pthread__self();
672c62a74e6Sthorpej }
673c62a74e6Sthorpej 
674c62a74e6Sthorpej 
675c62a74e6Sthorpej int
676c62a74e6Sthorpej pthread_cancel(pthread_t thread)
677c62a74e6Sthorpej {
678c62a74e6Sthorpej 	pthread_t self;
679c62a74e6Sthorpej 
680ba70e96aSchs 	self = pthread__self();
681ba70e96aSchs 	if (pthread__find(self, thread) != 0)
682ba70e96aSchs 		return ESRCH;
68350fa8db4Sad 	pthread_spinlock(self, &thread->pt_lock);
6841ac6a89bSad 	thread->pt_flags |= PT_FLAG_CS_PENDING;
6851ac6a89bSad 	if ((thread->pt_flags & PT_FLAG_CS_DISABLED) == 0) {
6861ac6a89bSad 		thread->pt_cancel = 1;
68750fa8db4Sad 		pthread_spinunlock(self, &thread->pt_lock);
6881ac6a89bSad 		_lwp_wakeup(thread->pt_lid);
6891ac6a89bSad 	} else
69050fa8db4Sad 		pthread_spinunlock(self, &thread->pt_lock);
691c62a74e6Sthorpej 
692c62a74e6Sthorpej 	return 0;
693c62a74e6Sthorpej }
694c62a74e6Sthorpej 
695c62a74e6Sthorpej 
696c62a74e6Sthorpej int
697c62a74e6Sthorpej pthread_setcancelstate(int state, int *oldstate)
698c62a74e6Sthorpej {
699c62a74e6Sthorpej 	pthread_t self;
7000878df5dSnathanw 	int retval;
701c62a74e6Sthorpej 
702c62a74e6Sthorpej 	self = pthread__self();
7030878df5dSnathanw 	retval = 0;
704c62a74e6Sthorpej 
70550fa8db4Sad 	pthread_spinlock(self, &self->pt_lock);
70650fa8db4Sad 
707c62a74e6Sthorpej 	if (oldstate != NULL) {
7080878df5dSnathanw 		if (self->pt_flags & PT_FLAG_CS_DISABLED)
709c62a74e6Sthorpej 			*oldstate = PTHREAD_CANCEL_DISABLE;
710c62a74e6Sthorpej 		else
711c62a74e6Sthorpej 			*oldstate = PTHREAD_CANCEL_ENABLE;
712c62a74e6Sthorpej 	}
713c62a74e6Sthorpej 
7140878df5dSnathanw 	if (state == PTHREAD_CANCEL_DISABLE) {
7150878df5dSnathanw 		self->pt_flags |= PT_FLAG_CS_DISABLED;
7160878df5dSnathanw 		if (self->pt_cancel) {
7170878df5dSnathanw 			self->pt_flags |= PT_FLAG_CS_PENDING;
7180878df5dSnathanw 			self->pt_cancel = 0;
7190878df5dSnathanw 		}
7200878df5dSnathanw 	} else if (state == PTHREAD_CANCEL_ENABLE) {
7210878df5dSnathanw 		self->pt_flags &= ~PT_FLAG_CS_DISABLED;
722c62a74e6Sthorpej 		/*
723c62a74e6Sthorpej 		 * If a cancellation was requested while cancellation
724c62a74e6Sthorpej 		 * was disabled, note that fact for future
725c62a74e6Sthorpej 		 * cancellation tests.
726c62a74e6Sthorpej 		 */
7270878df5dSnathanw 		if (self->pt_flags & PT_FLAG_CS_PENDING) {
728c62a74e6Sthorpej 			self->pt_cancel = 1;
729c62a74e6Sthorpej 			/* This is not a deferred cancellation point. */
7300878df5dSnathanw 			if (self->pt_flags & PT_FLAG_CS_ASYNC) {
73150fa8db4Sad 				pthread_spinunlock(self, &self->pt_lock);
732c62a74e6Sthorpej 				pthread_exit(PTHREAD_CANCELED);
733c62a74e6Sthorpej 			}
7340878df5dSnathanw 		}
735c62a74e6Sthorpej 	} else
7360878df5dSnathanw 		retval = EINVAL;
737c62a74e6Sthorpej 
73850fa8db4Sad 	pthread_spinunlock(self, &self->pt_lock);
73950fa8db4Sad 
7400878df5dSnathanw 	return retval;
741c62a74e6Sthorpej }
742c62a74e6Sthorpej 
743c62a74e6Sthorpej 
744c62a74e6Sthorpej int
745c62a74e6Sthorpej pthread_setcanceltype(int type, int *oldtype)
746c62a74e6Sthorpej {
747c62a74e6Sthorpej 	pthread_t self;
7480878df5dSnathanw 	int retval;
749c62a74e6Sthorpej 
750c62a74e6Sthorpej 	self = pthread__self();
7510878df5dSnathanw 	retval = 0;
7520878df5dSnathanw 
75350fa8db4Sad 	pthread_spinlock(self, &self->pt_lock);
754c62a74e6Sthorpej 
755c62a74e6Sthorpej 	if (oldtype != NULL) {
7560878df5dSnathanw 		if (self->pt_flags & PT_FLAG_CS_ASYNC)
757c62a74e6Sthorpej 			*oldtype = PTHREAD_CANCEL_ASYNCHRONOUS;
758c62a74e6Sthorpej 		else
759c62a74e6Sthorpej 			*oldtype = PTHREAD_CANCEL_DEFERRED;
760c62a74e6Sthorpej 	}
761c62a74e6Sthorpej 
762c62a74e6Sthorpej 	if (type == PTHREAD_CANCEL_ASYNCHRONOUS) {
7630878df5dSnathanw 		self->pt_flags |= PT_FLAG_CS_ASYNC;
7640878df5dSnathanw 		if (self->pt_cancel) {
76550fa8db4Sad 			pthread_spinunlock(self, &self->pt_lock);
766c62a74e6Sthorpej 			pthread_exit(PTHREAD_CANCELED);
7670878df5dSnathanw 		}
768c62a74e6Sthorpej 	} else if (type == PTHREAD_CANCEL_DEFERRED)
7690878df5dSnathanw 		self->pt_flags &= ~PT_FLAG_CS_ASYNC;
770c62a74e6Sthorpej 	else
7710878df5dSnathanw 		retval = EINVAL;
772c62a74e6Sthorpej 
77350fa8db4Sad 	pthread_spinunlock(self, &self->pt_lock);
77450fa8db4Sad 
7750878df5dSnathanw 	return retval;
776c62a74e6Sthorpej }
777c62a74e6Sthorpej 
778c62a74e6Sthorpej 
779c62a74e6Sthorpej void
780c62a74e6Sthorpej pthread_testcancel()
781c62a74e6Sthorpej {
782c62a74e6Sthorpej 	pthread_t self;
783c62a74e6Sthorpej 
784c62a74e6Sthorpej 	self = pthread__self();
785c62a74e6Sthorpej 	if (self->pt_cancel)
786c62a74e6Sthorpej 		pthread_exit(PTHREAD_CANCELED);
787c62a74e6Sthorpej }
788c62a74e6Sthorpej 
789c62a74e6Sthorpej 
790c62a74e6Sthorpej /*
791c62a74e6Sthorpej  * POSIX requires that certain functions return an error rather than
792c62a74e6Sthorpej  * invoking undefined behavior even when handed completely bogus
793c62a74e6Sthorpej  * pthread_t values, e.g. stack garbage or (pthread_t)666. This
794c62a74e6Sthorpej  * utility routine searches the list of threads for the pthread_t
795c62a74e6Sthorpej  * value without dereferencing it.
796c62a74e6Sthorpej  */
797c62a74e6Sthorpej int
798c62a74e6Sthorpej pthread__find(pthread_t self, pthread_t id)
799c62a74e6Sthorpej {
800c62a74e6Sthorpej 	pthread_t target;
801c62a74e6Sthorpej 
80250fa8db4Sad 	pthread_spinlock(self, &pthread__queue_lock);
803c62a74e6Sthorpej 	PTQ_FOREACH(target, &pthread__allqueue, pt_allq)
804c62a74e6Sthorpej 	    if (target == id)
805c62a74e6Sthorpej 		    break;
80650fa8db4Sad 	pthread_spinunlock(self, &pthread__queue_lock);
807c62a74e6Sthorpej 
808c62a74e6Sthorpej 	if (target == NULL)
809c62a74e6Sthorpej 		return ESRCH;
810c62a74e6Sthorpej 
811c62a74e6Sthorpej 	return 0;
812c62a74e6Sthorpej }
813c62a74e6Sthorpej 
814c62a74e6Sthorpej 
815c62a74e6Sthorpej void
816c62a74e6Sthorpej pthread__testcancel(pthread_t self)
817c62a74e6Sthorpej {
818c62a74e6Sthorpej 
819c62a74e6Sthorpej 	if (self->pt_cancel)
820c62a74e6Sthorpej 		pthread_exit(PTHREAD_CANCELED);
821c62a74e6Sthorpej }
822c62a74e6Sthorpej 
823c62a74e6Sthorpej 
824c62a74e6Sthorpej void
825c62a74e6Sthorpej pthread__cleanup_push(void (*cleanup)(void *), void *arg, void *store)
826c62a74e6Sthorpej {
827c62a74e6Sthorpej 	pthread_t self;
828c62a74e6Sthorpej 	struct pt_clean_t *entry;
829c62a74e6Sthorpej 
830c62a74e6Sthorpej 	self = pthread__self();
831c62a74e6Sthorpej 	entry = store;
832c62a74e6Sthorpej 	entry->ptc_cleanup = cleanup;
833c62a74e6Sthorpej 	entry->ptc_arg = arg;
834c62a74e6Sthorpej 	PTQ_INSERT_HEAD(&self->pt_cleanup_stack, entry, ptc_next);
835c62a74e6Sthorpej }
836c62a74e6Sthorpej 
837c62a74e6Sthorpej 
838c62a74e6Sthorpej void
839c62a74e6Sthorpej pthread__cleanup_pop(int ex, void *store)
840c62a74e6Sthorpej {
841c62a74e6Sthorpej 	pthread_t self;
842c62a74e6Sthorpej 	struct pt_clean_t *entry;
843c62a74e6Sthorpej 
844c62a74e6Sthorpej 	self = pthread__self();
845c62a74e6Sthorpej 	entry = store;
846c62a74e6Sthorpej 
847c62a74e6Sthorpej 	PTQ_REMOVE(&self->pt_cleanup_stack, entry, ptc_next);
848c62a74e6Sthorpej 	if (ex)
849c62a74e6Sthorpej 		(*entry->ptc_cleanup)(entry->ptc_arg);
850c62a74e6Sthorpej }
851c62a74e6Sthorpej 
852c62a74e6Sthorpej 
853c62a74e6Sthorpej int *
854c62a74e6Sthorpej pthread__errno(void)
855c62a74e6Sthorpej {
856c62a74e6Sthorpej 	pthread_t self;
857c62a74e6Sthorpej 
858c62a74e6Sthorpej 	self = pthread__self();
859c62a74e6Sthorpej 
860c62a74e6Sthorpej 	return &(self->pt_errno);
861c62a74e6Sthorpej }
8628bcff70bSnathanw 
8630c967901Snathanw ssize_t	_sys_write(int, const void *, size_t);
8640c967901Snathanw 
8658bcff70bSnathanw void
8660e6c93b9Sdrochner pthread__assertfunc(const char *file, int line, const char *function,
8670e6c93b9Sdrochner 		    const char *expr)
8688bcff70bSnathanw {
8698bcff70bSnathanw 	char buf[1024];
8708bcff70bSnathanw 	int len;
8718bcff70bSnathanw 
87275a94788Smycroft 	SDPRINTF(("(af)\n"));
87375a94788Smycroft 
8748bcff70bSnathanw 	/*
8758bcff70bSnathanw 	 * snprintf should not acquire any locks, or we could
8768bcff70bSnathanw 	 * end up deadlocked if the assert caller held locks.
8778bcff70bSnathanw 	 */
8788bcff70bSnathanw 	len = snprintf(buf, 1024,
8798bcff70bSnathanw 	    "assertion \"%s\" failed: file \"%s\", line %d%s%s%s\n",
8808bcff70bSnathanw 	    expr, file, line,
8818bcff70bSnathanw 	    function ? ", function \"" : "",
8828bcff70bSnathanw 	    function ? function : "",
8838bcff70bSnathanw 	    function ? "\"" : "");
8848bcff70bSnathanw 
8850c967901Snathanw 	_sys_write(STDERR_FILENO, buf, (size_t)len);
8868bcff70bSnathanw 	(void)kill(getpid(), SIGABRT);
8878bcff70bSnathanw 
8888bcff70bSnathanw 	_exit(1);
8898bcff70bSnathanw }
890df277271Snathanw 
891df277271Snathanw 
892df277271Snathanw void
8930e6c93b9Sdrochner pthread__errorfunc(const char *file, int line, const char *function,
8940e6c93b9Sdrochner 		   const char *msg)
895df277271Snathanw {
896df277271Snathanw 	char buf[1024];
8970172694eSnathanw 	size_t len;
898df277271Snathanw 
8990172694eSnathanw 	if (pthread__diagassert == 0)
900df277271Snathanw 		return;
901df277271Snathanw 
902df277271Snathanw 	/*
903df277271Snathanw 	 * snprintf should not acquire any locks, or we could
904df277271Snathanw 	 * end up deadlocked if the assert caller held locks.
905df277271Snathanw 	 */
906df277271Snathanw 	len = snprintf(buf, 1024,
9070172694eSnathanw 	    "%s: Error detected by libpthread: %s.\n"
9080172694eSnathanw 	    "Detected by file \"%s\", line %d%s%s%s.\n"
9090172694eSnathanw 	    "See pthread(3) for information.\n",
9100172694eSnathanw 	    getprogname(), msg, file, line,
911df277271Snathanw 	    function ? ", function \"" : "",
912df277271Snathanw 	    function ? function : "",
9130172694eSnathanw 	    function ? "\"" : "");
914df277271Snathanw 
9150172694eSnathanw 	if (pthread__diagassert & DIAGASSERT_STDERR)
9160c967901Snathanw 		_sys_write(STDERR_FILENO, buf, len);
9170172694eSnathanw 
9180172694eSnathanw 	if (pthread__diagassert & DIAGASSERT_SYSLOG)
9190172694eSnathanw 		syslog(LOG_DEBUG | LOG_USER, "%s", buf);
9200172694eSnathanw 
9210172694eSnathanw 	if (pthread__diagassert & DIAGASSERT_ABORT) {
922df277271Snathanw 		(void)kill(getpid(), SIGABRT);
923df277271Snathanw 		_exit(1);
924df277271Snathanw 	}
925df277271Snathanw }
9261ac6a89bSad 
927fe9718acSad /*
928ded26025Sad  * Thread park/unpark operations.  The kernel operations are
929ded26025Sad  * modelled after a brief description from "Multithreading in
930ded26025Sad  * the Solaris Operating Environment":
931fe9718acSad  *
932fe9718acSad  * http://www.sun.com/software/whitepapers/solaris9/multithread.pdf
933fe9718acSad  */
934fe9718acSad 
9351ac6a89bSad #define	OOPS(msg)			\
936858097f9Schristos     pthread__errorfunc(__FILE__, __LINE__, __func__, msg)
9371ac6a89bSad 
9381ac6a89bSad int
9391ac6a89bSad pthread__park(pthread_t self, pthread_spin_t *lock,
94050fa8db4Sad 	      pthread_queue_t *queue, const struct timespec *abstime,
94150fa8db4Sad 	      int cancelpt, const void *hint)
9421ac6a89bSad {
943*c3f8e2eeSad 	int rv, error;
9441ac6a89bSad 
945792cc0e1Sad 	SDPRINTF(("(pthread__park %p) queue %p enter\n", self, queue));
9461ac6a89bSad 
947*c3f8e2eeSad 	/* Clear the willpark flag, since we're about to block. */
948*c3f8e2eeSad 	self->pt_willpark = 0;
949*c3f8e2eeSad 
950*c3f8e2eeSad 	/*
951*c3f8e2eeSad 	 * Kernels before 4.99.27 can't park and unpark in one step,
952*c3f8e2eeSad 	 * so take care of it now if on an old kernel.
953*c3f8e2eeSad 	 *
954*c3f8e2eeSad 	 * XXX Remove this check before NetBSD 5.0 is released.
955*c3f8e2eeSad 	 * It's for compatibility with recent -current only.
956*c3f8e2eeSad 	 */
957*c3f8e2eeSad 	if (__predict_false(pthread__osrev < 499002700) &&
958*c3f8e2eeSad 	    self->pt_unpark != 0) {
959*c3f8e2eeSad 		_lwp_unpark(self->pt_unpark, self->pt_unparkhint);
960*c3f8e2eeSad 		self->pt_unpark = 0;
961*c3f8e2eeSad 	}
962*c3f8e2eeSad 
963ded26025Sad 	/*
964ded26025Sad 	 * Wait until we are awoken by a pending unpark operation,
965ded26025Sad 	 * a signal, an unpark posted after we have gone asleep,
966ded26025Sad 	 * or an expired timeout.
96750fa8db4Sad 	 *
96850fa8db4Sad 	 * It is fine to test the value of both pt_sleepobj and
96950fa8db4Sad 	 * pt_sleeponq without holding any locks, because:
97050fa8db4Sad 	 *
97150fa8db4Sad 	 * o Only the blocking thread (this thread) ever sets them
97250fa8db4Sad 	 *   to a non-NULL value.
97350fa8db4Sad 	 *
97450fa8db4Sad 	 * o Other threads may set them NULL, but if they do so they
97550fa8db4Sad 	 *   must also make this thread return from _lwp_park.
97650fa8db4Sad 	 *
97750fa8db4Sad 	 * o _lwp_park, _lwp_unpark and _lwp_unpark_all are system
97850fa8db4Sad 	 *   calls and all make use of spinlocks in the kernel.  So
97950fa8db4Sad 	 *   these system calls act as full memory barriers, and will
98050fa8db4Sad 	 *   ensure that the calling CPU's store buffers are drained.
98150fa8db4Sad 	 *   In combination with the spinlock release before unpark,
98250fa8db4Sad 	 *   this means that modification of pt_sleepobj/onq by another
98350fa8db4Sad 	 *   thread will become globally visible before that thread
98450fa8db4Sad 	 *   schedules an unpark operation on this thread.
985*c3f8e2eeSad 	 *
986*c3f8e2eeSad 	 * Note: the test in the while() statement dodges the park op if
987*c3f8e2eeSad 	 * we have already been awoken, unless there is another thread to
988*c3f8e2eeSad 	 * awaken.  This saves a syscall - if we were already awakened,
989*c3f8e2eeSad 	 * the next call to _lwp_park() would need to return early in order
990*c3f8e2eeSad 	 * to eat the previous wakeup.
991ded26025Sad 	 */
992ded26025Sad 	rv = 0;
993*c3f8e2eeSad 	while ((self->pt_sleepobj != NULL || self->pt_unpark != 0) && rv == 0) {
994*c3f8e2eeSad 		/*
995*c3f8e2eeSad 		 * If we deferred unparking a thread, arrange to
996*c3f8e2eeSad 		 * have _lwp_park() restart it before blocking.
997*c3f8e2eeSad 		 */
998*c3f8e2eeSad 		error = _lwp_park(abstime, self->pt_unpark, hint,
999*c3f8e2eeSad 		    self->pt_unparkhint);
1000*c3f8e2eeSad 		self->pt_unpark = 0;
1001*c3f8e2eeSad 		if (error != 0) {
1002ded26025Sad 			switch (rv = errno) {
10031ac6a89bSad 			case EINTR:
10041ac6a89bSad 			case EALREADY:
1005ded26025Sad 				rv = 0;
1006ded26025Sad 				break;
1007ded26025Sad 			case ETIMEDOUT:
10081ac6a89bSad 				break;
10091ac6a89bSad 			default:
10101ac6a89bSad 				OOPS("_lwp_park failed");
10111ac6a89bSad 				SDPRINTF(("(pthread__park %p) syscall rv=%d\n",
10121ac6a89bSad 				    self, rv));
10131ac6a89bSad 				break;
10141ac6a89bSad 			}
1015ded26025Sad 		}
10160c61b6a6Sad 		/* Check for cancellation. */
10170c61b6a6Sad 		if (cancelpt && self->pt_cancel) {
10180c61b6a6Sad 			/*
10190c61b6a6Sad 			 * Ensure visibility of the correct value.
10200c61b6a6Sad 			 * _lwp_park/_lwp_wakeup also provide a
10210c61b6a6Sad 			 * barrier.
10220c61b6a6Sad 			 */
102350fa8db4Sad 			pthread_spinlock(self, &self->pt_lock);
10240c61b6a6Sad 			if (self->pt_cancel)
10250c61b6a6Sad 				rv = EINTR;
102650fa8db4Sad 			pthread_spinunlock(self, &self->pt_lock);
10270c61b6a6Sad 		}
102850fa8db4Sad 	}
10291ac6a89bSad 
1030ded26025Sad 	/*
1031ded26025Sad 	 * If we have been awoken early but are still on the queue,
103250fa8db4Sad 	 * then remove ourself.  Again, it's safe to do the test
103350fa8db4Sad 	 * without holding any locks.
1034ded26025Sad 	 */
1035792cc0e1Sad 	if (self->pt_sleeponq) {
103650fa8db4Sad 		pthread_spinlock(self, lock);
103750fa8db4Sad 		if (self->pt_sleeponq) {
10381ac6a89bSad 			PTQ_REMOVE(queue, self, pt_sleep);
10391ac6a89bSad 			self->pt_sleepobj = NULL;
1040ded26025Sad 			self->pt_sleeponq = 0;
1041792cc0e1Sad 		}
104250fa8db4Sad 		pthread_spinunlock(self, lock);
104350fa8db4Sad 	}
10441ac6a89bSad 
1045792cc0e1Sad 	SDPRINTF(("(pthread__park %p) queue %p exit\n", self, queue));
10461ac6a89bSad 
10471ac6a89bSad 	return rv;
10481ac6a89bSad }
10491ac6a89bSad 
10501ac6a89bSad void
1051792cc0e1Sad pthread__unpark(pthread_t self, pthread_spin_t *lock,
105250fa8db4Sad 		pthread_queue_t *queue, pthread_t target)
10531ac6a89bSad {
10541ac6a89bSad 	int rv;
10551ac6a89bSad 
10560c61b6a6Sad 	if (target == NULL) {
10570c61b6a6Sad 		pthread_spinunlock(self, lock);
10580c61b6a6Sad 		return;
10590c61b6a6Sad 	}
10600c61b6a6Sad 
1061792cc0e1Sad 	SDPRINTF(("(pthread__unpark %p) queue %p target %p\n",
1062792cc0e1Sad 	    self, queue, target));
10631ac6a89bSad 
1064ded26025Sad 	/*
1065ded26025Sad 	 * Easy: the thread has already been removed from
1066ded26025Sad 	 * the queue, so just awaken it.
1067ded26025Sad 	 */
10681ac6a89bSad 	target->pt_sleepobj = NULL;
1069ded26025Sad 	target->pt_sleeponq = 0;
107050fa8db4Sad 
107150fa8db4Sad 	/*
107250fa8db4Sad 	 * Releasing the spinlock serves as a store barrier,
107350fa8db4Sad 	 * which ensures that all our modifications are visible
107450fa8db4Sad 	 * to the thread in pthread__park() before the unpark
107550fa8db4Sad 	 * operation is set in motion.
107650fa8db4Sad 	 */
10771ac6a89bSad 	pthread_spinunlock(self, lock);
10781ac6a89bSad 
1079*c3f8e2eeSad 	/*
1080*c3f8e2eeSad 	 * If the calling thread is about to block, defer
1081*c3f8e2eeSad 	 * unparking the target until _lwp_park() is called.
1082*c3f8e2eeSad 	 */
1083*c3f8e2eeSad 	if (self->pt_willpark && self->pt_unpark == 0) {
1084*c3f8e2eeSad 		self->pt_unpark = target->pt_lid;
1085*c3f8e2eeSad 		self->pt_unparkhint = queue;
1086*c3f8e2eeSad 	} else {
1087*c3f8e2eeSad 		rv = _lwp_unpark(target->pt_lid, queue);
10881ac6a89bSad 		if (rv != 0 && errno != EALREADY && errno != EINTR) {
10891ac6a89bSad 			SDPRINTF(("(pthread__unpark %p) syscall rv=%d\n",
10901ac6a89bSad 			    self, rv));
10911ac6a89bSad 			OOPS("_lwp_unpark failed");
10921ac6a89bSad 		}
10931ac6a89bSad 	}
1094*c3f8e2eeSad }
10951ac6a89bSad 
10961ac6a89bSad void
1097792cc0e1Sad pthread__unpark_all(pthread_t self, pthread_spin_t *lock,
109850fa8db4Sad 		    pthread_queue_t *queue)
10991ac6a89bSad {
1100ded26025Sad 	lwpid_t waiters[PTHREAD__UNPARK_MAX];
110167513ce0Sad 	ssize_t n, rv;
1102ded26025Sad 	pthread_t thread, next;
1103ded26025Sad 
1104ded26025Sad 	if (PTQ_EMPTY(queue)) {
1105ded26025Sad 		pthread_spinunlock(self, lock);
1106ded26025Sad 		return;
1107ded26025Sad 	}
1108ded26025Sad 
1109ded26025Sad 	/*
1110ded26025Sad 	 * First, clear all sleepobj pointers, since we can release the
1111ded26025Sad 	 * spin lock before awkening everybody, and must synchronise with
1112ded26025Sad 	 * pthread__park().
1113ded26025Sad 	 */
1114ded26025Sad 	PTQ_FOREACH(thread, queue, pt_sleep) {
1115ded26025Sad 		thread->pt_sleepobj = NULL;
1116792cc0e1Sad 		if (thread == PTQ_NEXT(thread, pt_sleep))
1117792cc0e1Sad 			OOPS("unpark: thread linked to self");
1118ded26025Sad 	}
11191ac6a89bSad 
11201ac6a89bSad 	for (;;) {
1121ded26025Sad 		thread = PTQ_FIRST(queue);
1122ded26025Sad 		for (n = 0; n < pthread__unpark_max && thread != NULL;
1123ded26025Sad 		    thread = next) {
1124ded26025Sad 			/*
1125ded26025Sad 			 * If the sleepobj pointer is non-NULL, it
1126ded26025Sad 			 * means one of two things:
1127ded26025Sad 			 *
1128ded26025Sad 			 * o The thread has awoken early, spun
1129ded26025Sad 			 *   through application code and is
1130ded26025Sad 			 *   once more asleep on this object.
1131ded26025Sad 			 *
1132ded26025Sad 			 * o This is a new thread that has blocked
1133ded26025Sad 			 *   on the object after we have released
1134ded26025Sad 			 *   the interlock in this loop.
1135ded26025Sad 			 *
1136ded26025Sad 			 * In both cases we shouldn't remove the
1137ded26025Sad 			 * thread from the queue.
1138ded26025Sad 			 */
1139ded26025Sad 			next = PTQ_NEXT(thread, pt_sleep);
1140ded26025Sad 			if (thread->pt_sleepobj != NULL)
1141ded26025Sad 			    	continue;
1142ded26025Sad 			thread->pt_sleeponq = 0;
1143ded26025Sad 			waiters[n++] = thread->pt_lid;
11441ac6a89bSad 			PTQ_REMOVE(queue, thread, pt_sleep);
1145792cc0e1Sad 			SDPRINTF(("(pthread__unpark_all %p) queue %p "
1146792cc0e1Sad 			    "unpark %p\n", self, queue, thread));
11471ac6a89bSad 		}
1148ded26025Sad 
114950fa8db4Sad 		/*
115050fa8db4Sad 		 * Releasing the spinlock serves as a store barrier,
115150fa8db4Sad 		 * which ensures that all our modifications are visible
115250fa8db4Sad 		 * to the thread in pthread__park() before the unpark
115350fa8db4Sad 		 * operation is set in motion.
115450fa8db4Sad 		 */
11551ac6a89bSad 		pthread_spinunlock(self, lock);
1156ded26025Sad 		switch (n) {
11571ac6a89bSad 		case 0:
11581ac6a89bSad 			return;
11591ac6a89bSad 		case 1:
1160*c3f8e2eeSad 			/*
1161*c3f8e2eeSad 			 * If the calling thread is about to block,
1162*c3f8e2eeSad 			 * defer unparking the target until _lwp_park()
1163*c3f8e2eeSad 			 * is called.
1164*c3f8e2eeSad 			 */
1165*c3f8e2eeSad 			if (self->pt_willpark && self->pt_unpark == 0) {
1166*c3f8e2eeSad 				self->pt_unpark = waiters[0];
1167*c3f8e2eeSad 				self->pt_unparkhint = queue;
1168*c3f8e2eeSad 				return;
1169*c3f8e2eeSad 			}
1170792cc0e1Sad 			rv = (ssize_t)_lwp_unpark(waiters[0], queue);
11711ac6a89bSad 			if (rv != 0 && errno != EALREADY && errno != EINTR) {
11721ac6a89bSad 				OOPS("_lwp_unpark failed");
11731ac6a89bSad 				SDPRINTF(("(pthread__unpark_all %p) "
11741ac6a89bSad 				    "syscall rv=%d\n", self, rv));
11751ac6a89bSad 			}
11761ac6a89bSad 			return;
11771ac6a89bSad 		default:
117850fa8db4Sad 			rv = _lwp_unpark_all(waiters, (size_t)n, queue);
11791ac6a89bSad 			if (rv != 0 && errno != EINTR) {
11801ac6a89bSad 				OOPS("_lwp_unpark_all failed");
11811ac6a89bSad 				SDPRINTF(("(pthread__unpark_all %p) "
11821ac6a89bSad 				    "syscall rv=%d\n", self, rv));
11831ac6a89bSad 			}
11841ac6a89bSad 			break;
11851ac6a89bSad 		}
11861ac6a89bSad 		pthread_spinlock(self, lock);
11871ac6a89bSad 	}
11881ac6a89bSad }
11891ac6a89bSad 
11901ac6a89bSad #undef	OOPS
1191