xref: /netbsd-src/lib/libpthread/pthread.c (revision ae29c597e8dda1eeac9c34ed754aaa2afcbee798)
1*ae29c597Shannken /*	$NetBSD: pthread.c,v 1.185 2024/06/08 08:01:49 hannken Exp $	*/
2c62a74e6Sthorpej 
3c62a74e6Sthorpej /*-
4edf01486Sad  * Copyright (c) 2001, 2002, 2003, 2006, 2007, 2008, 2020
5edf01486Sad  *     The NetBSD Foundation, Inc.
6c62a74e6Sthorpej  * All rights reserved.
7c62a74e6Sthorpej  *
8c62a74e6Sthorpej  * This code is derived from software contributed to The NetBSD Foundation
91ac6a89bSad  * by Nathan J. Williams and Andrew Doran.
10c62a74e6Sthorpej  *
11c62a74e6Sthorpej  * Redistribution and use in source and binary forms, with or without
12c62a74e6Sthorpej  * modification, are permitted provided that the following conditions
13c62a74e6Sthorpej  * are met:
14c62a74e6Sthorpej  * 1. Redistributions of source code must retain the above copyright
15c62a74e6Sthorpej  *    notice, this list of conditions and the following disclaimer.
16c62a74e6Sthorpej  * 2. Redistributions in binary form must reproduce the above copyright
17c62a74e6Sthorpej  *    notice, this list of conditions and the following disclaimer in the
18c62a74e6Sthorpej  *    documentation and/or other materials provided with the distribution.
19c62a74e6Sthorpej  *
20c62a74e6Sthorpej  * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
21c62a74e6Sthorpej  * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
22c62a74e6Sthorpej  * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
23c62a74e6Sthorpej  * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
24c62a74e6Sthorpej  * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
25c62a74e6Sthorpej  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
26c62a74e6Sthorpej  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
27c62a74e6Sthorpej  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
28c62a74e6Sthorpej  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
29c62a74e6Sthorpej  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
30c62a74e6Sthorpej  * POSSIBILITY OF SUCH DAMAGE.
31c62a74e6Sthorpej  */
32c62a74e6Sthorpej 
33f043c0fbSlukem #include <sys/cdefs.h>
34*ae29c597Shannken __RCSID("$NetBSD: pthread.c,v 1.185 2024/06/08 08:01:49 hannken Exp $");
359e287199Sad 
369e287199Sad #define	__EXPOSE_STACK	1
379e287199Sad 
387adb4107Sriastradh /* Need to use libc-private names for atomic operations. */
397adb4107Sriastradh #include "../../common/lib/libc/atomic/atomic_op_namespace.h"
407adb4107Sriastradh 
419e287199Sad #include <sys/param.h>
42a5644095Sjoerg #include <sys/exec_elf.h>
439e287199Sad #include <sys/mman.h>
440645d95bSjoerg #include <sys/lwp.h>
4566ac2ffaSad #include <sys/lwpctl.h>
462bf5f9dbSdsl #include <sys/resource.h>
475f391f4aSjoerg #include <sys/sysctl.h>
48aad59997Sjoerg #include <sys/tls.h>
495f391f4aSjoerg #include <uvm/uvm_param.h>
50f043c0fbSlukem 
51a5644095Sjoerg #include <assert.h>
52a5644095Sjoerg #include <dlfcn.h>
53c62a74e6Sthorpej #include <err.h>
54c62a74e6Sthorpej #include <errno.h>
55c62a74e6Sthorpej #include <lwp.h>
56c62a74e6Sthorpej #include <signal.h>
578bcff70bSnathanw #include <stdio.h>
58c62a74e6Sthorpej #include <stdlib.h>
59d79b47c3Srmind #include <stddef.h>
60c62a74e6Sthorpej #include <string.h>
610172694eSnathanw #include <syslog.h>
62c62a74e6Sthorpej #include <ucontext.h>
638bcff70bSnathanw #include <unistd.h>
64c62a74e6Sthorpej #include <sched.h>
659e287199Sad 
66e5678be8Sjoerg #include "atexit.h"
67c62a74e6Sthorpej #include "pthread.h"
68c62a74e6Sthorpej #include "pthread_int.h"
69082d249aSpooka #include "pthread_makelwp.h"
7071d484f9Schristos #include "reentrant.h"
71c62a74e6Sthorpej 
72558a0c73Sjoerg __BEGIN_DECLS
73558a0c73Sjoerg void _malloc_thread_cleanup(void) __weak;
74558a0c73Sjoerg __END_DECLS
75558a0c73Sjoerg 
769583eeb2Sad pthread_rwlock_t pthread__alltree_lock = PTHREAD_RWLOCK_INITIALIZER;
77d79b47c3Srmind static rb_tree_t	pthread__alltree;
789583eeb2Sad 
79d79b47c3Srmind static signed int	pthread__cmp(void *, const void *, const void *);
80d79b47c3Srmind 
81d79b47c3Srmind static const rb_tree_ops_t pthread__alltree_ops = {
82d79b47c3Srmind 	.rbto_compare_nodes = pthread__cmp,
83d79b47c3Srmind 	.rbto_compare_key = pthread__cmp,
84d79b47c3Srmind 	.rbto_node_offset = offsetof(struct __pthread_st, pt_alltree),
85d79b47c3Srmind 	.rbto_context = NULL
86d79b47c3Srmind };
879583eeb2Sad 
8861cac435Sad static void	pthread__create_tramp(void *);
8950fa8db4Sad static void	pthread__initthread(pthread_t);
90b8833ff5Sad static void	pthread__scrubthread(pthread_t, char *, int);
919e287199Sad static void	pthread__initmain(pthread_t *);
92989565f8Sad static void	pthread__reap(pthread_t);
93c62a74e6Sthorpej 
9415e9cec1Sad void	pthread__init(void);
9515e9cec1Sad 
96c62a74e6Sthorpej int pthread__started;
9771d484f9Schristos int __uselibcstub = 1;
98f4fd6b79Sad pthread_mutex_t pthread__deadqueue_lock = PTHREAD_MUTEX_INITIALIZER;
9950fa8db4Sad pthread_queue_t pthread__deadqueue;
100f1b2c1c4Sad pthread_queue_t pthread__allqueue;
101c62a74e6Sthorpej 
102c62a74e6Sthorpej static pthread_attr_t pthread_default_attr;
10366ac2ffaSad static lwpctl_t pthread__dummy_lwpctl = { .lc_curcpu = LWPCTL_CPU_NONE };
104c62a74e6Sthorpej 
1050172694eSnathanw enum {
1060172694eSnathanw 	DIAGASSERT_ABORT =	1<<0,
1070172694eSnathanw 	DIAGASSERT_STDERR =	1<<1,
1080172694eSnathanw 	DIAGASSERT_SYSLOG =	1<<2
1090172694eSnathanw };
110df277271Snathanw 
111beaa63b6Sad static int pthread__diagassert;
112df277271Snathanw 
113c94f5a91Sad int pthread__concurrency;
114c94f5a91Sad int pthread__nspins;
115bc77394cSad size_t pthread__unpark_max = PTHREAD__UNPARK_MAX;
1160f48379fSchristos int pthread__dbg;	/* set by libpthread_dbg if active */
117f2f10664Scl 
1189e287199Sad /*
1199e287199Sad  * We have to initialize the pthread_stack* variables here because
1209e287199Sad  * mutexes are used before pthread_init() and thus pthread__initmain()
1219e287199Sad  * are called.  Since mutexes only save the stack pointer and not a
1229e287199Sad  * pointer to the thread data, it is safe to change the mapping from
1239e287199Sad  * stack pointer to thread data afterwards.
1249e287199Sad  */
125a5644095Sjoerg size_t	pthread__stacksize;
1265f391f4aSjoerg size_t	pthread__guardsize;
127a5644095Sjoerg size_t	pthread__pagesize;
128841339f0Smanu static struct __pthread_st *pthread__main;
129841339f0Smanu static size_t __pthread_st_size;
1309e287199Sad 
131f782e995Sdrochner int _sys___sigprocmask14(int, const sigset_t *, sigset_t *);
132f782e995Sdrochner 
133c62a74e6Sthorpej __strong_alias(__libc_thr_self,pthread_self)
1347dc01dbfSthorpej __strong_alias(__libc_thr_create,pthread_create)
1357dc01dbfSthorpej __strong_alias(__libc_thr_exit,pthread_exit)
136c62a74e6Sthorpej __strong_alias(__libc_thr_errno,pthread__errno)
1379e5c8705Snathanw __strong_alias(__libc_thr_setcancelstate,pthread_setcancelstate)
138095b25e7Sdrochner __strong_alias(__libc_thr_equal,pthread_equal)
13915e9cec1Sad __strong_alias(__libc_thr_init,pthread__init)
140c62a74e6Sthorpej 
141c62a74e6Sthorpej /*
142c62a74e6Sthorpej  * Static library kludge.  Place a reference to a symbol any library
143c62a74e6Sthorpej  * file which does not already have a reference here.
144c62a74e6Sthorpej  */
145c62a74e6Sthorpej extern int pthread__cancel_stub_binder;
146c62a74e6Sthorpej 
147c62a74e6Sthorpej void *pthread__static_lib_binder[] = {
148c62a74e6Sthorpej 	&pthread__cancel_stub_binder,
149c62a74e6Sthorpej 	pthread_cond_init,
150c62a74e6Sthorpej 	pthread_mutex_init,
151c62a74e6Sthorpej 	pthread_rwlock_init,
152c62a74e6Sthorpej 	pthread_barrier_init,
153c62a74e6Sthorpej 	pthread_key_create,
154bd9a18b7Snathanw 	pthread_setspecific,
155c62a74e6Sthorpej };
156c62a74e6Sthorpej 
1572bcb8bf1Sad #define	NHASHLOCK	64
1582bcb8bf1Sad 
1592bcb8bf1Sad static union hashlock {
1602bcb8bf1Sad 	pthread_mutex_t	mutex;
1612bcb8bf1Sad 	char		pad[64];
1622bcb8bf1Sad } hashlocks[NHASHLOCK] __aligned(64);
1632bcb8bf1Sad 
164858ee362Sjoerg static void
pthread__prefork(void)165858ee362Sjoerg pthread__prefork(void)
166858ee362Sjoerg {
167858ee362Sjoerg 	pthread_mutex_lock(&pthread__deadqueue_lock);
168858ee362Sjoerg }
169858ee362Sjoerg 
170858ee362Sjoerg static void
pthread__fork_parent(void)171858ee362Sjoerg pthread__fork_parent(void)
172858ee362Sjoerg {
173858ee362Sjoerg 	pthread_mutex_unlock(&pthread__deadqueue_lock);
174858ee362Sjoerg }
175858ee362Sjoerg 
176858ee362Sjoerg static void
pthread__fork_child(void)177858ee362Sjoerg pthread__fork_child(void)
178858ee362Sjoerg {
179858ee362Sjoerg 	struct __pthread_st *self = pthread__self();
180858ee362Sjoerg 
181858ee362Sjoerg 	pthread_mutex_init(&pthread__deadqueue_lock, NULL);
182858ee362Sjoerg 
183858ee362Sjoerg 	/* lwpctl state is not copied across fork. */
184858ee362Sjoerg 	if (_lwp_ctl(LWPCTL_FEATURE_CURCPU, &self->pt_lwpctl)) {
185858ee362Sjoerg 		err(EXIT_FAILURE, "_lwp_ctl");
186858ee362Sjoerg 	}
187858ee362Sjoerg 	self->pt_lid = _lwp_self();
188858ee362Sjoerg }
189858ee362Sjoerg 
190c62a74e6Sthorpej /*
191c62a74e6Sthorpej  * This needs to be started by the library loading code, before main()
192c62a74e6Sthorpej  * gets to run, for various things that use the state of the initial thread
193c62a74e6Sthorpej  * to work properly (thread-specific data is an application-visible example;
194c62a74e6Sthorpej  * spinlock counts for mutexes is an internal example).
195c62a74e6Sthorpej  */
196c62a74e6Sthorpej void
pthread__init(void)19715e9cec1Sad pthread__init(void)
198c62a74e6Sthorpej {
199c62a74e6Sthorpej 	pthread_t first;
2000172694eSnathanw 	char *p;
2015f391f4aSjoerg 	int mib[2];
2025f391f4aSjoerg 	unsigned int value;
203bc77394cSad 	ssize_t slen;
2045f391f4aSjoerg 	size_t len;
205c62a74e6Sthorpej 	extern int __isthreaded;
206c62a74e6Sthorpej 
207841339f0Smanu 	/*
208841339f0Smanu 	 * Allocate pthread_keys descriptors before
209984bb2b3Smsaitoh 	 * resetting __uselibcstub because otherwise
210841339f0Smanu 	 * malloc() will call pthread_keys_create()
211841339f0Smanu 	 * while pthread_keys descriptors are not
212841339f0Smanu 	 * yet allocated.
213841339f0Smanu 	 */
214331480e6Skamil 	pthread__main = pthread_tsd_init(&__pthread_st_size);
215cb27e655Schristos 	if (pthread__main == NULL)
216cb27e655Schristos 		err(EXIT_FAILURE, "Cannot allocate pthread storage");
217841339f0Smanu 
21871d484f9Schristos 	__uselibcstub = 0;
21971d484f9Schristos 
220a5644095Sjoerg 	pthread__pagesize = (size_t)sysconf(_SC_PAGESIZE);
221284dc1a8Schristos 	pthread__concurrency = (int)sysconf(_SC_NPROCESSORS_CONF);
222c3f8e2eeSad 
2235f391f4aSjoerg 	mib[0] = CTL_VM;
2245f391f4aSjoerg 	mib[1] = VM_THREAD_GUARD_SIZE;
2255f391f4aSjoerg 	len = sizeof(value);
2265f391f4aSjoerg 	if (sysctl(mib, __arraycount(mib), &value, &len, NULL, 0) == 0)
2275f391f4aSjoerg 		pthread__guardsize = value;
2285f391f4aSjoerg 	else
2295f391f4aSjoerg 		pthread__guardsize = pthread__pagesize;
2305f391f4aSjoerg 
231c62a74e6Sthorpej 	/* Initialize locks first; they're needed elsewhere. */
232b8833ff5Sad 	pthread__lockprim_init();
233bc77394cSad 	for (int i = 0; i < NHASHLOCK; i++) {
2342bcb8bf1Sad 		pthread_mutex_init(&hashlocks[i].mutex, NULL);
2352bcb8bf1Sad 	}
236f2f10664Scl 
237b8833ff5Sad 	/* Fetch parameters. */
238bc77394cSad 	slen = _lwp_unpark_all(NULL, 0, NULL);
239bc77394cSad 	if (slen < 0)
240841339f0Smanu 		err(EXIT_FAILURE, "_lwp_unpark_all");
241bc77394cSad 	if ((size_t)slen < pthread__unpark_max)
242bc77394cSad 		pthread__unpark_max = slen;
243c62a74e6Sthorpej 
244c62a74e6Sthorpej 	/* Basic data structure setup */
245c62a74e6Sthorpej 	pthread_attr_init(&pthread_default_attr);
246f1b2c1c4Sad 	PTQ_INIT(&pthread__allqueue);
247c62a74e6Sthorpej 	PTQ_INIT(&pthread__deadqueue);
248d79b47c3Srmind 
249d79b47c3Srmind 	rb_tree_init(&pthread__alltree, &pthread__alltree_ops);
2509e287199Sad 
251c62a74e6Sthorpej 	/* Create the thread structure corresponding to main() */
252c62a74e6Sthorpej 	pthread__initmain(&first);
25350fa8db4Sad 	pthread__initthread(first);
254b8833ff5Sad 	pthread__scrubthread(first, NULL, 0);
2551ac6a89bSad 
2561ac6a89bSad 	first->pt_lid = _lwp_self();
257f1b2c1c4Sad 	PTQ_INSERT_HEAD(&pthread__allqueue, first, pt_allq);
258d79b47c3Srmind 	(void)rb_tree_insert_node(&pthread__alltree, first);
259c62a74e6Sthorpej 
2607de9da97Sad 	if (_lwp_ctl(LWPCTL_FEATURE_CURCPU, &first->pt_lwpctl) != 0) {
261841339f0Smanu 		err(EXIT_FAILURE, "_lwp_ctl");
2627de9da97Sad 	}
2637de9da97Sad 
264c62a74e6Sthorpej 	/* Start subsystems */
265c62a74e6Sthorpej 	PTHREAD_MD_INIT
266c62a74e6Sthorpej 
26715e9cec1Sad 	for (p = pthread__getenv("PTHREAD_DIAGASSERT"); p && *p; p++) {
2680172694eSnathanw 		switch (*p) {
2690172694eSnathanw 		case 'a':
2700172694eSnathanw 			pthread__diagassert |= DIAGASSERT_ABORT;
2710172694eSnathanw 			break;
2720172694eSnathanw 		case 'A':
2730172694eSnathanw 			pthread__diagassert &= ~DIAGASSERT_ABORT;
2740172694eSnathanw 			break;
2750172694eSnathanw 		case 'e':
2760172694eSnathanw 			pthread__diagassert |= DIAGASSERT_STDERR;
2770172694eSnathanw 			break;
2780172694eSnathanw 		case 'E':
2790172694eSnathanw 			pthread__diagassert &= ~DIAGASSERT_STDERR;
2800172694eSnathanw 			break;
2810172694eSnathanw 		case 'l':
2820172694eSnathanw 			pthread__diagassert |= DIAGASSERT_SYSLOG;
2830172694eSnathanw 			break;
2840172694eSnathanw 		case 'L':
2850172694eSnathanw 			pthread__diagassert &= ~DIAGASSERT_SYSLOG;
2860172694eSnathanw 			break;
287df277271Snathanw 		}
2880172694eSnathanw 	}
2890172694eSnathanw 
290331480e6Skamil 	/* Tell libc that we're here and it should role-play accordingly. */
291858ee362Sjoerg 	pthread_atfork(pthread__prefork, pthread__fork_parent, pthread__fork_child);
292331480e6Skamil 	__isthreaded = 1;
293c62a74e6Sthorpej }
294c62a74e6Sthorpej 
295c62a74e6Sthorpej /* General-purpose thread data structure sanitization. */
29650fa8db4Sad /* ARGSUSED */
29750fa8db4Sad static void
pthread__initthread(pthread_t t)29850fa8db4Sad pthread__initthread(pthread_t t)
299c62a74e6Sthorpej {
300c62a74e6Sthorpej 
30115e9cec1Sad 	t->pt_self = t;
302c62a74e6Sthorpej 	t->pt_magic = PT_MAGIC;
303c3f8e2eeSad 	t->pt_sleepobj = NULL;
304b8833ff5Sad 	t->pt_havespecific = 0;
30566ac2ffaSad 	t->pt_lwpctl = &pthread__dummy_lwpctl;
3061ac6a89bSad 
30715e9cec1Sad 	memcpy(&t->pt_lockops, pthread__lock_ops, sizeof(t->pt_lockops));
308f4fd6b79Sad 	pthread_mutex_init(&t->pt_lock, NULL);
309c62a74e6Sthorpej 	PTQ_INIT(&t->pt_cleanup_stack);
310c62a74e6Sthorpej }
311c62a74e6Sthorpej 
312b8833ff5Sad static void
pthread__scrubthread(pthread_t t,char * name,int flags)313b8833ff5Sad pthread__scrubthread(pthread_t t, char *name, int flags)
314b8833ff5Sad {
315b8833ff5Sad 
316b8833ff5Sad 	t->pt_state = PT_STATE_RUNNING;
317b8833ff5Sad 	t->pt_exitval = NULL;
318b8833ff5Sad 	t->pt_flags = flags;
319b8833ff5Sad 	t->pt_cancel = 0;
320b8833ff5Sad 	t->pt_errno = 0;
321b8833ff5Sad 	t->pt_name = name;
322b8833ff5Sad 	t->pt_lid = 0;
323b8833ff5Sad }
324b8833ff5Sad 
325a5644095Sjoerg static int
pthread__getstack(pthread_t newthread,const pthread_attr_t * attr)326d3660af7Sjoerg pthread__getstack(pthread_t newthread, const pthread_attr_t *attr)
327a5644095Sjoerg {
328d3660af7Sjoerg 	void *stackbase, *stackbase2, *redzone;
3291d34190eSjoerg 	size_t stacksize, guardsize;
330d3660af7Sjoerg 	bool allocated;
331a5644095Sjoerg 
332344a2311Sjoerg 	if (attr != NULL) {
333344a2311Sjoerg 		pthread_attr_getstack(attr, &stackbase, &stacksize);
33420941a42Sriastradh 		if (stackbase == NULL)
3355f391f4aSjoerg 			pthread_attr_getguardsize(attr, &guardsize);
33620941a42Sriastradh 		else
33720941a42Sriastradh 			guardsize = 0;
338344a2311Sjoerg 	} else {
339344a2311Sjoerg 		stackbase = NULL;
340344a2311Sjoerg 		stacksize = 0;
3415f391f4aSjoerg 		guardsize = pthread__guardsize;
342344a2311Sjoerg 	}
343344a2311Sjoerg 	if (stacksize == 0)
344344a2311Sjoerg 		stacksize = pthread__stacksize;
345344a2311Sjoerg 
346d3660af7Sjoerg 	if (newthread->pt_stack_allocated) {
347e917deeeSdrochner 		if (stackbase == NULL &&
3485f391f4aSjoerg 		    newthread->pt_stack.ss_size == stacksize &&
3495f391f4aSjoerg 		    newthread->pt_guardsize == guardsize)
350d3660af7Sjoerg 			return 0;
351d3660af7Sjoerg 		stackbase2 = newthread->pt_stack.ss_sp;
352ac02e870Skamil #ifndef __MACHINE_STACK_GROWS_UP
353d3660af7Sjoerg 		stackbase2 = (char *)stackbase2 - newthread->pt_guardsize;
354d3660af7Sjoerg #endif
355d3660af7Sjoerg 		munmap(stackbase2,
356d3660af7Sjoerg 		    newthread->pt_stack.ss_size + newthread->pt_guardsize);
357d3660af7Sjoerg 		newthread->pt_stack.ss_sp = NULL;
358d3660af7Sjoerg 		newthread->pt_stack.ss_size = 0;
359d3660af7Sjoerg 		newthread->pt_guardsize = 0;
360d3660af7Sjoerg 		newthread->pt_stack_allocated = false;
361d3660af7Sjoerg 	}
362d3660af7Sjoerg 
363d3660af7Sjoerg 	newthread->pt_stack_allocated = false;
364d3660af7Sjoerg 
365344a2311Sjoerg 	if (stackbase == NULL) {
366d3660af7Sjoerg 		stacksize = ((stacksize - 1) | (pthread__pagesize - 1)) + 1;
3675f391f4aSjoerg 		guardsize = ((guardsize - 1) | (pthread__pagesize - 1)) + 1;
3681d34190eSjoerg 		stackbase = mmap(NULL, stacksize + guardsize,
369a5644095Sjoerg 		    PROT_READ|PROT_WRITE, MAP_ANON|MAP_PRIVATE, -1, (off_t)0);
370a5644095Sjoerg 		if (stackbase == MAP_FAILED)
371a5644095Sjoerg 			return ENOMEM;
372d3660af7Sjoerg 		allocated = true;
3731d34190eSjoerg 	} else {
374d3660af7Sjoerg 		allocated = false;
375344a2311Sjoerg 	}
376a5644095Sjoerg #ifdef __MACHINE_STACK_GROWS_UP
377d3660af7Sjoerg 	redzone = (char *)stackbase + stacksize;
378d3660af7Sjoerg 	stackbase2 = (char *)stackbase;
379a5644095Sjoerg #else
380a5644095Sjoerg 	redzone = (char *)stackbase;
381d3660af7Sjoerg 	stackbase2 = (char *)stackbase + guardsize;
382a5644095Sjoerg #endif
383d3660af7Sjoerg 	if (allocated && guardsize &&
384d3660af7Sjoerg 	    mprotect(redzone, guardsize, PROT_NONE) == -1) {
3851d34190eSjoerg 		munmap(stackbase, stacksize + guardsize);
386a5644095Sjoerg 		return EPERM;
387a5644095Sjoerg 	}
388d3660af7Sjoerg 	newthread->pt_stack.ss_size = stacksize;
389d3660af7Sjoerg 	newthread->pt_stack.ss_sp = stackbase2;
390d3660af7Sjoerg 	newthread->pt_guardsize = guardsize;
391d3660af7Sjoerg 	newthread->pt_stack_allocated = allocated;
392a5644095Sjoerg 	return 0;
393a5644095Sjoerg }
394c62a74e6Sthorpej 
395c62a74e6Sthorpej int
pthread_create(pthread_t * thread,const pthread_attr_t * attr,void * (* startfunc)(void *),void * arg)396c62a74e6Sthorpej pthread_create(pthread_t *thread, const pthread_attr_t *attr,
397c62a74e6Sthorpej 	    void *(*startfunc)(void *), void *arg)
398c62a74e6Sthorpej {
399d9adedd7Sad 	pthread_t newthread;
400c62a74e6Sthorpej 	pthread_attr_t nattr;
401b33971b9Sthorpej 	struct pthread_attr_private *p;
4023ca3d0b1Schristos 	char * volatile name;
403ed964af1Sad 	unsigned long flag;
404aad59997Sjoerg 	void *private_area;
405ed964af1Sad 	int ret;
406c62a74e6Sthorpej 
40771d484f9Schristos 	if (__predict_false(__uselibcstub)) {
40871d484f9Schristos     		pthread__errorfunc(__FILE__, __LINE__, __func__,
40971d484f9Schristos 		    "pthread_create() requires linking with -lpthread");
41071d484f9Schristos 		return __libc_thr_create_stub(thread, attr, startfunc, arg);
41171d484f9Schristos 	}
41271d484f9Schristos 
413c62a74e6Sthorpej 	if (attr == NULL)
414c62a74e6Sthorpej 		nattr = pthread_default_attr;
415e81f9f17Sdrochner 	else if (attr->pta_magic == PT_ATTR_MAGIC)
416c62a74e6Sthorpej 		nattr = *attr;
417c62a74e6Sthorpej 	else
418c62a74e6Sthorpej 		return EINVAL;
419c62a74e6Sthorpej 
420e3d96c2fSriastradh 	if (!pthread__started) {
421e3d96c2fSriastradh 		/*
422e3d96c2fSriastradh 		 * Force the _lwp_park symbol to be resolved before we
423e3d96c2fSriastradh 		 * begin any activity that might rely on concurrent
424e3d96c2fSriastradh 		 * wakeups.
425e3d96c2fSriastradh 		 *
426e3d96c2fSriastradh 		 * This is necessary because rtld itself uses _lwp_park
427e3d96c2fSriastradh 		 * and _lwp_unpark internally for its own locking: If
428e3d96c2fSriastradh 		 * we wait to resolve _lwp_park until there is an
429e3d96c2fSriastradh 		 * _lwp_unpark from another thread pending in the
430e3d96c2fSriastradh 		 * current lwp (for example, pthread_mutex_unlock or
431e3d96c2fSriastradh 		 * pthread_cond_signal), rtld's internal use of
432e3d96c2fSriastradh 		 * _lwp_park might consume the pending unpark.  The
433e3d96c2fSriastradh 		 * result is a deadlock where libpthread and rtld have
434e3d96c2fSriastradh 		 * both correctly used _lwp_park and _lwp_unpark for
435e3d96c2fSriastradh 		 * themselves, but rtld has consumed the wakeup meant
436e3d96c2fSriastradh 		 * for libpthread so it is lost to libpthread.
437e3d96c2fSriastradh 		 *
438e3d96c2fSriastradh 		 * For the very first thread, before pthread__started
439e3d96c2fSriastradh 		 * is set to true, pthread__self()->pt_lid should have
440e3d96c2fSriastradh 		 * been initialized in pthread__init by the time we get
441e3d96c2fSriastradh 		 * here to the correct lid so we go to sleep and wake
442e3d96c2fSriastradh 		 * ourselves at the same time as a no-op.
443e3d96c2fSriastradh 		 */
444e3d96c2fSriastradh 		_lwp_park(CLOCK_REALTIME, 0, NULL, pthread__self()->pt_lid,
445e3d96c2fSriastradh 		    NULL, NULL);
446e3d96c2fSriastradh 	}
447e3d96c2fSriastradh 
448f3cc99aeSjoerg 	pthread__started = 1;
449f3cc99aeSjoerg 
450b33971b9Sthorpej 	/* Fetch misc. attributes from the attr structure. */
451508a50acSnathanw 	name = NULL;
452508a50acSnathanw 	if ((p = nattr.pta_private) != NULL)
453508a50acSnathanw 		if (p->ptap_name[0] != '\0')
454b33971b9Sthorpej 			if ((name = strdup(p->ptap_name)) == NULL)
455b33971b9Sthorpej 				return ENOMEM;
456c62a74e6Sthorpej 
457a014cf23Sad 	newthread = NULL;
458c62a74e6Sthorpej 
459b8833ff5Sad 	/*
460b8833ff5Sad 	 * Try to reclaim a dead thread.
461b8833ff5Sad 	 */
462a014cf23Sad 	if (!PTQ_EMPTY(&pthread__deadqueue)) {
463f4fd6b79Sad 		pthread_mutex_lock(&pthread__deadqueue_lock);
46485ddadbfSchristos 		PTQ_FOREACH(newthread, &pthread__deadqueue, pt_deadq) {
465*ae29c597Shannken 			/* Still running? */
466*ae29c597Shannken 			if (_lwp_kill(newthread->pt_lid, 0) == -1 &&
467*ae29c597Shannken 			    errno == ESRCH)
46885ddadbfSchristos 				break;
46950fa8db4Sad 		}
47085ddadbfSchristos 		if (newthread)
47185ddadbfSchristos 			PTQ_REMOVE(&pthread__deadqueue, newthread, pt_deadq);
472f4fd6b79Sad 		pthread_mutex_unlock(&pthread__deadqueue_lock);
473928f301bSjoerg #if defined(__HAVE_TLS_VARIANT_I) || defined(__HAVE_TLS_VARIANT_II)
474928f301bSjoerg 		if (newthread && newthread->pt_tls) {
475928f301bSjoerg 			_rtld_tls_free(newthread->pt_tls);
476928f301bSjoerg 			newthread->pt_tls = NULL;
477928f301bSjoerg 		}
478928f301bSjoerg #endif
479a014cf23Sad 	}
480a014cf23Sad 
481b8833ff5Sad 	/*
482b8833ff5Sad 	 * If necessary set up a stack, allocate space for a pthread_st,
483b8833ff5Sad 	 * and initialize it.
484b8833ff5Sad 	 */
4854cdc2ed8Syamt 	if (newthread == NULL) {
486841339f0Smanu 		newthread = calloc(1, __pthread_st_size);
487a5644095Sjoerg 		if (newthread == NULL) {
488b7559f85Schristos 			free(name);
489a5644095Sjoerg 			return ENOMEM;
490a5644095Sjoerg 		}
491d3660af7Sjoerg 		newthread->pt_stack_allocated = false;
492a5644095Sjoerg 
493d3660af7Sjoerg 		if (pthread__getstack(newthread, attr)) {
494a5644095Sjoerg 			free(newthread);
495a5644095Sjoerg 			free(name);
496a5644095Sjoerg 			return ENOMEM;
497c62a74e6Sthorpej 		}
498b33971b9Sthorpej 
499928f301bSjoerg #if defined(__HAVE_TLS_VARIANT_I) || defined(__HAVE_TLS_VARIANT_II)
500928f301bSjoerg 		newthread->pt_tls = NULL;
501928f301bSjoerg #endif
502b8833ff5Sad 
503b8833ff5Sad 		/* Add to list of all threads. */
5049583eeb2Sad 		pthread_rwlock_wrlock(&pthread__alltree_lock);
505f1b2c1c4Sad 		PTQ_INSERT_TAIL(&pthread__allqueue, newthread, pt_allq);
506d79b47c3Srmind 		(void)rb_tree_insert_node(&pthread__alltree, newthread);
5079583eeb2Sad 		pthread_rwlock_unlock(&pthread__alltree_lock);
508b8833ff5Sad 
509b8833ff5Sad 		/* Will be reset by the thread upon exit. */
510b8833ff5Sad 		pthread__initthread(newthread);
511d3660af7Sjoerg 	} else {
512d3660af7Sjoerg 		if (pthread__getstack(newthread, attr)) {
513d3660af7Sjoerg 			pthread_mutex_lock(&pthread__deadqueue_lock);
514d3660af7Sjoerg 			PTQ_INSERT_TAIL(&pthread__deadqueue, newthread, pt_deadq);
515d3660af7Sjoerg 			pthread_mutex_unlock(&pthread__deadqueue_lock);
516d3660af7Sjoerg 			return ENOMEM;
517d3660af7Sjoerg 		}
518ed964af1Sad 	}
519ed964af1Sad 
520b8833ff5Sad 	/*
521b8833ff5Sad 	 * Create the new LWP.
522b8833ff5Sad 	 */
523b8833ff5Sad 	pthread__scrubthread(newthread, name, nattr.pta_flags);
52461cac435Sad 	newthread->pt_func = startfunc;
52561cac435Sad 	newthread->pt_arg = arg;
526aad59997Sjoerg #if defined(__HAVE_TLS_VARIANT_I) || defined(__HAVE_TLS_VARIANT_II)
527aad59997Sjoerg 	private_area = newthread->pt_tls = _rtld_tls_allocate();
528aad59997Sjoerg 	newthread->pt_tls->tcb_pthread = newthread;
529aad59997Sjoerg #else
530aad59997Sjoerg 	private_area = newthread;
531aad59997Sjoerg #endif
532aad59997Sjoerg 
533cd1754abSad 	flag = 0;
534cbd43ffaSad 	if ((newthread->pt_flags & PT_FLAG_SUSPENDED) != 0 ||
5350e006eebSad 	    (nattr.pta_flags & PT_FLAG_EXPLICIT_SCHED) != 0)
536ded26025Sad 		flag |= LWP_SUSPENDED;
537cd1754abSad 	if ((newthread->pt_flags & PT_FLAG_DETACHED) != 0)
538cd1754abSad 		flag |= LWP_DETACHED;
539082d249aSpooka 
540082d249aSpooka 	ret = pthread__makelwp(pthread__create_tramp, newthread, private_area,
541082d249aSpooka 	    newthread->pt_stack.ss_sp, newthread->pt_stack.ss_size,
542082d249aSpooka 	    flag, &newthread->pt_lid);
5431ac6a89bSad 	if (ret != 0) {
544b0ce37c2Sdrochner 		ret = errno;
5450dcf29f9Srmind 		pthread_mutex_lock(&newthread->pt_lock);
5460dcf29f9Srmind 		/* Will unlock and free name. */
5470dcf29f9Srmind 		pthread__reap(newthread);
5481ac6a89bSad 		return ret;
5491ac6a89bSad 	}
5501ac6a89bSad 
5510e006eebSad 	if ((nattr.pta_flags & PT_FLAG_EXPLICIT_SCHED) != 0) {
552cbd43ffaSad 		if (p != NULL) {
553cbd43ffaSad 			(void)pthread_setschedparam(newthread, p->ptap_policy,
554cbd43ffaSad 			    &p->ptap_sp);
555cbd43ffaSad 		}
556cbd43ffaSad 		if ((newthread->pt_flags & PT_FLAG_SUSPENDED) == 0) {
557cbd43ffaSad 			(void)_lwp_continue(newthread->pt_lid);
558cbd43ffaSad 		}
559cbd43ffaSad 	}
560cbd43ffaSad 
561c62a74e6Sthorpej 	*thread = newthread;
562c62a74e6Sthorpej 
563c62a74e6Sthorpej 	return 0;
564c62a74e6Sthorpej }
565c62a74e6Sthorpej 
566c62a74e6Sthorpej 
56767f518f4Sjoerg __dead static void
pthread__create_tramp(void * cookie)56861cac435Sad pthread__create_tramp(void *cookie)
569c62a74e6Sthorpej {
57061cac435Sad 	pthread_t self;
571c62a74e6Sthorpej 	void *retval;
57298c521ffSmrg 	void *junk __unused;
573c62a74e6Sthorpej 
57461cac435Sad 	self = cookie;
57566ac2ffaSad 
57650fa8db4Sad 	/*
57750fa8db4Sad 	 * Throw away some stack in a feeble attempt to reduce cache
57850fa8db4Sad 	 * thrash.  May help for SMT processors.  XXX We should not
57950fa8db4Sad 	 * be allocating stacks on fixed 2MB boundaries.  Needs a
58061cac435Sad 	 * thread register or decent thread local storage.
58150fa8db4Sad 	 */
58298c521ffSmrg 	junk = alloca(((unsigned)self->pt_lid & 7) << 8);
583f63239c2Sad 
584f63239c2Sad 	if (self->pt_name != NULL) {
585f63239c2Sad 		pthread_mutex_lock(&self->pt_lock);
586f63239c2Sad 		if (self->pt_name != NULL)
58766ac2ffaSad 			(void)_lwp_setname(0, self->pt_name);
588f63239c2Sad 		pthread_mutex_unlock(&self->pt_lock);
589f63239c2Sad 	}
59050fa8db4Sad 
591eceac52fSad 	if (_lwp_ctl(LWPCTL_FEATURE_CURCPU, &self->pt_lwpctl)) {
592841339f0Smanu 		err(EXIT_FAILURE, "_lwp_ctl");
593eceac52fSad 	}
59466ac2ffaSad 
59561cac435Sad 	retval = (*self->pt_func)(self->pt_arg);
596c62a74e6Sthorpej 
597c62a74e6Sthorpej 	pthread_exit(retval);
598c62a74e6Sthorpej 
599143f5a27Schristos 	/*NOTREACHED*/
600143f5a27Schristos 	pthread__abort();
601c62a74e6Sthorpej }
602c62a74e6Sthorpej 
60338b1c6f4Schristos int
pthread_suspend_np(pthread_t thread)60438b1c6f4Schristos pthread_suspend_np(pthread_t thread)
60538b1c6f4Schristos {
606ba70e96aSchs 	pthread_t self;
607ba70e96aSchs 
60820668e14Skamil 	pthread__error(EINVAL, "Invalid thread",
60920668e14Skamil 	    thread->pt_magic == PT_MAGIC);
61020668e14Skamil 
611ba70e96aSchs 	self = pthread__self();
61238b1c6f4Schristos 	if (self == thread) {
61338b1c6f4Schristos 		return EDEADLK;
61438b1c6f4Schristos 	}
615d9adedd7Sad 	if (pthread__find(thread) != 0)
616ba70e96aSchs 		return ESRCH;
61740724da2Sad 	if (_lwp_suspend(thread->pt_lid) == 0)
61840724da2Sad 		return 0;
61940724da2Sad 	return errno;
62038b1c6f4Schristos }
62138b1c6f4Schristos 
62238b1c6f4Schristos int
pthread_resume_np(pthread_t thread)62338b1c6f4Schristos pthread_resume_np(pthread_t thread)
62438b1c6f4Schristos {
62538b1c6f4Schristos 
62620668e14Skamil 	pthread__error(EINVAL, "Invalid thread",
62720668e14Skamil 	    thread->pt_magic == PT_MAGIC);
62820668e14Skamil 
629d9adedd7Sad 	if (pthread__find(thread) != 0)
630ba70e96aSchs 		return ESRCH;
63140724da2Sad 	if (_lwp_continue(thread->pt_lid) == 0)
63240724da2Sad 		return 0;
63340724da2Sad 	return errno;
63438b1c6f4Schristos }
63538b1c6f4Schristos 
636c62a74e6Sthorpej void
pthread_exit(void * retval)637c62a74e6Sthorpej pthread_exit(void *retval)
638c62a74e6Sthorpej {
63996b5a26dSnathanw 	pthread_t self;
640c62a74e6Sthorpej 	struct pt_clean_t *cleanup;
641c62a74e6Sthorpej 
64271d484f9Schristos 	if (__predict_false(__uselibcstub)) {
64371d484f9Schristos 		__libc_thr_exit_stub(retval);
64471d484f9Schristos 		goto out;
64571d484f9Schristos 	}
64671d484f9Schristos 
647c62a74e6Sthorpej 	self = pthread__self();
648c62a74e6Sthorpej 
649c62a74e6Sthorpej 	/* Disable cancellability. */
650f4fd6b79Sad 	pthread_mutex_lock(&self->pt_lock);
651c62a74e6Sthorpej 	self->pt_flags |= PT_FLAG_CS_DISABLED;
65266fcc1ceSnathanw 	self->pt_cancel = 0;
65330140ed2Sad 	pthread_mutex_unlock(&self->pt_lock);
654c62a74e6Sthorpej 
655c62a74e6Sthorpej 	/* Call any cancellation cleanup handlers */
656989565f8Sad 	if (!PTQ_EMPTY(&self->pt_cleanup_stack)) {
657c62a74e6Sthorpej 		while (!PTQ_EMPTY(&self->pt_cleanup_stack)) {
658c62a74e6Sthorpej 			cleanup = PTQ_FIRST(&self->pt_cleanup_stack);
659c62a74e6Sthorpej 			PTQ_REMOVE(&self->pt_cleanup_stack, cleanup, ptc_next);
660c62a74e6Sthorpej 			(*cleanup->ptc_cleanup)(cleanup->ptc_arg);
661c62a74e6Sthorpej 		}
662989565f8Sad 	}
663c62a74e6Sthorpej 
664e5678be8Sjoerg 	__cxa_thread_run_atexit();
665e5678be8Sjoerg 
666c62a74e6Sthorpej 	/* Perform cleanup of thread-specific data */
667c62a74e6Sthorpej 	pthread__destroy_tsd(self);
668c62a74e6Sthorpej 
669558a0c73Sjoerg 	if (_malloc_thread_cleanup)
670558a0c73Sjoerg 		_malloc_thread_cleanup();
671558a0c73Sjoerg 
672047ca71bSad 	/*
673047ca71bSad 	 * Signal our exit.  Our stack and pthread_t won't be reused until
674047ca71bSad 	 * pthread_create() can see from kernel info that this LWP is gone.
675047ca71bSad 	 */
67630140ed2Sad 	pthread_mutex_lock(&self->pt_lock);
677c62a74e6Sthorpej 	self->pt_exitval = retval;
6786b2b9c62Syamt 	if (self->pt_flags & PT_FLAG_DETACHED) {
679cd1754abSad 		/* pthread__reap() will drop the lock. */
680cd1754abSad 		pthread__reap(self);
6811ac6a89bSad 		_lwp_exit();
682c62a74e6Sthorpej 	} else {
6836b2b9c62Syamt 		self->pt_state = PT_STATE_ZOMBIE;
684f4fd6b79Sad 		pthread_mutex_unlock(&self->pt_lock);
685b33971b9Sthorpej 		/* Note: name will be freed by the joiner. */
6861ac6a89bSad 		_lwp_exit();
687c62a74e6Sthorpej 	}
688c62a74e6Sthorpej 
68971d484f9Schristos out:
690143f5a27Schristos 	/*NOTREACHED*/
691143f5a27Schristos 	pthread__abort();
692c62a74e6Sthorpej 	exit(1);
693c62a74e6Sthorpej }
694c62a74e6Sthorpej 
695c62a74e6Sthorpej 
696c62a74e6Sthorpej int
pthread_join(pthread_t thread,void ** valptr)697c62a74e6Sthorpej pthread_join(pthread_t thread, void **valptr)
698c62a74e6Sthorpej {
699c62a74e6Sthorpej 	pthread_t self;
700c62a74e6Sthorpej 
70120668e14Skamil 	pthread__error(EINVAL, "Invalid thread",
70220668e14Skamil 	    thread->pt_magic == PT_MAGIC);
70320668e14Skamil 
704c62a74e6Sthorpej 	self = pthread__self();
705c62a74e6Sthorpej 
706d9adedd7Sad 	if (pthread__find(thread) != 0)
707c62a74e6Sthorpej 		return ESRCH;
708c62a74e6Sthorpej 
709c62a74e6Sthorpej 	if (thread == self)
710c62a74e6Sthorpej 		return EDEADLK;
711c62a74e6Sthorpej 
712cd1754abSad 	/* IEEE Std 1003.1 says pthread_join() never returns EINTR. */
713989565f8Sad 	for (;;) {
714cd1754abSad 		pthread__testcancel(self);
715cd1754abSad 		if (_lwp_wait(thread->pt_lid, NULL) == 0)
716989565f8Sad 			break;
717cd1754abSad 		if (errno != EINTR)
718cd1754abSad 			return errno;
719c94f5a91Sad 	}
720622bbc50Sad 
721cd1754abSad 	/*
722cd1754abSad 	 * Don't test for cancellation again.  The spec is that if
723cd1754abSad 	 * cancelled, pthread_join() must not have succeeded.
724cd1754abSad 	 */
725cd1754abSad 	pthread_mutex_lock(&thread->pt_lock);
726cd1754abSad 	if (thread->pt_state != PT_STATE_ZOMBIE) {
727cd1754abSad 		pthread__errorfunc(__FILE__, __LINE__, __func__,
728cd1754abSad 		    "not a zombie");
729c94f5a91Sad  	}
7301ac6a89bSad 	if (valptr != NULL)
731ded26025Sad 		*valptr = thread->pt_exitval;
732cd1754abSad 
733989565f8Sad 	/* pthread__reap() will drop the lock. */
734989565f8Sad 	pthread__reap(thread);
735c94f5a91Sad 	return 0;
736c62a74e6Sthorpej }
737c62a74e6Sthorpej 
738989565f8Sad static void
pthread__reap(pthread_t thread)739989565f8Sad pthread__reap(pthread_t thread)
740989565f8Sad {
741989565f8Sad 	char *name;
742989565f8Sad 
743989565f8Sad 	name = thread->pt_name;
744989565f8Sad 	thread->pt_name = NULL;
745989565f8Sad 	thread->pt_state = PT_STATE_DEAD;
746989565f8Sad 	pthread_mutex_unlock(&thread->pt_lock);
747989565f8Sad 
748989565f8Sad 	pthread_mutex_lock(&pthread__deadqueue_lock);
749989565f8Sad 	PTQ_INSERT_HEAD(&pthread__deadqueue, thread, pt_deadq);
750989565f8Sad 	pthread_mutex_unlock(&pthread__deadqueue_lock);
751989565f8Sad 
752989565f8Sad 	if (name != NULL)
753989565f8Sad 		free(name);
754989565f8Sad }
755c62a74e6Sthorpej 
756c62a74e6Sthorpej int
pthread_equal(pthread_t t1,pthread_t t2)757c62a74e6Sthorpej pthread_equal(pthread_t t1, pthread_t t2)
758c62a74e6Sthorpej {
75920668e14Skamil 
76071d484f9Schristos 	if (__predict_false(__uselibcstub))
76171d484f9Schristos 		return __libc_thr_equal_stub(t1, t2);
762c62a74e6Sthorpej 
763f66ccdf0Skamil 	pthread__error(0, "Invalid thread",
764f66ccdf0Skamil 	    (t1 != NULL) && (t1->pt_magic == PT_MAGIC));
76520668e14Skamil 
766f66ccdf0Skamil 	pthread__error(0, "Invalid thread",
767f66ccdf0Skamil 	    (t2 != NULL) && (t2->pt_magic == PT_MAGIC));
76820668e14Skamil 
769c62a74e6Sthorpej 	/* Nothing special here. */
770c62a74e6Sthorpej 	return (t1 == t2);
771c62a74e6Sthorpej }
772c62a74e6Sthorpej 
773c62a74e6Sthorpej 
774c62a74e6Sthorpej int
pthread_detach(pthread_t thread)775c62a74e6Sthorpej pthread_detach(pthread_t thread)
776c62a74e6Sthorpej {
777cd1754abSad 	int error;
778c62a74e6Sthorpej 
77920668e14Skamil 	pthread__error(EINVAL, "Invalid thread",
78020668e14Skamil 	    thread->pt_magic == PT_MAGIC);
78120668e14Skamil 
782d9adedd7Sad 	if (pthread__find(thread) != 0)
783c62a74e6Sthorpej 		return ESRCH;
784c62a74e6Sthorpej 
785f4fd6b79Sad 	pthread_mutex_lock(&thread->pt_lock);
786cd1754abSad 	if ((thread->pt_flags & PT_FLAG_DETACHED) != 0) {
787cd1754abSad 		error = EINVAL;
788cd1754abSad 	} else {
789cd1754abSad 		error = _lwp_detach(thread->pt_lid);
790cd1754abSad 		if (error == 0)
7911296e850Sad 			thread->pt_flags |= PT_FLAG_DETACHED;
792cd1754abSad 		else
793cd1754abSad 			error = errno;
794cd1754abSad 	}
795989565f8Sad 	if (thread->pt_state == PT_STATE_ZOMBIE) {
796989565f8Sad 		/* pthread__reap() will drop the lock. */
797989565f8Sad 		pthread__reap(thread);
798cd1754abSad 	} else
799f4fd6b79Sad 		pthread_mutex_unlock(&thread->pt_lock);
800cd1754abSad 	return error;
801c62a74e6Sthorpej }
802c62a74e6Sthorpej 
803c62a74e6Sthorpej 
804c62a74e6Sthorpej int
pthread_getname_np(pthread_t thread,char * name,size_t len)805b33971b9Sthorpej pthread_getname_np(pthread_t thread, char *name, size_t len)
806c62a74e6Sthorpej {
807c62a74e6Sthorpej 
80820668e14Skamil 	pthread__error(EINVAL, "Invalid thread",
80920668e14Skamil 	    thread->pt_magic == PT_MAGIC);
81020668e14Skamil 
811d9adedd7Sad 	if (pthread__find(thread) != 0)
812b33971b9Sthorpej 		return ESRCH;
813b33971b9Sthorpej 
814f4fd6b79Sad 	pthread_mutex_lock(&thread->pt_lock);
815b33971b9Sthorpej 	if (thread->pt_name == NULL)
816b33971b9Sthorpej 		name[0] = '\0';
817b33971b9Sthorpej 	else
818b33971b9Sthorpej 		strlcpy(name, thread->pt_name, len);
819f4fd6b79Sad 	pthread_mutex_unlock(&thread->pt_lock);
820c62a74e6Sthorpej 
821c62a74e6Sthorpej 	return 0;
822c62a74e6Sthorpej }
823c62a74e6Sthorpej 
824c62a74e6Sthorpej 
825c62a74e6Sthorpej int
pthread_setname_np(pthread_t thread,const char * name,void * arg)826b33971b9Sthorpej pthread_setname_np(pthread_t thread, const char *name, void *arg)
827b33971b9Sthorpej {
828b33971b9Sthorpej 	char *oldname, *cp, newname[PTHREAD_MAX_NAMELEN_NP];
829b33971b9Sthorpej 	int namelen;
830b33971b9Sthorpej 
83120668e14Skamil 	pthread__error(EINVAL, "Invalid thread",
83220668e14Skamil 	    thread->pt_magic == PT_MAGIC);
83320668e14Skamil 
834d9adedd7Sad 	if (pthread__find(thread) != 0)
835b33971b9Sthorpej 		return ESRCH;
836b33971b9Sthorpej 
837b33971b9Sthorpej 	namelen = snprintf(newname, sizeof(newname), name, arg);
838b33971b9Sthorpej 	if (namelen >= PTHREAD_MAX_NAMELEN_NP)
839b33971b9Sthorpej 		return EINVAL;
840b33971b9Sthorpej 
841b33971b9Sthorpej 	cp = strdup(newname);
842b33971b9Sthorpej 	if (cp == NULL)
843b33971b9Sthorpej 		return ENOMEM;
844b33971b9Sthorpej 
845f4fd6b79Sad 	pthread_mutex_lock(&thread->pt_lock);
846b33971b9Sthorpej 	oldname = thread->pt_name;
847b33971b9Sthorpej 	thread->pt_name = cp;
848f63239c2Sad 	(void)_lwp_setname(thread->pt_lid, cp);
849f4fd6b79Sad 	pthread_mutex_unlock(&thread->pt_lock);
850b33971b9Sthorpej 
851b33971b9Sthorpej 	if (oldname != NULL)
852b33971b9Sthorpej 		free(oldname);
853b33971b9Sthorpej 
854b33971b9Sthorpej 	return 0;
855b33971b9Sthorpej }
856b33971b9Sthorpej 
857b33971b9Sthorpej 
858c62a74e6Sthorpej pthread_t
pthread_self(void)859c62a74e6Sthorpej pthread_self(void)
860c62a74e6Sthorpej {
86171d484f9Schristos 	if (__predict_false(__uselibcstub))
86271d484f9Schristos 		return (pthread_t)__libc_thr_self_stub();
863c62a74e6Sthorpej 
864c62a74e6Sthorpej 	return pthread__self();
865c62a74e6Sthorpej }
866c62a74e6Sthorpej 
867c62a74e6Sthorpej 
868c62a74e6Sthorpej int
pthread_cancel(pthread_t thread)869c62a74e6Sthorpej pthread_cancel(pthread_t thread)
870c62a74e6Sthorpej {
871c62a74e6Sthorpej 
87220668e14Skamil 	pthread__error(EINVAL, "Invalid thread",
87320668e14Skamil 	    thread->pt_magic == PT_MAGIC);
87420668e14Skamil 
875d9adedd7Sad 	if (pthread__find(thread) != 0)
876ba70e96aSchs 		return ESRCH;
877f4fd6b79Sad 	pthread_mutex_lock(&thread->pt_lock);
8781ac6a89bSad 	thread->pt_flags |= PT_FLAG_CS_PENDING;
8791ac6a89bSad 	if ((thread->pt_flags & PT_FLAG_CS_DISABLED) == 0) {
8801ac6a89bSad 		thread->pt_cancel = 1;
881f4fd6b79Sad 		pthread_mutex_unlock(&thread->pt_lock);
8821ac6a89bSad 		_lwp_wakeup(thread->pt_lid);
8831ac6a89bSad 	} else
884f4fd6b79Sad 		pthread_mutex_unlock(&thread->pt_lock);
885c62a74e6Sthorpej 
886c62a74e6Sthorpej 	return 0;
887c62a74e6Sthorpej }
888c62a74e6Sthorpej 
889c62a74e6Sthorpej 
890c62a74e6Sthorpej int
pthread_setcancelstate(int state,int * oldstate)891c62a74e6Sthorpej pthread_setcancelstate(int state, int *oldstate)
892c62a74e6Sthorpej {
893c62a74e6Sthorpej 	pthread_t self;
8940878df5dSnathanw 	int retval;
895c62a74e6Sthorpej 
89671d484f9Schristos 	if (__predict_false(__uselibcstub))
89771d484f9Schristos 		return __libc_thr_setcancelstate_stub(state, oldstate);
89871d484f9Schristos 
899c62a74e6Sthorpej 	self = pthread__self();
9000878df5dSnathanw 	retval = 0;
901c62a74e6Sthorpej 
902f4fd6b79Sad 	pthread_mutex_lock(&self->pt_lock);
90350fa8db4Sad 
904c62a74e6Sthorpej 	if (oldstate != NULL) {
9050878df5dSnathanw 		if (self->pt_flags & PT_FLAG_CS_DISABLED)
906c62a74e6Sthorpej 			*oldstate = PTHREAD_CANCEL_DISABLE;
907c62a74e6Sthorpej 		else
908c62a74e6Sthorpej 			*oldstate = PTHREAD_CANCEL_ENABLE;
909c62a74e6Sthorpej 	}
910c62a74e6Sthorpej 
9110878df5dSnathanw 	if (state == PTHREAD_CANCEL_DISABLE) {
9120878df5dSnathanw 		self->pt_flags |= PT_FLAG_CS_DISABLED;
9130878df5dSnathanw 		if (self->pt_cancel) {
9140878df5dSnathanw 			self->pt_flags |= PT_FLAG_CS_PENDING;
9150878df5dSnathanw 			self->pt_cancel = 0;
9160878df5dSnathanw 		}
9170878df5dSnathanw 	} else if (state == PTHREAD_CANCEL_ENABLE) {
9180878df5dSnathanw 		self->pt_flags &= ~PT_FLAG_CS_DISABLED;
919c62a74e6Sthorpej 		/*
920c62a74e6Sthorpej 		 * If a cancellation was requested while cancellation
921c62a74e6Sthorpej 		 * was disabled, note that fact for future
922c62a74e6Sthorpej 		 * cancellation tests.
923c62a74e6Sthorpej 		 */
9240878df5dSnathanw 		if (self->pt_flags & PT_FLAG_CS_PENDING) {
925c62a74e6Sthorpej 			self->pt_cancel = 1;
926c62a74e6Sthorpej 			/* This is not a deferred cancellation point. */
9270878df5dSnathanw 			if (self->pt_flags & PT_FLAG_CS_ASYNC) {
928f4fd6b79Sad 				pthread_mutex_unlock(&self->pt_lock);
929989565f8Sad 				pthread__cancelled();
930c62a74e6Sthorpej 			}
9310878df5dSnathanw 		}
932c62a74e6Sthorpej 	} else
9330878df5dSnathanw 		retval = EINVAL;
934c62a74e6Sthorpej 
935f4fd6b79Sad 	pthread_mutex_unlock(&self->pt_lock);
93650fa8db4Sad 
9370878df5dSnathanw 	return retval;
938c62a74e6Sthorpej }
939c62a74e6Sthorpej 
940c62a74e6Sthorpej 
941c62a74e6Sthorpej int
pthread_setcanceltype(int type,int * oldtype)942c62a74e6Sthorpej pthread_setcanceltype(int type, int *oldtype)
943c62a74e6Sthorpej {
944c62a74e6Sthorpej 	pthread_t self;
9450878df5dSnathanw 	int retval;
946c62a74e6Sthorpej 
947c62a74e6Sthorpej 	self = pthread__self();
9480878df5dSnathanw 	retval = 0;
9490878df5dSnathanw 
950f4fd6b79Sad 	pthread_mutex_lock(&self->pt_lock);
951c62a74e6Sthorpej 
952c62a74e6Sthorpej 	if (oldtype != NULL) {
9530878df5dSnathanw 		if (self->pt_flags & PT_FLAG_CS_ASYNC)
954c62a74e6Sthorpej 			*oldtype = PTHREAD_CANCEL_ASYNCHRONOUS;
955c62a74e6Sthorpej 		else
956c62a74e6Sthorpej 			*oldtype = PTHREAD_CANCEL_DEFERRED;
957c62a74e6Sthorpej 	}
958c62a74e6Sthorpej 
959c62a74e6Sthorpej 	if (type == PTHREAD_CANCEL_ASYNCHRONOUS) {
9600878df5dSnathanw 		self->pt_flags |= PT_FLAG_CS_ASYNC;
9610878df5dSnathanw 		if (self->pt_cancel) {
962f4fd6b79Sad 			pthread_mutex_unlock(&self->pt_lock);
963989565f8Sad 			pthread__cancelled();
9640878df5dSnathanw 		}
965c62a74e6Sthorpej 	} else if (type == PTHREAD_CANCEL_DEFERRED)
9660878df5dSnathanw 		self->pt_flags &= ~PT_FLAG_CS_ASYNC;
967c62a74e6Sthorpej 	else
9680878df5dSnathanw 		retval = EINVAL;
969c62a74e6Sthorpej 
970f4fd6b79Sad 	pthread_mutex_unlock(&self->pt_lock);
97150fa8db4Sad 
9720878df5dSnathanw 	return retval;
973c62a74e6Sthorpej }
974c62a74e6Sthorpej 
975c62a74e6Sthorpej 
976c62a74e6Sthorpej void
pthread_testcancel(void)977989565f8Sad pthread_testcancel(void)
978c62a74e6Sthorpej {
979c62a74e6Sthorpej 	pthread_t self;
980c62a74e6Sthorpej 
981c62a74e6Sthorpej 	self = pthread__self();
982c62a74e6Sthorpej 	if (self->pt_cancel)
983989565f8Sad 		pthread__cancelled();
984c62a74e6Sthorpej }
985c62a74e6Sthorpej 
986c62a74e6Sthorpej 
987c62a74e6Sthorpej /*
988c62a74e6Sthorpej  * POSIX requires that certain functions return an error rather than
989c62a74e6Sthorpej  * invoking undefined behavior even when handed completely bogus
990d79b47c3Srmind  * pthread_t values, e.g. stack garbage.
991c62a74e6Sthorpej  */
992c62a74e6Sthorpej int
pthread__find(pthread_t id)993d9adedd7Sad pthread__find(pthread_t id)
994c62a74e6Sthorpej {
995c62a74e6Sthorpej 	pthread_t target;
996d79b47c3Srmind 	int error;
997c62a74e6Sthorpej 
9989583eeb2Sad 	pthread_rwlock_rdlock(&pthread__alltree_lock);
999d79b47c3Srmind 	target = rb_tree_find_node(&pthread__alltree, id);
1000d79b47c3Srmind 	error = (target && target->pt_state != PT_STATE_DEAD) ? 0 : ESRCH;
10019583eeb2Sad 	pthread_rwlock_unlock(&pthread__alltree_lock);
1002c62a74e6Sthorpej 
1003d79b47c3Srmind 	return error;
1004c62a74e6Sthorpej }
1005c62a74e6Sthorpej 
1006c62a74e6Sthorpej 
1007c62a74e6Sthorpej void
pthread__testcancel(pthread_t self)1008c62a74e6Sthorpej pthread__testcancel(pthread_t self)
1009c62a74e6Sthorpej {
1010c62a74e6Sthorpej 
1011c62a74e6Sthorpej 	if (self->pt_cancel)
1012989565f8Sad 		pthread__cancelled();
1013989565f8Sad }
1014989565f8Sad 
1015989565f8Sad 
1016989565f8Sad void
pthread__cancelled(void)1017989565f8Sad pthread__cancelled(void)
1018989565f8Sad {
1019989565f8Sad 
1020c62a74e6Sthorpej 	pthread_exit(PTHREAD_CANCELED);
1021c62a74e6Sthorpej }
1022c62a74e6Sthorpej 
1023c62a74e6Sthorpej 
1024c62a74e6Sthorpej void
pthread__cleanup_push(void (* cleanup)(void *),void * arg,void * store)1025c62a74e6Sthorpej pthread__cleanup_push(void (*cleanup)(void *), void *arg, void *store)
1026c62a74e6Sthorpej {
1027c62a74e6Sthorpej 	pthread_t self;
1028c62a74e6Sthorpej 	struct pt_clean_t *entry;
1029c62a74e6Sthorpej 
1030c62a74e6Sthorpej 	self = pthread__self();
1031c62a74e6Sthorpej 	entry = store;
1032c62a74e6Sthorpej 	entry->ptc_cleanup = cleanup;
1033c62a74e6Sthorpej 	entry->ptc_arg = arg;
1034c62a74e6Sthorpej 	PTQ_INSERT_HEAD(&self->pt_cleanup_stack, entry, ptc_next);
1035c62a74e6Sthorpej }
1036c62a74e6Sthorpej 
1037c62a74e6Sthorpej 
1038c62a74e6Sthorpej void
pthread__cleanup_pop(int ex,void * store)1039c62a74e6Sthorpej pthread__cleanup_pop(int ex, void *store)
1040c62a74e6Sthorpej {
1041c62a74e6Sthorpej 	pthread_t self;
1042c62a74e6Sthorpej 	struct pt_clean_t *entry;
1043c62a74e6Sthorpej 
1044c62a74e6Sthorpej 	self = pthread__self();
1045c62a74e6Sthorpej 	entry = store;
1046c62a74e6Sthorpej 
1047c62a74e6Sthorpej 	PTQ_REMOVE(&self->pt_cleanup_stack, entry, ptc_next);
1048c62a74e6Sthorpej 	if (ex)
1049c62a74e6Sthorpej 		(*entry->ptc_cleanup)(entry->ptc_arg);
1050c62a74e6Sthorpej }
1051c62a74e6Sthorpej 
1052c62a74e6Sthorpej 
1053783e2f6dSad int *
pthread__errno(void)1054783e2f6dSad pthread__errno(void)
1055783e2f6dSad {
1056783e2f6dSad 	pthread_t self;
1057783e2f6dSad 
105871d484f9Schristos 	if (__predict_false(__uselibcstub)) {
105971d484f9Schristos     		pthread__errorfunc(__FILE__, __LINE__, __func__,
106071d484f9Schristos 		    "pthread__errno() requires linking with -lpthread");
106171d484f9Schristos 		return __libc_thr_errno_stub();
106271d484f9Schristos 	}
106371d484f9Schristos 
1064783e2f6dSad 	self = pthread__self();
1065783e2f6dSad 
1066783e2f6dSad 	return &(self->pt_errno);
1067783e2f6dSad }
1068783e2f6dSad 
10690c967901Snathanw ssize_t	_sys_write(int, const void *, size_t);
10700c967901Snathanw 
10718bcff70bSnathanw void
pthread__assertfunc(const char * file,int line,const char * function,const char * expr)10720e6c93b9Sdrochner pthread__assertfunc(const char *file, int line, const char *function,
10730e6c93b9Sdrochner 		    const char *expr)
10748bcff70bSnathanw {
10758bcff70bSnathanw 	char buf[1024];
10768bcff70bSnathanw 	int len;
10778bcff70bSnathanw 
10788bcff70bSnathanw 	/*
1079a2c7f636Sjoerg 	 * snprintf_ss should not acquire any locks, or we could
10808bcff70bSnathanw 	 * end up deadlocked if the assert caller held locks.
10818bcff70bSnathanw 	 */
1082a2c7f636Sjoerg 	len = snprintf_ss(buf, 1024,
10838bcff70bSnathanw 	    "assertion \"%s\" failed: file \"%s\", line %d%s%s%s\n",
10848bcff70bSnathanw 	    expr, file, line,
10858bcff70bSnathanw 	    function ? ", function \"" : "",
10868bcff70bSnathanw 	    function ? function : "",
10878bcff70bSnathanw 	    function ? "\"" : "");
10888bcff70bSnathanw 
10890c967901Snathanw 	_sys_write(STDERR_FILENO, buf, (size_t)len);
109006d492d1Sad 	(void)raise(SIGABRT);
10918bcff70bSnathanw 	_exit(1);
10928bcff70bSnathanw }
1093df277271Snathanw 
1094df277271Snathanw 
1095df277271Snathanw void
pthread__errorfunc(const char * file,int line,const char * function,const char * msg,...)10960e6c93b9Sdrochner pthread__errorfunc(const char *file, int line, const char *function,
109734a4ae72Sjoerg 		   const char *msg, ...)
1098df277271Snathanw {
1099df277271Snathanw 	char buf[1024];
110034a4ae72Sjoerg 	char buf2[1024];
11010172694eSnathanw 	size_t len;
110234a4ae72Sjoerg 	va_list ap;
1103df277271Snathanw 
11040172694eSnathanw 	if (pthread__diagassert == 0)
1105df277271Snathanw 		return;
1106df277271Snathanw 
110734a4ae72Sjoerg 	va_start(ap, msg);
110834a4ae72Sjoerg 	vsnprintf_ss(buf2, sizeof(buf2), msg, ap);
110934a4ae72Sjoerg 	va_end(ap);
111034a4ae72Sjoerg 
1111df277271Snathanw 	/*
1112a2c7f636Sjoerg 	 * snprintf_ss should not acquire any locks, or we could
1113df277271Snathanw 	 * end up deadlocked if the assert caller held locks.
1114df277271Snathanw 	 */
111534a4ae72Sjoerg 	len = snprintf_ss(buf, sizeof(buf),
11160172694eSnathanw 	    "%s: Error detected by libpthread: %s.\n"
11170172694eSnathanw 	    "Detected by file \"%s\", line %d%s%s%s.\n"
11180172694eSnathanw 	    "See pthread(3) for information.\n",
111934a4ae72Sjoerg 	    getprogname(), buf2, file, line,
1120df277271Snathanw 	    function ? ", function \"" : "",
1121df277271Snathanw 	    function ? function : "",
11220172694eSnathanw 	    function ? "\"" : "");
1123df277271Snathanw 
11240172694eSnathanw 	if (pthread__diagassert & DIAGASSERT_STDERR)
11250c967901Snathanw 		_sys_write(STDERR_FILENO, buf, len);
11260172694eSnathanw 
11270172694eSnathanw 	if (pthread__diagassert & DIAGASSERT_SYSLOG)
11280172694eSnathanw 		syslog(LOG_DEBUG | LOG_USER, "%s", buf);
11290172694eSnathanw 
11300172694eSnathanw 	if (pthread__diagassert & DIAGASSERT_ABORT) {
113134013547Sad 		(void)raise(SIGABRT);
1132df277271Snathanw 		_exit(1);
1133df277271Snathanw 	}
1134df277271Snathanw }
11351ac6a89bSad 
1136fe9718acSad /*
1137ded26025Sad  * Thread park/unpark operations.  The kernel operations are
1138ded26025Sad  * modelled after a brief description from "Multithreading in
1139ded26025Sad  * the Solaris Operating Environment":
1140fe9718acSad  *
1141fe9718acSad  * http://www.sun.com/software/whitepapers/solaris9/multithread.pdf
1142fe9718acSad  */
1143fe9718acSad 
11441ac6a89bSad int
pthread__park(pthread_t self,pthread_mutex_t * lock,pthread_queue_t * queue,const struct timespec * abstime,int cancelpt)11452bcb8bf1Sad pthread__park(pthread_t self, pthread_mutex_t *lock,
114650fa8db4Sad 	      pthread_queue_t *queue, const struct timespec *abstime,
1147bc77394cSad 	      int cancelpt)
11481ac6a89bSad {
1149c3f8e2eeSad 	int rv, error;
11501ac6a89bSad 
11512bcb8bf1Sad 	pthread_mutex_unlock(lock);
115266ac2ffaSad 
115366ac2ffaSad 	/*
1154ded26025Sad 	 * Wait until we are awoken by a pending unpark operation,
1155ded26025Sad 	 * a signal, an unpark posted after we have gone asleep,
1156ded26025Sad 	 * or an expired timeout.
115750fa8db4Sad 	 *
11582bcb8bf1Sad 	 * It is fine to test the value of pt_sleepobj without
11592bcb8bf1Sad 	 * holding any locks, because:
116050fa8db4Sad 	 *
116106d492d1Sad 	 * o Only the blocking thread (this thread) ever sets it
116250fa8db4Sad 	 *   to a non-NULL value.
116350fa8db4Sad 	 *
116406d492d1Sad 	 * o Other threads may set it NULL, but if they do so they
116550fa8db4Sad 	 *   must also make this thread return from _lwp_park.
116650fa8db4Sad 	 *
116750fa8db4Sad 	 * o _lwp_park, _lwp_unpark and _lwp_unpark_all are system
116850fa8db4Sad 	 *   calls and all make use of spinlocks in the kernel.  So
116906d492d1Sad 	 *   these system calls act as full memory barriers.
1170ded26025Sad 	 */
1171ded26025Sad 	rv = 0;
11722bcb8bf1Sad 	do {
1173c3f8e2eeSad 		/*
1174c3f8e2eeSad 		 * If we deferred unparking a thread, arrange to
1175c3f8e2eeSad 		 * have _lwp_park() restart it before blocking.
1176c3f8e2eeSad 		 */
117785d957d4Skre 		error = _lwp_park(CLOCK_REALTIME, TIMER_ABSTIME,
117862e0939eSad 		    __UNCONST(abstime), 0, NULL, NULL);
1179c3f8e2eeSad 		if (error != 0) {
1180ded26025Sad 			switch (rv = errno) {
11811ac6a89bSad 			case EINTR:
11821ac6a89bSad 			case EALREADY:
1183ded26025Sad 				rv = 0;
1184ded26025Sad 				break;
1185ded26025Sad 			case ETIMEDOUT:
11861ac6a89bSad 				break;
11871ac6a89bSad 			default:
118806d492d1Sad 				pthread__errorfunc(__FILE__, __LINE__,
118934a4ae72Sjoerg 				    __func__, "_lwp_park failed: %d", errno);
11901ac6a89bSad 				break;
11911ac6a89bSad 			}
1192ded26025Sad 		}
11930c61b6a6Sad 		/* Check for cancellation. */
1194d9adedd7Sad 		if (cancelpt && self->pt_cancel)
11950c61b6a6Sad 			rv = EINTR;
11962bcb8bf1Sad 	} while (self->pt_sleepobj != NULL && rv == 0);
11971ac6a89bSad 	return rv;
11981ac6a89bSad }
11991ac6a89bSad 
12001ac6a89bSad void
pthread__unpark(pthread_queue_t * queue,pthread_t self,pthread_mutex_t * interlock)12012bcb8bf1Sad pthread__unpark(pthread_queue_t *queue, pthread_t self,
12022bcb8bf1Sad 		pthread_mutex_t *interlock)
12031ac6a89bSad {
12042bcb8bf1Sad 	pthread_t target;
12051ac6a89bSad 
12062bcb8bf1Sad 	target = PTQ_FIRST(queue);
12071ac6a89bSad 	target->pt_sleepobj = NULL;
12082bcb8bf1Sad 	PTQ_REMOVE(queue, target, pt_sleep);
120962e0939eSad 	(void)_lwp_unpark(target->pt_lid, NULL);
1210c3f8e2eeSad }
12111ac6a89bSad 
12121ac6a89bSad void
pthread__unpark_all(pthread_queue_t * queue,pthread_t self,pthread_mutex_t * interlock)12132bcb8bf1Sad pthread__unpark_all(pthread_queue_t *queue, pthread_t self,
12142bcb8bf1Sad 		    pthread_mutex_t *interlock)
12151ac6a89bSad {
121662e0939eSad 	lwpid_t lids[PTHREAD__UNPARK_MAX];
121762e0939eSad 	const size_t mlid = pthread__unpark_max;
12182bcb8bf1Sad 	pthread_t target;
121962e0939eSad 	size_t nlid = 0;
1220ded26025Sad 
12212bcb8bf1Sad 	PTQ_FOREACH(target, queue, pt_sleep) {
122262e0939eSad 		if (nlid == mlid) {
122362e0939eSad 			(void)_lwp_unpark_all(lids, nlid, NULL);
122462e0939eSad 			nlid = 0;
1225ded26025Sad 		}
12262bcb8bf1Sad 		target->pt_sleepobj = NULL;
122762e0939eSad 		lids[nlid++] = target->pt_lid;
12281ac6a89bSad 	}
12292bcb8bf1Sad 	PTQ_INIT(queue);
123062e0939eSad 	if (nlid == 1) {
123162e0939eSad 		(void)_lwp_unpark(lids[0], NULL);
123262e0939eSad 	} else if (nlid > 1) {
123362e0939eSad 		(void)_lwp_unpark_all(lids, nlid, NULL);
123462e0939eSad 	}
12351ac6a89bSad }
12361ac6a89bSad 
12371ac6a89bSad #undef	OOPS
12389e287199Sad 
1239a5644095Sjoerg static void
pthread__initmainstack(void)1240a5644095Sjoerg pthread__initmainstack(void)
12419e287199Sad {
1242a5644095Sjoerg 	struct rlimit slimit;
1243a5644095Sjoerg 	const AuxInfo *aux;
12445f391f4aSjoerg 	size_t size, len;
12455f391f4aSjoerg 	int mib[2];
12465f391f4aSjoerg 	unsigned int value;
12479e287199Sad 
1248a5644095Sjoerg 	_DIAGASSERT(_dlauxinfo() != NULL);
12499e287199Sad 
1250a5644095Sjoerg 	if (getrlimit(RLIMIT_STACK, &slimit) == -1)
1251841339f0Smanu 		err(EXIT_FAILURE,
1252841339f0Smanu 		    "Couldn't get stack resource consumption limits");
1253bfcb2008Sjoerg 	size = slimit.rlim_cur;
1254841339f0Smanu 	pthread__main->pt_stack.ss_size = size;
12555f391f4aSjoerg 	pthread__main->pt_guardsize = pthread__pagesize;
12565f391f4aSjoerg 
12575f391f4aSjoerg 	mib[0] = CTL_VM;
12585f391f4aSjoerg 	mib[1] = VM_GUARD_SIZE;
12595f391f4aSjoerg 	len = sizeof(value);
12605f391f4aSjoerg 	if (sysctl(mib, __arraycount(mib), &value, &len, NULL, 0) == 0)
12615f391f4aSjoerg 		pthread__main->pt_guardsize = value;
12629e287199Sad 
1263a5644095Sjoerg 	for (aux = _dlauxinfo(); aux->a_type != AT_NULL; ++aux) {
1264a5644095Sjoerg 		if (aux->a_type == AT_STACKBASE) {
1265bfcb2008Sjoerg #ifdef __MACHINE_STACK_GROWS_UP
1266841339f0Smanu 			pthread__main->pt_stack.ss_sp = (void *)aux->a_v;
1267bfcb2008Sjoerg #else
1268841339f0Smanu 			pthread__main->pt_stack.ss_sp = (char *)aux->a_v - size;
1269bfcb2008Sjoerg #endif
1270a5644095Sjoerg 			break;
12719e287199Sad 		}
1272a5644095Sjoerg 	}
1273939c050dSchristos 	pthread__copy_tsd(pthread__main);
1274a5644095Sjoerg }
12759e287199Sad 
12769e287199Sad /*
12779e287199Sad  * Set up the slightly special stack for the "initial" thread, which
12789e287199Sad  * runs on the normal system stack, and thus gets slightly different
12799e287199Sad  * treatment.
12809e287199Sad  */
12819e287199Sad static void
pthread__initmain(pthread_t * newt)12829e287199Sad pthread__initmain(pthread_t *newt)
12839e287199Sad {
12849e287199Sad 	char *value;
12859e287199Sad 
1286a5644095Sjoerg 	pthread__initmainstack();
128715e9cec1Sad 
128815e9cec1Sad 	value = pthread__getenv("PTHREAD_STACKSIZE");
128915e9cec1Sad 	if (value != NULL) {
12909e287199Sad 		pthread__stacksize = atoi(value) * 1024;
1291841339f0Smanu 		if (pthread__stacksize > pthread__main->pt_stack.ss_size)
1292841339f0Smanu 			pthread__stacksize = pthread__main->pt_stack.ss_size;
12939e287199Sad 	}
12949e287199Sad 	if (pthread__stacksize == 0)
1295841339f0Smanu 		pthread__stacksize = pthread__main->pt_stack.ss_size;
1296a5644095Sjoerg 	pthread__stacksize += pthread__pagesize - 1;
1297677d666cSdrochner 	pthread__stacksize &= ~(pthread__pagesize - 1);
1298a5644095Sjoerg 	if (pthread__stacksize < 4 * pthread__pagesize)
12999e287199Sad 		errx(1, "Stacksize limit is too low, minimum %zd kbyte.",
1300a5644095Sjoerg 		    4 * pthread__pagesize / 1024);
13019e287199Sad 
1302841339f0Smanu 	*newt = pthread__main;
1303082d249aSpooka #if defined(_PTHREAD_GETTCB_EXT)
1304841339f0Smanu 	pthread__main->pt_tls = _PTHREAD_GETTCB_EXT();
1305082d249aSpooka #elif defined(__HAVE___LWP_GETTCB_FAST)
1306841339f0Smanu 	pthread__main->pt_tls = __lwp_gettcb_fast();
1307928f301bSjoerg #else
1308841339f0Smanu 	pthread__main->pt_tls = _lwp_getprivate();
1309928f301bSjoerg #endif
1310841339f0Smanu 	pthread__main->pt_tls->tcb_pthread = pthread__main;
13119e287199Sad }
13129e287199Sad 
1313d79b47c3Srmind static signed int
1314cb292d56Schristos /*ARGSUSED*/
pthread__cmp(void * ctx,const void * n1,const void * n2)1315d79b47c3Srmind pthread__cmp(void *ctx, const void *n1, const void *n2)
13169583eeb2Sad {
13179d94c026Sapb 	const uintptr_t p1 = (const uintptr_t)n1;
13189d94c026Sapb 	const uintptr_t p2 = (const uintptr_t)n2;
1319f1c955a1Sdrochner 
1320d79b47c3Srmind 	if (p1 < p2)
1321d79b47c3Srmind 		return -1;
1322d79b47c3Srmind 	if (p1 > p2)
1323f1c955a1Sdrochner 		return 1;
1324d79b47c3Srmind 	return 0;
13259583eeb2Sad }
13269583eeb2Sad 
132715e9cec1Sad /* Because getenv() wants to use locks. */
132815e9cec1Sad char *
pthread__getenv(const char * name)132915e9cec1Sad pthread__getenv(const char *name)
133015e9cec1Sad {
1331103af04bStron 	extern char **environ;
1332103af04bStron 	size_t l_name, offset;
133315e9cec1Sad 
1334d3a99cd5Sjoerg 	if (issetugid())
1335d3a99cd5Sjoerg 		return (NULL);
1336d3a99cd5Sjoerg 
1337103af04bStron 	l_name = strlen(name);
1338103af04bStron 	for (offset = 0; environ[offset] != NULL; offset++) {
1339103af04bStron 		if (strncmp(name, environ[offset], l_name) == 0 &&
1340103af04bStron 		    environ[offset][l_name] == '=') {
1341103af04bStron 			return environ[offset] + l_name + 1;
1342103af04bStron 		}
1343103af04bStron 	}
1344103af04bStron 
1345103af04bStron 	return NULL;
134615e9cec1Sad }
134715e9cec1Sad 
13482bcb8bf1Sad pthread_mutex_t *
pthread__hashlock(volatile const void * p)13492bcb8bf1Sad pthread__hashlock(volatile const void *p)
13502bcb8bf1Sad {
13512bcb8bf1Sad 	uintptr_t v;
135215e9cec1Sad 
13532bcb8bf1Sad 	v = (uintptr_t)p;
13542bcb8bf1Sad 	return &hashlocks[((v >> 9) ^ (v >> 3)) & (NHASHLOCK - 1)].mutex;
13552bcb8bf1Sad }
1356cbd43ffaSad 
1357cbd43ffaSad int
pthread__checkpri(int pri)1358cbd43ffaSad pthread__checkpri(int pri)
1359cbd43ffaSad {
1360c0038aadSmatt 	static int havepri;
1361c0038aadSmatt 	static long min, max;
1362cbd43ffaSad 
1363cbd43ffaSad 	if (!havepri) {
1364cbd43ffaSad 		min = sysconf(_SC_SCHED_PRI_MIN);
1365cbd43ffaSad 		max = sysconf(_SC_SCHED_PRI_MAX);
1366cbd43ffaSad 		havepri = 1;
1367cbd43ffaSad 	}
1368cbd43ffaSad 	return (pri < min || pri > max) ? EINVAL : 0;
1369cbd43ffaSad }
1370