xref: /netbsd-src/lib/libpthread/pthread.c (revision 50fa8db4e44b07accbfd5f2821987476be3bf05c)
1*50fa8db4Sad /*	$NetBSD: pthread.c,v 1.69 2007/08/04 13:37:48 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*50fa8db4Sad __RCSID("$NetBSD: pthread.c,v 1.69 2007/08/04 13:37:48 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 
71*50fa8db4Sad static void	pthread__create_tramp(void *(*)(void *), void *);
72*50fa8db4Sad static void	pthread__initthread(pthread_t);
73c62a74e6Sthorpej 
74c62a74e6Sthorpej int pthread__started;
75c62a74e6Sthorpej 
76*50fa8db4Sad pthread_spin_t pthread__queue_lock = __SIMPLELOCK_UNLOCKED;
77*50fa8db4Sad pthread_queue_t pthread__allqueue;
78*50fa8db4Sad 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;
92f2f10664Scl 
93f782e995Sdrochner int _sys___sigprocmask14(int, const sigset_t *, sigset_t *);
94f782e995Sdrochner 
95c62a74e6Sthorpej __strong_alias(__libc_thr_self,pthread_self)
967dc01dbfSthorpej __strong_alias(__libc_thr_create,pthread_create)
977dc01dbfSthorpej __strong_alias(__libc_thr_exit,pthread_exit)
98c62a74e6Sthorpej __strong_alias(__libc_thr_errno,pthread__errno)
999e5c8705Snathanw __strong_alias(__libc_thr_setcancelstate,pthread_setcancelstate)
100c62a74e6Sthorpej 
101c62a74e6Sthorpej /*
102c62a74e6Sthorpej  * Static library kludge.  Place a reference to a symbol any library
103c62a74e6Sthorpej  * file which does not already have a reference here.
104c62a74e6Sthorpej  */
105c62a74e6Sthorpej extern int pthread__cancel_stub_binder;
106c62a74e6Sthorpej 
107c62a74e6Sthorpej void *pthread__static_lib_binder[] = {
108c62a74e6Sthorpej 	&pthread__cancel_stub_binder,
109c62a74e6Sthorpej 	pthread_cond_init,
110c62a74e6Sthorpej 	pthread_mutex_init,
111c62a74e6Sthorpej 	pthread_rwlock_init,
112c62a74e6Sthorpej 	pthread_barrier_init,
113c62a74e6Sthorpej 	pthread_key_create,
114bd9a18b7Snathanw 	pthread_setspecific,
115c62a74e6Sthorpej };
116c62a74e6Sthorpej 
117c62a74e6Sthorpej /*
118c62a74e6Sthorpej  * This needs to be started by the library loading code, before main()
119c62a74e6Sthorpej  * gets to run, for various things that use the state of the initial thread
120c62a74e6Sthorpej  * to work properly (thread-specific data is an application-visible example;
121c62a74e6Sthorpej  * spinlock counts for mutexes is an internal example).
122c62a74e6Sthorpej  */
123c62a74e6Sthorpej void
124c62a74e6Sthorpej pthread_init(void)
125c62a74e6Sthorpej {
126c62a74e6Sthorpej 	pthread_t first;
1270172694eSnathanw 	char *p;
128ded26025Sad 	int i, mib[2], ncpu;
129f2f10664Scl 	size_t len;
130c62a74e6Sthorpej 	extern int __isthreaded;
131c62a74e6Sthorpej 
132f2f10664Scl 	mib[0] = CTL_HW;
133f2f10664Scl 	mib[1] = HW_NCPU;
134f2f10664Scl 
135f2f10664Scl 	len = sizeof(ncpu);
136792cc0e1Sad 	if (sysctl(mib, 2, &ncpu, &len, NULL, 0) == -1)
137792cc0e1Sad 		err(1, "sysctl(hw.ncpu");
138f2f10664Scl 
139c62a74e6Sthorpej 	/* Initialize locks first; they're needed elsewhere. */
140f2f10664Scl 	pthread__lockprim_init(ncpu);
141f2f10664Scl 
142ded26025Sad 	/*
143ded26025Sad 	 * Get number of CPUs, and maximum number of LWPs that can be
144ded26025Sad 	 * unparked at once.
145ded26025Sad 	 */
146ded26025Sad 	if ((pthread__concurrency = ncpu) > 1)
147ded26025Sad 		pthread__nspins = PTHREAD__NSPINS;
148ded26025Sad 	else
149ded26025Sad 		pthread__nspins = 1;
150*50fa8db4Sad 	if ((p = getenv("PTHREAD_NSPINS")) != NULL)
151*50fa8db4Sad 		pthread__nspins = atoi(p);
1523247035dSad 	i = (int)_lwp_unpark_all(NULL, 0, NULL);
1533247035dSad 	if (i == -1)
1543247035dSad 		err(1, "_lwp_unpark_all");
155ded26025Sad 	if (i < pthread__unpark_max)
156ded26025Sad 		pthread__unpark_max = i;
157c62a74e6Sthorpej 
158c62a74e6Sthorpej 	/* Basic data structure setup */
159c62a74e6Sthorpej 	pthread_attr_init(&pthread_default_attr);
160c62a74e6Sthorpej 	PTQ_INIT(&pthread__allqueue);
161c62a74e6Sthorpej 	PTQ_INIT(&pthread__deadqueue);
162c62a74e6Sthorpej 	/* Create the thread structure corresponding to main() */
163c62a74e6Sthorpej 	pthread__initmain(&first);
164*50fa8db4Sad 	pthread__initthread(first);
1651ac6a89bSad 
166c62a74e6Sthorpej 	first->pt_state = PT_STATE_RUNNING;
1671ac6a89bSad 	first->pt_lid = _lwp_self();
168c62a74e6Sthorpej 	PTQ_INSERT_HEAD(&pthread__allqueue, first, pt_allq);
169c62a74e6Sthorpej 
170c62a74e6Sthorpej 	/* Start subsystems */
171c62a74e6Sthorpej 	PTHREAD_MD_INIT
172c62a74e6Sthorpej #ifdef PTHREAD__DEBUG
173f2f10664Scl 	pthread__debug_init(ncpu);
174c62a74e6Sthorpej #endif
175c62a74e6Sthorpej 
1760172694eSnathanw 	for (p = getenv("PTHREAD_DIAGASSERT"); p && *p; p++) {
1770172694eSnathanw 		switch (*p) {
1780172694eSnathanw 		case 'a':
1790172694eSnathanw 			pthread__diagassert |= DIAGASSERT_ABORT;
1800172694eSnathanw 			break;
1810172694eSnathanw 		case 'A':
1820172694eSnathanw 			pthread__diagassert &= ~DIAGASSERT_ABORT;
1830172694eSnathanw 			break;
1840172694eSnathanw 		case 'e':
1850172694eSnathanw 			pthread__diagassert |= DIAGASSERT_STDERR;
1860172694eSnathanw 			break;
1870172694eSnathanw 		case 'E':
1880172694eSnathanw 			pthread__diagassert &= ~DIAGASSERT_STDERR;
1890172694eSnathanw 			break;
1900172694eSnathanw 		case 'l':
1910172694eSnathanw 			pthread__diagassert |= DIAGASSERT_SYSLOG;
1920172694eSnathanw 			break;
1930172694eSnathanw 		case 'L':
1940172694eSnathanw 			pthread__diagassert &= ~DIAGASSERT_SYSLOG;
1950172694eSnathanw 			break;
196df277271Snathanw 		}
1970172694eSnathanw 	}
1980172694eSnathanw 
199df277271Snathanw 
200c62a74e6Sthorpej 	/* Tell libc that we're here and it should role-play accordingly. */
201c62a74e6Sthorpej 	__isthreaded = 1;
202c62a74e6Sthorpej }
203c62a74e6Sthorpej 
2042a4cef11Snathanw static void
2052a4cef11Snathanw pthread__child_callback(void)
2062a4cef11Snathanw {
2072a4cef11Snathanw 	/*
2082a4cef11Snathanw 	 * Clean up data structures that a forked child process might
2092a4cef11Snathanw 	 * trip over. Note that if threads have been created (causing
2102a4cef11Snathanw 	 * this handler to be registered) the standards say that the
2112a4cef11Snathanw 	 * child will trigger undefined behavior if it makes any
2122a4cef11Snathanw 	 * pthread_* calls (or any other calls that aren't
2132a4cef11Snathanw 	 * async-signal-safe), so we don't really have to clean up
2142a4cef11Snathanw 	 * much. Anything that permits some pthread_* calls to work is
2152a4cef11Snathanw 	 * merely being polite.
2162a4cef11Snathanw 	 */
2172a4cef11Snathanw 	pthread__started = 0;
2182a4cef11Snathanw }
219c62a74e6Sthorpej 
2200e675542Schs static void
221c62a74e6Sthorpej pthread__start(void)
222c62a74e6Sthorpej {
2231ac6a89bSad 	pthread_t self;
224c62a74e6Sthorpej 
225c62a74e6Sthorpej 	self = pthread__self(); /* should be the "main()" thread */
226c62a74e6Sthorpej 
227ff14fbf2Snathanw 	/*
228ff14fbf2Snathanw 	 * Per-process timers are cleared by fork(); despite the
229ff14fbf2Snathanw 	 * various restrictions on fork() and threads, it's legal to
230ff14fbf2Snathanw 	 * fork() before creating any threads.
231ff14fbf2Snathanw 	 */
2322a4cef11Snathanw 	pthread_atfork(NULL, NULL, pthread__child_callback);
233c62a74e6Sthorpej 	SDPRINTF(("(pthread__start %p) Started.\n", self));
234c62a74e6Sthorpej }
235c62a74e6Sthorpej 
236c62a74e6Sthorpej 
237c62a74e6Sthorpej /* General-purpose thread data structure sanitization. */
238*50fa8db4Sad /* ARGSUSED */
239*50fa8db4Sad static void
240*50fa8db4Sad pthread__initthread(pthread_t t)
241c62a74e6Sthorpej {
242c62a74e6Sthorpej 
243c62a74e6Sthorpej 	t->pt_magic = PT_MAGIC;
244c62a74e6Sthorpej 	t->pt_spinlocks = 0;
245c62a74e6Sthorpej 	t->pt_exitval = NULL;
246c62a74e6Sthorpej 	t->pt_flags = 0;
247c62a74e6Sthorpej 	t->pt_cancel = 0;
248c62a74e6Sthorpej 	t->pt_errno = 0;
2491ac6a89bSad 	t->pt_state = PT_STATE_RUNNING;
2501ac6a89bSad 
251*50fa8db4Sad 	pthread_lockinit(&t->pt_lock);
252c62a74e6Sthorpej 	PTQ_INIT(&t->pt_cleanup_stack);
253c62a74e6Sthorpej 	memset(&t->pt_specific, 0, sizeof(int) * PTHREAD_KEYS_MAX);
254b33971b9Sthorpej 	t->pt_name = NULL;
255c62a74e6Sthorpej }
256c62a74e6Sthorpej 
257c62a74e6Sthorpej 
258c62a74e6Sthorpej int
259c62a74e6Sthorpej pthread_create(pthread_t *thread, const pthread_attr_t *attr,
260c62a74e6Sthorpej 	    void *(*startfunc)(void *), void *arg)
261c62a74e6Sthorpej {
262c62a74e6Sthorpej 	pthread_t self, newthread;
263c62a74e6Sthorpej 	pthread_attr_t nattr;
264b33971b9Sthorpej 	struct pthread_attr_private *p;
2653ca3d0b1Schristos 	char * volatile name;
266de213816Sad 	int ret, flag;
267c62a74e6Sthorpej 
268c62a74e6Sthorpej 	PTHREADD_ADD(PTHREADD_CREATE);
269c62a74e6Sthorpej 
270c62a74e6Sthorpej 	/*
271c62a74e6Sthorpej 	 * It's okay to check this without a lock because there can
272c62a74e6Sthorpej 	 * only be one thread before it becomes true.
273c62a74e6Sthorpej 	 */
274c62a74e6Sthorpej 	if (pthread__started == 0) {
275c62a74e6Sthorpej 		pthread__start();
276c62a74e6Sthorpej 		pthread__started = 1;
277c62a74e6Sthorpej 	}
278c62a74e6Sthorpej 
279c62a74e6Sthorpej 	if (attr == NULL)
280c62a74e6Sthorpej 		nattr = pthread_default_attr;
281e81f9f17Sdrochner 	else if (attr->pta_magic == PT_ATTR_MAGIC)
282c62a74e6Sthorpej 		nattr = *attr;
283c62a74e6Sthorpej 	else
284c62a74e6Sthorpej 		return EINVAL;
285c62a74e6Sthorpej 
286b33971b9Sthorpej 	/* Fetch misc. attributes from the attr structure. */
287508a50acSnathanw 	name = NULL;
288508a50acSnathanw 	if ((p = nattr.pta_private) != NULL)
289508a50acSnathanw 		if (p->ptap_name[0] != '\0')
290b33971b9Sthorpej 			if ((name = strdup(p->ptap_name)) == NULL)
291b33971b9Sthorpej 				return ENOMEM;
292c62a74e6Sthorpej 
293c62a74e6Sthorpej 	self = pthread__self();
294c62a74e6Sthorpej 
295*50fa8db4Sad 	pthread_spinlock(self, &pthread__queue_lock);
296c62a74e6Sthorpej 	newthread = PTQ_FIRST(&pthread__deadqueue);
2974cdc2ed8Syamt 	if (newthread != NULL) {
298*50fa8db4Sad 		if ((newthread->pt_flags & PT_FLAG_DETACHED) != 0) {
299*50fa8db4Sad 			PTQ_REMOVE(&pthread__deadqueue, newthread, pt_allq);
300*50fa8db4Sad 			pthread_spinunlock(self, &pthread__queue_lock);
301*50fa8db4Sad 			if (_lwp_kill(newthread->pt_lid, 0) == 0 ||
302*50fa8db4Sad 			    errno != ESRCH) {
303*50fa8db4Sad 				pthread_spinlock(self, &pthread__queue_lock);
304*50fa8db4Sad 				PTQ_INSERT_TAIL(&pthread__deadqueue,
305*50fa8db4Sad 				    newthread, pt_allq);
306*50fa8db4Sad 				pthread_spinunlock(self, &pthread__queue_lock);
3074cdc2ed8Syamt 				newthread = NULL;
308*50fa8db4Sad 			}
309*50fa8db4Sad 		} else
310c62a74e6Sthorpej 			PTQ_REMOVE(&pthread__deadqueue, newthread, pt_allq);
3114cdc2ed8Syamt 	}
312*50fa8db4Sad 	pthread_spinunlock(self, &pthread__queue_lock);
3134cdc2ed8Syamt 	if (newthread == NULL) {
314c62a74e6Sthorpej 		/* Set up a stack and allocate space for a pthread_st. */
315c62a74e6Sthorpej 		ret = pthread__stackalloc(&newthread);
316b7559f85Schristos 		if (ret != 0) {
317b7559f85Schristos 			if (name)
318b7559f85Schristos 				free(name);
319c62a74e6Sthorpej 			return ret;
320c62a74e6Sthorpej 		}
321b7559f85Schristos 	}
322c62a74e6Sthorpej 
323c62a74e6Sthorpej 	/* 2. Set up state. */
324*50fa8db4Sad 	pthread__initthread(newthread);
325c62a74e6Sthorpej 	newthread->pt_flags = nattr.pta_flags;
326c62a74e6Sthorpej 
327b33971b9Sthorpej 	/* 3. Set up misc. attributes. */
328b33971b9Sthorpej 	newthread->pt_name = name;
329b33971b9Sthorpej 
330c62a74e6Sthorpej 	/*
331b33971b9Sthorpej 	 * 4. Set up context.
332c62a74e6Sthorpej 	 *
333c62a74e6Sthorpej 	 * The pt_uc pointer points to a location safely below the
334c62a74e6Sthorpej 	 * stack start; this is arranged by pthread__stackalloc().
335c62a74e6Sthorpej 	 */
336c62a74e6Sthorpej 	_INITCONTEXT_U(newthread->pt_uc);
337877f8985Snathanw #ifdef PTHREAD_MACHINE_HAS_ID_REGISTER
338877f8985Snathanw 	pthread__uc_id(newthread->pt_uc) = newthread;
339877f8985Snathanw #endif
340c62a74e6Sthorpej 	newthread->pt_uc->uc_stack = newthread->pt_stack;
341c62a74e6Sthorpej 	newthread->pt_uc->uc_link = NULL;
342c62a74e6Sthorpej 	makecontext(newthread->pt_uc, pthread__create_tramp, 2,
343c62a74e6Sthorpej 	    startfunc, arg);
344c62a74e6Sthorpej 
345efb1fc06Sad 	/* 5. Add to list of all threads. */
346*50fa8db4Sad 	pthread_spinlock(self, &pthread__queue_lock);
347efb1fc06Sad 	PTQ_INSERT_HEAD(&pthread__allqueue, newthread, pt_allq);
348*50fa8db4Sad 	pthread_spinunlock(self, &pthread__queue_lock);
349efb1fc06Sad 
350efb1fc06Sad 	/* 5a. Create the new LWP. */
3517630e387Sad 	newthread->pt_sleeponq = 0;
352ded26025Sad 	flag = 0;
353ded26025Sad 	if ((newthread->pt_flags & PT_FLAG_SUSPENDED) != 0)
354ded26025Sad 		flag |= LWP_SUSPENDED;
355ded26025Sad 	if ((newthread->pt_flags & PT_FLAG_DETACHED) != 0)
356ded26025Sad 		flag |= LWP_DETACHED;
3571ac6a89bSad 	ret = _lwp_create(newthread->pt_uc, (u_long)flag, &newthread->pt_lid);
3581ac6a89bSad 	if (ret != 0) {
3591ac6a89bSad 		SDPRINTF(("(pthread_create %p) _lwp_create: %s\n",
3601ac6a89bSad 		    strerror(errno)));
3611ac6a89bSad 		free(name);
362*50fa8db4Sad 		pthread_spinlock(self, &pthread__queue_lock);
363efb1fc06Sad 		PTQ_REMOVE(&pthread__allqueue, newthread, pt_allq);
364efb1fc06Sad 		PTQ_INSERT_HEAD(&pthread__deadqueue, newthread, pt_allq);
365*50fa8db4Sad 		pthread_spinunlock(self, &pthread__queue_lock);
3661ac6a89bSad 		return ret;
3671ac6a89bSad 	}
3681ac6a89bSad 
369*50fa8db4Sad 	/* XXX must die */
370*50fa8db4Sad 	newthread->pt_num = newthread->pt_lid;
371*50fa8db4Sad 
3721ac6a89bSad 	SDPRINTF(("(pthread_create %p) new thread %p (name %p, lid %d).\n",
3731ac6a89bSad 		  self, newthread, newthread->pt_name,
3741ac6a89bSad 		  (int)newthread->pt_lid));
375c62a74e6Sthorpej 
376c62a74e6Sthorpej 	*thread = newthread;
377c62a74e6Sthorpej 
378c62a74e6Sthorpej 	return 0;
379c62a74e6Sthorpej }
380c62a74e6Sthorpej 
381c62a74e6Sthorpej 
382c62a74e6Sthorpej static void
383c62a74e6Sthorpej pthread__create_tramp(void *(*start)(void *), void *arg)
384c62a74e6Sthorpej {
385c62a74e6Sthorpej 	void *retval;
386c62a74e6Sthorpej 
387*50fa8db4Sad 	/*
388*50fa8db4Sad 	 * Throw away some stack in a feeble attempt to reduce cache
389*50fa8db4Sad 	 * thrash.  May help for SMT processors.  XXX We should not
390*50fa8db4Sad 	 * be allocating stacks on fixed 2MB boundaries.  Needs a
391*50fa8db4Sad 	 * thread register or decent thread local storage.
392*50fa8db4Sad 	 */
393*50fa8db4Sad 	(void)alloca(((unsigned)pthread__self()->pt_lid & 7) << 8);
394*50fa8db4Sad 
39594a458ceSchs 	retval = (*start)(arg);
396c62a74e6Sthorpej 
397c62a74e6Sthorpej 	pthread_exit(retval);
398c62a74e6Sthorpej 
399143f5a27Schristos 	/*NOTREACHED*/
400143f5a27Schristos 	pthread__abort();
401c62a74e6Sthorpej }
402c62a74e6Sthorpej 
40338b1c6f4Schristos int
40438b1c6f4Schristos pthread_suspend_np(pthread_t thread)
40538b1c6f4Schristos {
406ba70e96aSchs 	pthread_t self;
407ba70e96aSchs 
408ba70e96aSchs 	self = pthread__self();
40938b1c6f4Schristos 	if (self == thread) {
41038b1c6f4Schristos 		return EDEADLK;
41138b1c6f4Schristos 	}
412ba70e96aSchs #ifdef ERRORCHECK
413ba70e96aSchs 	if (pthread__find(self, thread) != 0)
414ba70e96aSchs 		return ESRCH;
415ba70e96aSchs #endif
4161ac6a89bSad 	SDPRINTF(("(pthread_suspend_np %p) Suspend thread %p.\n",
4171ac6a89bSad 		     self, thread));
4181ac6a89bSad 	return _lwp_suspend(thread->pt_lid);
41938b1c6f4Schristos }
42038b1c6f4Schristos 
42138b1c6f4Schristos int
42238b1c6f4Schristos pthread_resume_np(pthread_t thread)
42338b1c6f4Schristos {
424ba70e96aSchs 	pthread_t self;
42538b1c6f4Schristos 
426ba70e96aSchs 	self = pthread__self();
427ba70e96aSchs #ifdef ERRORCHECK
428ba70e96aSchs 	if (pthread__find(self, thread) != 0)
429ba70e96aSchs 		return ESRCH;
430ba70e96aSchs #endif
4311ac6a89bSad 	SDPRINTF(("(pthread_resume_np %p) Resume thread %p.\n",
4321ac6a89bSad 		     self, thread));
4331ac6a89bSad 	return _lwp_continue(thread->pt_lid);
43438b1c6f4Schristos }
43538b1c6f4Schristos 
436c62a74e6Sthorpej void
437c62a74e6Sthorpej pthread_exit(void *retval)
438c62a74e6Sthorpej {
43996b5a26dSnathanw 	pthread_t self;
440c62a74e6Sthorpej 	struct pt_clean_t *cleanup;
441b33971b9Sthorpej 	char *name;
442c62a74e6Sthorpej 
443c62a74e6Sthorpej 	self = pthread__self();
444ba70e96aSchs 	SDPRINTF(("(pthread_exit %p) status %p, flags %x, cancel %d\n",
445ba70e96aSchs 		  self, retval, self->pt_flags, self->pt_cancel));
446c62a74e6Sthorpej 
447c62a74e6Sthorpej 	/* Disable cancellability. */
448*50fa8db4Sad 	pthread_spinlock(self, &self->pt_lock);
449c62a74e6Sthorpej 	self->pt_flags |= PT_FLAG_CS_DISABLED;
45066fcc1ceSnathanw 	self->pt_cancel = 0;
451*50fa8db4Sad 	pthread_spinunlock(self, &self->pt_lock);
452c62a74e6Sthorpej 
453c62a74e6Sthorpej 	/* Call any cancellation cleanup handlers */
454c62a74e6Sthorpej 	while (!PTQ_EMPTY(&self->pt_cleanup_stack)) {
455c62a74e6Sthorpej 		cleanup = PTQ_FIRST(&self->pt_cleanup_stack);
456c62a74e6Sthorpej 		PTQ_REMOVE(&self->pt_cleanup_stack, cleanup, ptc_next);
457c62a74e6Sthorpej 		(*cleanup->ptc_cleanup)(cleanup->ptc_arg);
458c62a74e6Sthorpej 	}
459c62a74e6Sthorpej 
460c62a74e6Sthorpej 	/* Perform cleanup of thread-specific data */
461c62a74e6Sthorpej 	pthread__destroy_tsd(self);
462c62a74e6Sthorpej 
463c62a74e6Sthorpej 	self->pt_exitval = retval;
464c62a74e6Sthorpej 
465*50fa8db4Sad 	pthread_spinlock(self, &self->pt_lock);
4666b2b9c62Syamt 	if (self->pt_flags & PT_FLAG_DETACHED) {
4676b2b9c62Syamt 		self->pt_state = PT_STATE_DEAD;
468b33971b9Sthorpej 		name = self->pt_name;
469b33971b9Sthorpej 		self->pt_name = NULL;
470*50fa8db4Sad 		pthread_spinlock(self, &pthread__queue_lock);
471*50fa8db4Sad 		PTQ_REMOVE(&pthread__allqueue, self, pt_allq);
472*50fa8db4Sad 		PTQ_INSERT_TAIL(&pthread__deadqueue, self, pt_allq);
473*50fa8db4Sad 		pthread_spinunlock(self, &pthread__queue_lock);
474*50fa8db4Sad 		pthread_spinunlock(self, &self->pt_lock);
475b33971b9Sthorpej 		if (name != NULL)
476b33971b9Sthorpej 			free(name);
4771ac6a89bSad 		_lwp_exit();
478c62a74e6Sthorpej 	} else {
4796b2b9c62Syamt 		self->pt_state = PT_STATE_ZOMBIE;
480*50fa8db4Sad 		pthread_spinunlock(self, &self->pt_lock);
481b33971b9Sthorpej 		/* Note: name will be freed by the joiner. */
4821ac6a89bSad 		_lwp_exit();
483c62a74e6Sthorpej 	}
484c62a74e6Sthorpej 
485143f5a27Schristos 	/*NOTREACHED*/
486143f5a27Schristos 	pthread__abort();
487c62a74e6Sthorpej 	exit(1);
488c62a74e6Sthorpej }
489c62a74e6Sthorpej 
490c62a74e6Sthorpej 
491c62a74e6Sthorpej int
492c62a74e6Sthorpej pthread_join(pthread_t thread, void **valptr)
493c62a74e6Sthorpej {
494c62a74e6Sthorpej 	pthread_t self;
495b33971b9Sthorpej 	char *name;
4961ac6a89bSad 	int num, retval;
497c62a74e6Sthorpej 
498c62a74e6Sthorpej 	self = pthread__self();
499c62a74e6Sthorpej 	SDPRINTF(("(pthread_join %p) Joining %p.\n", self, thread));
500c62a74e6Sthorpej 
501c62a74e6Sthorpej 	if (pthread__find(self, thread) != 0)
502c62a74e6Sthorpej 		return ESRCH;
503c62a74e6Sthorpej 
504c62a74e6Sthorpej 	if (thread->pt_magic != PT_MAGIC)
505c62a74e6Sthorpej 		return EINVAL;
506c62a74e6Sthorpej 
507c62a74e6Sthorpej 	if (thread == self)
508c62a74e6Sthorpej 		return EDEADLK;
509c62a74e6Sthorpej 
5101ac6a89bSad 	retval = 0;
5111ac6a89bSad 	name = NULL;
5121ac6a89bSad  again:
513*50fa8db4Sad  	pthread_spinlock(self, &thread->pt_lock);
5141ac6a89bSad 	switch (thread->pt_state) {
5151ac6a89bSad 	case PT_STATE_RUNNING:
516*50fa8db4Sad 		pthread_spinunlock(self, &thread->pt_lock);
517ded26025Sad 
518ded26025Sad 		/*
519ded26025Sad 		 * IEEE Std 1003.1, 2004 Edition:
520ded26025Sad 		 *
521ded26025Sad 		 * "The pthread_join() function shall not
522ded26025Sad 		 * return an error code of [EINTR]."
523ded26025Sad 		 */
524ded26025Sad 		if (_lwp_wait(thread->pt_lid, &num) != 0 && errno != EINTR)
525ded26025Sad 			return errno;
5261ac6a89bSad 		goto again;
5271ac6a89bSad 	case PT_STATE_ZOMBIE:
5281ac6a89bSad 		if (valptr != NULL)
529ded26025Sad 			*valptr = thread->pt_exitval;
5301ac6a89bSad 		if (retval == 0) {
5311ac6a89bSad 			name = thread->pt_name;
5321ac6a89bSad 			thread->pt_name = NULL;
5331ac6a89bSad 		}
5341ac6a89bSad 		thread->pt_state = PT_STATE_DEAD;
535*50fa8db4Sad 		pthread_spinlock(self, &pthread__queue_lock);
536*50fa8db4Sad 		PTQ_REMOVE(&pthread__allqueue, thread, pt_allq);
537*50fa8db4Sad 		PTQ_INSERT_HEAD(&pthread__deadqueue, thread, pt_allq);
538*50fa8db4Sad 		pthread_spinunlock(self, &pthread__queue_lock);
539*50fa8db4Sad 		pthread_spinunlock(self, &thread->pt_lock);
540*50fa8db4Sad 		SDPRINTF(("(pthread_join %p) Joined %p.\n", self, thread));
541*50fa8db4Sad 		if (name != NULL)
542*50fa8db4Sad 			free(name);
543b8daad98Sad 		(void)_lwp_detach(thread->pt_lid);
544*50fa8db4Sad 		return retval;
5451ac6a89bSad 	default:
546*50fa8db4Sad 		pthread_spinunlock(self, &thread->pt_lock);
5471ac6a89bSad 		return EINVAL;
5481ac6a89bSad 	}
5491ac6a89bSad 
550c62a74e6Sthorpej }
551c62a74e6Sthorpej 
552c62a74e6Sthorpej 
553c62a74e6Sthorpej int
554c62a74e6Sthorpej pthread_equal(pthread_t t1, pthread_t t2)
555c62a74e6Sthorpej {
556c62a74e6Sthorpej 
557c62a74e6Sthorpej 	/* Nothing special here. */
558c62a74e6Sthorpej 	return (t1 == t2);
559c62a74e6Sthorpej }
560c62a74e6Sthorpej 
561c62a74e6Sthorpej 
562c62a74e6Sthorpej int
563c62a74e6Sthorpej pthread_detach(pthread_t thread)
564c62a74e6Sthorpej {
56596b5a26dSnathanw 	pthread_t self;
566c62a74e6Sthorpej 
567c62a74e6Sthorpej 	self = pthread__self();
568c62a74e6Sthorpej 
569c62a74e6Sthorpej 	if (pthread__find(self, thread) != 0)
570c62a74e6Sthorpej 		return ESRCH;
571c62a74e6Sthorpej 
572c62a74e6Sthorpej 	if (thread->pt_magic != PT_MAGIC)
573c62a74e6Sthorpej 		return EINVAL;
574c62a74e6Sthorpej 
575*50fa8db4Sad 	pthread_spinlock(self, &self->pt_lock);
5761296e850Sad 	thread->pt_flags |= PT_FLAG_DETACHED;
577*50fa8db4Sad 	pthread_spinunlock(self, &self->pt_lock);
578de213816Sad 
5791ac6a89bSad 	return _lwp_detach(thread->pt_lid);
580c62a74e6Sthorpej }
581c62a74e6Sthorpej 
582c62a74e6Sthorpej 
583c62a74e6Sthorpej int
584b33971b9Sthorpej pthread_getname_np(pthread_t thread, char *name, size_t len)
585c62a74e6Sthorpej {
586b33971b9Sthorpej 	pthread_t self;
587c62a74e6Sthorpej 
588b33971b9Sthorpej 	self = pthread__self();
589b33971b9Sthorpej 
590b33971b9Sthorpej 	if (pthread__find(self, thread) != 0)
591b33971b9Sthorpej 		return ESRCH;
592b33971b9Sthorpej 
593b33971b9Sthorpej 	if (thread->pt_magic != PT_MAGIC)
594b33971b9Sthorpej 		return EINVAL;
595b33971b9Sthorpej 
596*50fa8db4Sad 	pthread_spinlock(self, &thread->pt_lock);
597b33971b9Sthorpej 	if (thread->pt_name == NULL)
598b33971b9Sthorpej 		name[0] = '\0';
599b33971b9Sthorpej 	else
600b33971b9Sthorpej 		strlcpy(name, thread->pt_name, len);
601*50fa8db4Sad 	pthread_spinunlock(self, &thread->pt_lock);
602c62a74e6Sthorpej 
603c62a74e6Sthorpej 	return 0;
604c62a74e6Sthorpej }
605c62a74e6Sthorpej 
606c62a74e6Sthorpej 
607c62a74e6Sthorpej int
608b33971b9Sthorpej pthread_setname_np(pthread_t thread, const char *name, void *arg)
609b33971b9Sthorpej {
610ba70e96aSchs 	pthread_t self;
611b33971b9Sthorpej 	char *oldname, *cp, newname[PTHREAD_MAX_NAMELEN_NP];
612b33971b9Sthorpej 	int namelen;
613b33971b9Sthorpej 
614ba70e96aSchs 	self = pthread__self();
615b33971b9Sthorpej 	if (pthread__find(self, thread) != 0)
616b33971b9Sthorpej 		return ESRCH;
617b33971b9Sthorpej 
618b33971b9Sthorpej 	if (thread->pt_magic != PT_MAGIC)
619b33971b9Sthorpej 		return EINVAL;
620b33971b9Sthorpej 
621b33971b9Sthorpej 	namelen = snprintf(newname, sizeof(newname), name, arg);
622b33971b9Sthorpej 	if (namelen >= PTHREAD_MAX_NAMELEN_NP)
623b33971b9Sthorpej 		return EINVAL;
624b33971b9Sthorpej 
625b33971b9Sthorpej 	cp = strdup(newname);
626b33971b9Sthorpej 	if (cp == NULL)
627b33971b9Sthorpej 		return ENOMEM;
628b33971b9Sthorpej 
629*50fa8db4Sad 	pthread_spinlock(self, &thread->pt_lock);
630b33971b9Sthorpej 	oldname = thread->pt_name;
631b33971b9Sthorpej 	thread->pt_name = cp;
632*50fa8db4Sad 	pthread_spinunlock(self, &thread->pt_lock);
633b33971b9Sthorpej 
634b33971b9Sthorpej 	if (oldname != NULL)
635b33971b9Sthorpej 		free(oldname);
636b33971b9Sthorpej 
637b33971b9Sthorpej 	return 0;
638b33971b9Sthorpej }
639b33971b9Sthorpej 
640b33971b9Sthorpej 
641b33971b9Sthorpej 
642c62a74e6Sthorpej /*
643c62a74e6Sthorpej  * XXX There should be a way for applications to use the efficent
644c62a74e6Sthorpej  *  inline version, but there are opacity/namespace issues.
645c62a74e6Sthorpej  */
646c62a74e6Sthorpej pthread_t
647c62a74e6Sthorpej pthread_self(void)
648c62a74e6Sthorpej {
649c62a74e6Sthorpej 
650c62a74e6Sthorpej 	return pthread__self();
651c62a74e6Sthorpej }
652c62a74e6Sthorpej 
653c62a74e6Sthorpej 
654c62a74e6Sthorpej int
655c62a74e6Sthorpej pthread_cancel(pthread_t thread)
656c62a74e6Sthorpej {
657c62a74e6Sthorpej 	pthread_t self;
658c62a74e6Sthorpej 
659ba70e96aSchs 	self = pthread__self();
660ba70e96aSchs 	if (pthread__find(self, thread) != 0)
661ba70e96aSchs 		return ESRCH;
662*50fa8db4Sad 	pthread_spinlock(self, &thread->pt_lock);
6631ac6a89bSad 	thread->pt_flags |= PT_FLAG_CS_PENDING;
6641ac6a89bSad 	if ((thread->pt_flags & PT_FLAG_CS_DISABLED) == 0) {
6651ac6a89bSad 		thread->pt_cancel = 1;
666*50fa8db4Sad 		pthread_spinunlock(self, &thread->pt_lock);
6671ac6a89bSad 		_lwp_wakeup(thread->pt_lid);
6681ac6a89bSad 	} else
669*50fa8db4Sad 		pthread_spinunlock(self, &thread->pt_lock);
670c62a74e6Sthorpej 
671c62a74e6Sthorpej 	return 0;
672c62a74e6Sthorpej }
673c62a74e6Sthorpej 
674c62a74e6Sthorpej 
675c62a74e6Sthorpej int
676c62a74e6Sthorpej pthread_setcancelstate(int state, int *oldstate)
677c62a74e6Sthorpej {
678c62a74e6Sthorpej 	pthread_t self;
6790878df5dSnathanw 	int retval;
680c62a74e6Sthorpej 
681c62a74e6Sthorpej 	self = pthread__self();
6820878df5dSnathanw 	retval = 0;
683c62a74e6Sthorpej 
684*50fa8db4Sad 	pthread_spinlock(self, &self->pt_lock);
685*50fa8db4Sad 
686c62a74e6Sthorpej 	if (oldstate != NULL) {
6870878df5dSnathanw 		if (self->pt_flags & PT_FLAG_CS_DISABLED)
688c62a74e6Sthorpej 			*oldstate = PTHREAD_CANCEL_DISABLE;
689c62a74e6Sthorpej 		else
690c62a74e6Sthorpej 			*oldstate = PTHREAD_CANCEL_ENABLE;
691c62a74e6Sthorpej 	}
692c62a74e6Sthorpej 
6930878df5dSnathanw 	if (state == PTHREAD_CANCEL_DISABLE) {
6940878df5dSnathanw 		self->pt_flags |= PT_FLAG_CS_DISABLED;
6950878df5dSnathanw 		if (self->pt_cancel) {
6960878df5dSnathanw 			self->pt_flags |= PT_FLAG_CS_PENDING;
6970878df5dSnathanw 			self->pt_cancel = 0;
6980878df5dSnathanw 		}
6990878df5dSnathanw 	} else if (state == PTHREAD_CANCEL_ENABLE) {
7000878df5dSnathanw 		self->pt_flags &= ~PT_FLAG_CS_DISABLED;
701c62a74e6Sthorpej 		/*
702c62a74e6Sthorpej 		 * If a cancellation was requested while cancellation
703c62a74e6Sthorpej 		 * was disabled, note that fact for future
704c62a74e6Sthorpej 		 * cancellation tests.
705c62a74e6Sthorpej 		 */
7060878df5dSnathanw 		if (self->pt_flags & PT_FLAG_CS_PENDING) {
707c62a74e6Sthorpej 			self->pt_cancel = 1;
708c62a74e6Sthorpej 			/* This is not a deferred cancellation point. */
7090878df5dSnathanw 			if (self->pt_flags & PT_FLAG_CS_ASYNC) {
710*50fa8db4Sad 				pthread_spinunlock(self, &self->pt_lock);
711c62a74e6Sthorpej 				pthread_exit(PTHREAD_CANCELED);
712c62a74e6Sthorpej 			}
7130878df5dSnathanw 		}
714c62a74e6Sthorpej 	} else
7150878df5dSnathanw 		retval = EINVAL;
716c62a74e6Sthorpej 
717*50fa8db4Sad 	pthread_spinunlock(self, &self->pt_lock);
718*50fa8db4Sad 
7190878df5dSnathanw 	return retval;
720c62a74e6Sthorpej }
721c62a74e6Sthorpej 
722c62a74e6Sthorpej 
723c62a74e6Sthorpej int
724c62a74e6Sthorpej pthread_setcanceltype(int type, int *oldtype)
725c62a74e6Sthorpej {
726c62a74e6Sthorpej 	pthread_t self;
7270878df5dSnathanw 	int retval;
728c62a74e6Sthorpej 
729c62a74e6Sthorpej 	self = pthread__self();
7300878df5dSnathanw 	retval = 0;
7310878df5dSnathanw 
732*50fa8db4Sad 	pthread_spinlock(self, &self->pt_lock);
733c62a74e6Sthorpej 
734c62a74e6Sthorpej 	if (oldtype != NULL) {
7350878df5dSnathanw 		if (self->pt_flags & PT_FLAG_CS_ASYNC)
736c62a74e6Sthorpej 			*oldtype = PTHREAD_CANCEL_ASYNCHRONOUS;
737c62a74e6Sthorpej 		else
738c62a74e6Sthorpej 			*oldtype = PTHREAD_CANCEL_DEFERRED;
739c62a74e6Sthorpej 	}
740c62a74e6Sthorpej 
741c62a74e6Sthorpej 	if (type == PTHREAD_CANCEL_ASYNCHRONOUS) {
7420878df5dSnathanw 		self->pt_flags |= PT_FLAG_CS_ASYNC;
7430878df5dSnathanw 		if (self->pt_cancel) {
744*50fa8db4Sad 			pthread_spinunlock(self, &self->pt_lock);
745c62a74e6Sthorpej 			pthread_exit(PTHREAD_CANCELED);
7460878df5dSnathanw 		}
747c62a74e6Sthorpej 	} else if (type == PTHREAD_CANCEL_DEFERRED)
7480878df5dSnathanw 		self->pt_flags &= ~PT_FLAG_CS_ASYNC;
749c62a74e6Sthorpej 	else
7500878df5dSnathanw 		retval = EINVAL;
751c62a74e6Sthorpej 
752*50fa8db4Sad 	pthread_spinunlock(self, &self->pt_lock);
753*50fa8db4Sad 
7540878df5dSnathanw 	return retval;
755c62a74e6Sthorpej }
756c62a74e6Sthorpej 
757c62a74e6Sthorpej 
758c62a74e6Sthorpej void
759c62a74e6Sthorpej pthread_testcancel()
760c62a74e6Sthorpej {
761c62a74e6Sthorpej 	pthread_t self;
762c62a74e6Sthorpej 
763c62a74e6Sthorpej 	self = pthread__self();
764c62a74e6Sthorpej 	if (self->pt_cancel)
765c62a74e6Sthorpej 		pthread_exit(PTHREAD_CANCELED);
766c62a74e6Sthorpej }
767c62a74e6Sthorpej 
768c62a74e6Sthorpej 
769c62a74e6Sthorpej /*
770c62a74e6Sthorpej  * POSIX requires that certain functions return an error rather than
771c62a74e6Sthorpej  * invoking undefined behavior even when handed completely bogus
772c62a74e6Sthorpej  * pthread_t values, e.g. stack garbage or (pthread_t)666. This
773c62a74e6Sthorpej  * utility routine searches the list of threads for the pthread_t
774c62a74e6Sthorpej  * value without dereferencing it.
775c62a74e6Sthorpej  */
776c62a74e6Sthorpej int
777c62a74e6Sthorpej pthread__find(pthread_t self, pthread_t id)
778c62a74e6Sthorpej {
779c62a74e6Sthorpej 	pthread_t target;
780c62a74e6Sthorpej 
781*50fa8db4Sad 	pthread_spinlock(self, &pthread__queue_lock);
782c62a74e6Sthorpej 	PTQ_FOREACH(target, &pthread__allqueue, pt_allq)
783c62a74e6Sthorpej 	    if (target == id)
784c62a74e6Sthorpej 		    break;
785*50fa8db4Sad 	pthread_spinunlock(self, &pthread__queue_lock);
786c62a74e6Sthorpej 
787c62a74e6Sthorpej 	if (target == NULL)
788c62a74e6Sthorpej 		return ESRCH;
789c62a74e6Sthorpej 
790c62a74e6Sthorpej 	return 0;
791c62a74e6Sthorpej }
792c62a74e6Sthorpej 
793c62a74e6Sthorpej 
794c62a74e6Sthorpej void
795c62a74e6Sthorpej pthread__testcancel(pthread_t self)
796c62a74e6Sthorpej {
797c62a74e6Sthorpej 
798c62a74e6Sthorpej 	if (self->pt_cancel)
799c62a74e6Sthorpej 		pthread_exit(PTHREAD_CANCELED);
800c62a74e6Sthorpej }
801c62a74e6Sthorpej 
802c62a74e6Sthorpej 
803c62a74e6Sthorpej void
804c62a74e6Sthorpej pthread__cleanup_push(void (*cleanup)(void *), void *arg, void *store)
805c62a74e6Sthorpej {
806c62a74e6Sthorpej 	pthread_t self;
807c62a74e6Sthorpej 	struct pt_clean_t *entry;
808c62a74e6Sthorpej 
809c62a74e6Sthorpej 	self = pthread__self();
810c62a74e6Sthorpej 	entry = store;
811c62a74e6Sthorpej 	entry->ptc_cleanup = cleanup;
812c62a74e6Sthorpej 	entry->ptc_arg = arg;
813c62a74e6Sthorpej 	PTQ_INSERT_HEAD(&self->pt_cleanup_stack, entry, ptc_next);
814c62a74e6Sthorpej }
815c62a74e6Sthorpej 
816c62a74e6Sthorpej 
817c62a74e6Sthorpej void
818c62a74e6Sthorpej pthread__cleanup_pop(int ex, void *store)
819c62a74e6Sthorpej {
820c62a74e6Sthorpej 	pthread_t self;
821c62a74e6Sthorpej 	struct pt_clean_t *entry;
822c62a74e6Sthorpej 
823c62a74e6Sthorpej 	self = pthread__self();
824c62a74e6Sthorpej 	entry = store;
825c62a74e6Sthorpej 
826c62a74e6Sthorpej 	PTQ_REMOVE(&self->pt_cleanup_stack, entry, ptc_next);
827c62a74e6Sthorpej 	if (ex)
828c62a74e6Sthorpej 		(*entry->ptc_cleanup)(entry->ptc_arg);
829c62a74e6Sthorpej }
830c62a74e6Sthorpej 
831c62a74e6Sthorpej 
832c62a74e6Sthorpej int *
833c62a74e6Sthorpej pthread__errno(void)
834c62a74e6Sthorpej {
835c62a74e6Sthorpej 	pthread_t self;
836c62a74e6Sthorpej 
837c62a74e6Sthorpej 	self = pthread__self();
838c62a74e6Sthorpej 
839c62a74e6Sthorpej 	return &(self->pt_errno);
840c62a74e6Sthorpej }
8418bcff70bSnathanw 
8420c967901Snathanw ssize_t	_sys_write(int, const void *, size_t);
8430c967901Snathanw 
8448bcff70bSnathanw void
8450e6c93b9Sdrochner pthread__assertfunc(const char *file, int line, const char *function,
8460e6c93b9Sdrochner 		    const char *expr)
8478bcff70bSnathanw {
8488bcff70bSnathanw 	char buf[1024];
8498bcff70bSnathanw 	int len;
8508bcff70bSnathanw 
85175a94788Smycroft 	SDPRINTF(("(af)\n"));
85275a94788Smycroft 
8538bcff70bSnathanw 	/*
8548bcff70bSnathanw 	 * snprintf should not acquire any locks, or we could
8558bcff70bSnathanw 	 * end up deadlocked if the assert caller held locks.
8568bcff70bSnathanw 	 */
8578bcff70bSnathanw 	len = snprintf(buf, 1024,
8588bcff70bSnathanw 	    "assertion \"%s\" failed: file \"%s\", line %d%s%s%s\n",
8598bcff70bSnathanw 	    expr, file, line,
8608bcff70bSnathanw 	    function ? ", function \"" : "",
8618bcff70bSnathanw 	    function ? function : "",
8628bcff70bSnathanw 	    function ? "\"" : "");
8638bcff70bSnathanw 
8640c967901Snathanw 	_sys_write(STDERR_FILENO, buf, (size_t)len);
8658bcff70bSnathanw 	(void)kill(getpid(), SIGABRT);
8668bcff70bSnathanw 
8678bcff70bSnathanw 	_exit(1);
8688bcff70bSnathanw }
869df277271Snathanw 
870df277271Snathanw 
871df277271Snathanw void
8720e6c93b9Sdrochner pthread__errorfunc(const char *file, int line, const char *function,
8730e6c93b9Sdrochner 		   const char *msg)
874df277271Snathanw {
875df277271Snathanw 	char buf[1024];
8760172694eSnathanw 	size_t len;
877df277271Snathanw 
8780172694eSnathanw 	if (pthread__diagassert == 0)
879df277271Snathanw 		return;
880df277271Snathanw 
881df277271Snathanw 	/*
882df277271Snathanw 	 * snprintf should not acquire any locks, or we could
883df277271Snathanw 	 * end up deadlocked if the assert caller held locks.
884df277271Snathanw 	 */
885df277271Snathanw 	len = snprintf(buf, 1024,
8860172694eSnathanw 	    "%s: Error detected by libpthread: %s.\n"
8870172694eSnathanw 	    "Detected by file \"%s\", line %d%s%s%s.\n"
8880172694eSnathanw 	    "See pthread(3) for information.\n",
8890172694eSnathanw 	    getprogname(), msg, file, line,
890df277271Snathanw 	    function ? ", function \"" : "",
891df277271Snathanw 	    function ? function : "",
8920172694eSnathanw 	    function ? "\"" : "");
893df277271Snathanw 
8940172694eSnathanw 	if (pthread__diagassert & DIAGASSERT_STDERR)
8950c967901Snathanw 		_sys_write(STDERR_FILENO, buf, len);
8960172694eSnathanw 
8970172694eSnathanw 	if (pthread__diagassert & DIAGASSERT_SYSLOG)
8980172694eSnathanw 		syslog(LOG_DEBUG | LOG_USER, "%s", buf);
8990172694eSnathanw 
9000172694eSnathanw 	if (pthread__diagassert & DIAGASSERT_ABORT) {
901df277271Snathanw 		(void)kill(getpid(), SIGABRT);
902df277271Snathanw 		_exit(1);
903df277271Snathanw 	}
904df277271Snathanw }
9051ac6a89bSad 
906fe9718acSad /*
907ded26025Sad  * Thread park/unpark operations.  The kernel operations are
908ded26025Sad  * modelled after a brief description from "Multithreading in
909ded26025Sad  * the Solaris Operating Environment":
910fe9718acSad  *
911fe9718acSad  * http://www.sun.com/software/whitepapers/solaris9/multithread.pdf
912fe9718acSad  */
913fe9718acSad 
9141ac6a89bSad #define	OOPS(msg)			\
915858097f9Schristos     pthread__errorfunc(__FILE__, __LINE__, __func__, msg)
9161ac6a89bSad 
9171ac6a89bSad int
9181ac6a89bSad pthread__park(pthread_t self, pthread_spin_t *lock,
919*50fa8db4Sad 	      pthread_queue_t *queue, const struct timespec *abstime,
920*50fa8db4Sad 	      int cancelpt, const void *hint)
9211ac6a89bSad {
9221ac6a89bSad 	int rv;
9231ac6a89bSad 
924792cc0e1Sad 	SDPRINTF(("(pthread__park %p) queue %p enter\n", self, queue));
9251ac6a89bSad 
926ded26025Sad 	/*
927ded26025Sad 	 * Wait until we are awoken by a pending unpark operation,
928ded26025Sad 	 * a signal, an unpark posted after we have gone asleep,
929ded26025Sad 	 * or an expired timeout.
930*50fa8db4Sad 	 *
931*50fa8db4Sad 	 * It is fine to test the value of both pt_sleepobj and
932*50fa8db4Sad 	 * pt_sleeponq without holding any locks, because:
933*50fa8db4Sad 	 *
934*50fa8db4Sad 	 * o Only the blocking thread (this thread) ever sets them
935*50fa8db4Sad 	 *   to a non-NULL value.
936*50fa8db4Sad 	 *
937*50fa8db4Sad 	 * o Other threads may set them NULL, but if they do so they
938*50fa8db4Sad 	 *   must also make this thread return from _lwp_park.
939*50fa8db4Sad 	 *
940*50fa8db4Sad 	 * o _lwp_park, _lwp_unpark and _lwp_unpark_all are system
941*50fa8db4Sad 	 *   calls and all make use of spinlocks in the kernel.  So
942*50fa8db4Sad 	 *   these system calls act as full memory barriers, and will
943*50fa8db4Sad 	 *   ensure that the calling CPU's store buffers are drained.
944*50fa8db4Sad 	 *   In combination with the spinlock release before unpark,
945*50fa8db4Sad 	 *   this means that modification of pt_sleepobj/onq by another
946*50fa8db4Sad 	 *   thread will become globally visible before that thread
947*50fa8db4Sad 	 *   schedules an unpark operation on this thread.
948ded26025Sad 	 */
949ded26025Sad 	rv = 0;
950*50fa8db4Sad 	while (self->pt_sleepobj != NULL && rv == 0) {
951a5070151Sad 		if (_lwp_park(abstime, NULL, hint) != 0) {
952ded26025Sad 			switch (rv = errno) {
9531ac6a89bSad 			case EINTR:
9541ac6a89bSad 			case EALREADY:
955ded26025Sad 				rv = 0;
956ded26025Sad 				break;
957ded26025Sad 			case ETIMEDOUT:
9581ac6a89bSad 				break;
9591ac6a89bSad 			default:
9601ac6a89bSad 				OOPS("_lwp_park failed");
9611ac6a89bSad 				SDPRINTF(("(pthread__park %p) syscall rv=%d\n",
9621ac6a89bSad 				    self, rv));
9631ac6a89bSad 				break;
9641ac6a89bSad 			}
965ded26025Sad 		}
9660c61b6a6Sad 		/* Check for cancellation. */
9670c61b6a6Sad 		if (cancelpt && self->pt_cancel) {
9680c61b6a6Sad 			/*
9690c61b6a6Sad 			 * Ensure visibility of the correct value.
9700c61b6a6Sad 			 * _lwp_park/_lwp_wakeup also provide a
9710c61b6a6Sad 			 * barrier.
9720c61b6a6Sad 			 */
973*50fa8db4Sad 			pthread_spinlock(self, &self->pt_lock);
9740c61b6a6Sad 			if (self->pt_cancel)
9750c61b6a6Sad 				rv = EINTR;
976*50fa8db4Sad 			pthread_spinunlock(self, &self->pt_lock);
9770c61b6a6Sad 		}
978*50fa8db4Sad 	}
9791ac6a89bSad 
980ded26025Sad 	/*
981ded26025Sad 	 * If we have been awoken early but are still on the queue,
982*50fa8db4Sad 	 * then remove ourself.  Again, it's safe to do the test
983*50fa8db4Sad 	 * without holding any locks.
984ded26025Sad 	 */
985792cc0e1Sad 	if (self->pt_sleeponq) {
986*50fa8db4Sad 		pthread_spinlock(self, lock);
987*50fa8db4Sad 		if (self->pt_sleeponq) {
9881ac6a89bSad 			PTQ_REMOVE(queue, self, pt_sleep);
9891ac6a89bSad 			self->pt_sleepobj = NULL;
990ded26025Sad 			self->pt_sleeponq = 0;
991792cc0e1Sad 		}
992*50fa8db4Sad 		pthread_spinunlock(self, lock);
993*50fa8db4Sad 	}
9941ac6a89bSad 
995792cc0e1Sad 	SDPRINTF(("(pthread__park %p) queue %p exit\n", self, queue));
9961ac6a89bSad 
9971ac6a89bSad 	return rv;
9981ac6a89bSad }
9991ac6a89bSad 
10001ac6a89bSad void
1001792cc0e1Sad pthread__unpark(pthread_t self, pthread_spin_t *lock,
1002*50fa8db4Sad 		pthread_queue_t *queue, pthread_t target)
10031ac6a89bSad {
10041ac6a89bSad 	int rv;
10051ac6a89bSad 
10060c61b6a6Sad 	if (target == NULL) {
10070c61b6a6Sad 		pthread_spinunlock(self, lock);
10080c61b6a6Sad 		return;
10090c61b6a6Sad 	}
10100c61b6a6Sad 
1011792cc0e1Sad 	SDPRINTF(("(pthread__unpark %p) queue %p target %p\n",
1012792cc0e1Sad 	    self, queue, target));
10131ac6a89bSad 
1014ded26025Sad 	/*
1015ded26025Sad 	 * Easy: the thread has already been removed from
1016ded26025Sad 	 * the queue, so just awaken it.
1017ded26025Sad 	 */
10181ac6a89bSad 	target->pt_sleepobj = NULL;
1019ded26025Sad 	target->pt_sleeponq = 0;
1020*50fa8db4Sad 
1021*50fa8db4Sad 	/*
1022*50fa8db4Sad 	 * Releasing the spinlock serves as a store barrier,
1023*50fa8db4Sad 	 * which ensures that all our modifications are visible
1024*50fa8db4Sad 	 * to the thread in pthread__park() before the unpark
1025*50fa8db4Sad 	 * operation is set in motion.
1026*50fa8db4Sad 	 */
10271ac6a89bSad 	pthread_spinunlock(self, lock);
1028792cc0e1Sad 	rv = _lwp_unpark(target->pt_lid, queue);
10291ac6a89bSad 
10301ac6a89bSad 	if (rv != 0 && errno != EALREADY && errno != EINTR) {
10311ac6a89bSad 		SDPRINTF(("(pthread__unpark %p) syscall rv=%d\n",
10321ac6a89bSad 		    self, rv));
10331ac6a89bSad 		OOPS("_lwp_unpark failed");
10341ac6a89bSad 	}
10351ac6a89bSad }
10361ac6a89bSad 
10371ac6a89bSad void
1038792cc0e1Sad pthread__unpark_all(pthread_t self, pthread_spin_t *lock,
1039*50fa8db4Sad 		    pthread_queue_t *queue)
10401ac6a89bSad {
1041ded26025Sad 	lwpid_t waiters[PTHREAD__UNPARK_MAX];
104267513ce0Sad 	ssize_t n, rv;
1043ded26025Sad 	pthread_t thread, next;
1044ded26025Sad 
1045ded26025Sad 	if (PTQ_EMPTY(queue)) {
1046ded26025Sad 		pthread_spinunlock(self, lock);
1047ded26025Sad 		return;
1048ded26025Sad 	}
1049ded26025Sad 
1050ded26025Sad 	/*
1051ded26025Sad 	 * First, clear all sleepobj pointers, since we can release the
1052ded26025Sad 	 * spin lock before awkening everybody, and must synchronise with
1053ded26025Sad 	 * pthread__park().
1054ded26025Sad 	 */
1055ded26025Sad 	PTQ_FOREACH(thread, queue, pt_sleep) {
1056ded26025Sad 		thread->pt_sleepobj = NULL;
1057792cc0e1Sad 		if (thread == PTQ_NEXT(thread, pt_sleep))
1058792cc0e1Sad 			OOPS("unpark: thread linked to self");
1059ded26025Sad 	}
10601ac6a89bSad 
10611ac6a89bSad 	for (;;) {
1062ded26025Sad 		thread = PTQ_FIRST(queue);
1063ded26025Sad 		for (n = 0; n < pthread__unpark_max && thread != NULL;
1064ded26025Sad 		    thread = next) {
1065ded26025Sad 			/*
1066ded26025Sad 			 * If the sleepobj pointer is non-NULL, it
1067ded26025Sad 			 * means one of two things:
1068ded26025Sad 			 *
1069ded26025Sad 			 * o The thread has awoken early, spun
1070ded26025Sad 			 *   through application code and is
1071ded26025Sad 			 *   once more asleep on this object.
1072ded26025Sad 			 *
1073ded26025Sad 			 * o This is a new thread that has blocked
1074ded26025Sad 			 *   on the object after we have released
1075ded26025Sad 			 *   the interlock in this loop.
1076ded26025Sad 			 *
1077ded26025Sad 			 * In both cases we shouldn't remove the
1078ded26025Sad 			 * thread from the queue.
1079ded26025Sad 			 */
1080ded26025Sad 			next = PTQ_NEXT(thread, pt_sleep);
1081ded26025Sad 			if (thread->pt_sleepobj != NULL)
1082ded26025Sad 			    	continue;
1083ded26025Sad 			thread->pt_sleeponq = 0;
1084ded26025Sad 			waiters[n++] = thread->pt_lid;
10851ac6a89bSad 			PTQ_REMOVE(queue, thread, pt_sleep);
1086792cc0e1Sad 			SDPRINTF(("(pthread__unpark_all %p) queue %p "
1087792cc0e1Sad 			    "unpark %p\n", self, queue, thread));
10881ac6a89bSad 		}
1089ded26025Sad 
1090*50fa8db4Sad 		/*
1091*50fa8db4Sad 		 * Releasing the spinlock serves as a store barrier,
1092*50fa8db4Sad 		 * which ensures that all our modifications are visible
1093*50fa8db4Sad 		 * to the thread in pthread__park() before the unpark
1094*50fa8db4Sad 		 * operation is set in motion.
1095*50fa8db4Sad 		 */
10961ac6a89bSad 		pthread_spinunlock(self, lock);
1097ded26025Sad 		switch (n) {
10981ac6a89bSad 		case 0:
10991ac6a89bSad 			return;
11001ac6a89bSad 		case 1:
1101792cc0e1Sad 			rv = (ssize_t)_lwp_unpark(waiters[0], queue);
11021ac6a89bSad 			if (rv != 0 && errno != EALREADY && errno != EINTR) {
11031ac6a89bSad 				OOPS("_lwp_unpark failed");
11041ac6a89bSad 				SDPRINTF(("(pthread__unpark_all %p) "
11051ac6a89bSad 				    "syscall rv=%d\n", self, rv));
11061ac6a89bSad 			}
11071ac6a89bSad 			return;
11081ac6a89bSad 		default:
1109*50fa8db4Sad 			rv = _lwp_unpark_all(waiters, (size_t)n, queue);
11101ac6a89bSad 			if (rv != 0 && errno != EINTR) {
11111ac6a89bSad 				OOPS("_lwp_unpark_all failed");
11121ac6a89bSad 				SDPRINTF(("(pthread__unpark_all %p) "
11131ac6a89bSad 				    "syscall rv=%d\n", self, rv));
11141ac6a89bSad 			}
11151ac6a89bSad 			break;
11161ac6a89bSad 		}
11171ac6a89bSad 		pthread_spinlock(self, lock);
11181ac6a89bSad 	}
11191ac6a89bSad }
11201ac6a89bSad 
11211ac6a89bSad #undef	OOPS
1122