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