1*16543c49Schristos /* $NetBSD: pthread_int.h,v 1.112 2024/11/30 01:04:04 christos Exp $ */ 2c62a74e6Sthorpej 3c62a74e6Sthorpej /*- 4cd1754abSad * Copyright (c) 2001, 2002, 2003, 2006, 2007, 2008, 2020 5cd1754abSad * The NetBSD Foundation, Inc. 6c62a74e6Sthorpej * All rights reserved. 7c62a74e6Sthorpej * 8c62a74e6Sthorpej * This code is derived from software contributed to The NetBSD Foundation 9de213816Sad * 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 33c62a74e6Sthorpej #ifndef _LIB_PTHREAD_INT_H 34c62a74e6Sthorpej #define _LIB_PTHREAD_INT_H 35c62a74e6Sthorpej 36aad59997Sjoerg #include <sys/tls.h> 37aad59997Sjoerg 38b8833ff5Sad /* #define PTHREAD__DEBUG */ 39c62a74e6Sthorpej 40c62a74e6Sthorpej #include "pthread_types.h" 41c62a74e6Sthorpej #include "pthread_queue.h" 42c62a74e6Sthorpej #include "pthread_md.h" 43c62a74e6Sthorpej 44a67e1e34Sad #include <sys/atomic.h> 45d79b47c3Srmind #include <sys/rbtree.h> 46c6559e92Sad #include <sys/param.h> 479583eeb2Sad 48d3660af7Sjoerg #include <limits.h> 491ac6a89bSad #include <lwp.h> 50c62a74e6Sthorpej #include <signal.h> 51d3660af7Sjoerg #include <stdbool.h> 52c62a74e6Sthorpej 53*16543c49Schristos #include <machine/lwp_private.h> 54*16543c49Schristos 5515e9cec1Sad #ifdef __GNUC__ 5615e9cec1Sad #define PTHREAD_HIDE __attribute__ ((visibility("hidden"))) 5715e9cec1Sad #else 5815e9cec1Sad #define PTHREAD_HIDE /* nothing */ 5915e9cec1Sad #endif 6015e9cec1Sad 617ed25834Sjoerg #define PTHREAD__UNPARK_MAX 128 628ccc6e06Sad 63c62a74e6Sthorpej /* 64c62a74e6Sthorpej * The size of this structure needs to be no larger than struct 65c62a74e6Sthorpej * __pthread_cleanup_store, defined in pthread.h. 66c62a74e6Sthorpej */ 67c62a74e6Sthorpej struct pt_clean_t { 68c62a74e6Sthorpej PTQ_ENTRY(pt_clean_t) ptc_next; 69c62a74e6Sthorpej void (*ptc_cleanup)(void *); 70c62a74e6Sthorpej void *ptc_arg; 71c62a74e6Sthorpej }; 72c62a74e6Sthorpej 73ec2c1698Snathanw /* Private data for pthread_attr_t */ 74ec2c1698Snathanw struct pthread_attr_private { 75ec2c1698Snathanw char ptap_name[PTHREAD_MAX_NAMELEN_NP]; 76ec2c1698Snathanw void *ptap_namearg; 77ec2c1698Snathanw void *ptap_stackaddr; 78ec2c1698Snathanw size_t ptap_stacksize; 79ec2c1698Snathanw size_t ptap_guardsize; 80cbd43ffaSad struct sched_param ptap_sp; 81cbd43ffaSad int ptap_policy; 82ec2c1698Snathanw }; 83ec2c1698Snathanw 8415e9cec1Sad struct pthread_lock_ops { 8515e9cec1Sad void (*plo_init)(__cpu_simple_lock_t *); 8615e9cec1Sad int (*plo_try)(__cpu_simple_lock_t *); 8715e9cec1Sad void (*plo_unlock)(__cpu_simple_lock_t *); 8815e9cec1Sad void (*plo_lock)(__cpu_simple_lock_t *); 8915e9cec1Sad }; 9015e9cec1Sad 91deb18e9dSnathanw struct __pthread_st { 9215e9cec1Sad pthread_t pt_self; /* Must be first. */ 93aad59997Sjoerg #if defined(__HAVE_TLS_VARIANT_I) || defined(__HAVE_TLS_VARIANT_II) 94aad59997Sjoerg struct tls_tcb *pt_tls; /* Thread Local Storage area */ 95aad59997Sjoerg #endif 9650fa8db4Sad unsigned int pt_magic; /* Magic number */ 97c62a74e6Sthorpej int pt_state; /* running, blocked, etc. */ 98c62a74e6Sthorpej int pt_flags; /* see PT_FLAG_* below */ 99c62a74e6Sthorpej int pt_cancel; /* Deferred cancellation */ 100c62a74e6Sthorpej int pt_errno; /* Thread-specific errno. */ 101c62a74e6Sthorpej stack_t pt_stack; /* Our stack */ 102d3660af7Sjoerg bool pt_stack_allocated; 103d3660af7Sjoerg size_t pt_guardsize; 104c62a74e6Sthorpej void *pt_exitval; /* Read by pthread_join() */ 105de213816Sad char *pt_name; /* Thread's name, set by the app. */ 10615e9cec1Sad struct pthread_lock_ops pt_lockops;/* Cached to avoid PIC overhead */ 10761cac435Sad void *(*pt_func)(void *);/* Function to call at start. */ 108eca6fe7eSlukem void *pt_arg; /* Argument to pass at start. */ 109c62a74e6Sthorpej 110c62a74e6Sthorpej /* Stack of cancellation cleanup handlers and their arguments */ 111c62a74e6Sthorpej PTQ_HEAD(, pt_clean_t) pt_cleanup_stack; 112c62a74e6Sthorpej 11350fa8db4Sad /* LWP ID and entry on the list of all threads. */ 11450fa8db4Sad lwpid_t pt_lid; 115b8833ff5Sad PTQ_ENTRY(__pthread_st) pt_deadq; 11650fa8db4Sad 11750fa8db4Sad /* 118c6559e92Sad * rbtree node and entry on the list of all threads. pt_alltree in 119c6559e92Sad * its own cacheline, so pthread__find() is not needlessly impacted 120c6559e92Sad * by threads going about their normal business. pt_allq is 121c6559e92Sad * adjusted at the same time as pt_alltree. 122c6559e92Sad */ 123c6559e92Sad rb_node_t pt_alltree __aligned(COHERENCY_UNIT); 124c6559e92Sad PTQ_ENTRY(__pthread_st) pt_allq; 125c6559e92Sad 126c6559e92Sad /* Lock on state also gets its own line. */ 127c6559e92Sad pthread_mutex_t pt_lock __aligned(COHERENCY_UNIT); 128c6559e92Sad 129c6559e92Sad /* 13050fa8db4Sad * General synchronization data. We try to align, as threads 13150fa8db4Sad * on other CPUs will access this data frequently. 13250fa8db4Sad */ 133c6559e92Sad int pt_dummy1 __aligned(COHERENCY_UNIT); 13466ac2ffaSad struct lwpctl *pt_lwpctl; /* Kernel/user comms area */ 1358ccc6e06Sad volatile int pt_rwlocked; /* Handed rwlock successfully */ 1368ccc6e06Sad void * volatile pt_sleepobj; /* Object slept on */ 13750fa8db4Sad PTQ_ENTRY(__pthread_st) pt_sleep; 138ed964af1Sad 139b8833ff5Sad /* Thread-specific data. Large so it sits close to the end. */ 140c6559e92Sad int pt_havespecific __aligned(COHERENCY_UNIT); 14155f47ec3Schristos struct pt_specific { 14255f47ec3Schristos void *pts_value; 14355f47ec3Schristos PTQ_ENTRY(pt_specific) pts_next; 144841339f0Smanu } pt_specific[]; 145c62a74e6Sthorpej }; 146c62a74e6Sthorpej 1471ac6a89bSad /* Thread states */ 1481ac6a89bSad #define PT_STATE_RUNNING 1 1491ac6a89bSad #define PT_STATE_ZOMBIE 5 1501ac6a89bSad #define PT_STATE_DEAD 6 1511ac6a89bSad 152c62a74e6Sthorpej /* Flag values */ 153c62a74e6Sthorpej 154c62a74e6Sthorpej #define PT_FLAG_DETACHED 0x0001 155c62a74e6Sthorpej #define PT_FLAG_CS_DISABLED 0x0004 /* Cancellation disabled */ 156c62a74e6Sthorpej #define PT_FLAG_CS_ASYNC 0x0008 /* Cancellation is async */ 157c62a74e6Sthorpej #define PT_FLAG_CS_PENDING 0x0010 158deb18e9dSnathanw #define PT_FLAG_SCOPE_SYSTEM 0x0040 159deb18e9dSnathanw #define PT_FLAG_EXPLICIT_SCHED 0x0080 16038b1c6f4Schristos #define PT_FLAG_SUSPENDED 0x0100 /* In the suspended queue */ 161c62a74e6Sthorpej 162c62a74e6Sthorpej #define PT_MAGIC 0x11110001 163c62a74e6Sthorpej #define PT_DEAD 0xDEAD0001 164c62a74e6Sthorpej 165c62a74e6Sthorpej #define PT_ATTR_MAGIC 0x22220002 166c62a74e6Sthorpej #define PT_ATTR_DEAD 0xDEAD0002 167c62a74e6Sthorpej 1689e287199Sad extern size_t pthread__stacksize; 1695f391f4aSjoerg extern size_t pthread__guardsize; 170a5644095Sjoerg extern size_t pthread__pagesize; 171b8833ff5Sad extern int pthread__nspins; 172b8833ff5Sad extern int pthread__concurrency; 173b8833ff5Sad extern int pthread__osrev; 174bc77394cSad extern size_t pthread__unpark_max; 175841339f0Smanu extern int pthread_keys_max; 1762c9b7b1eScl 17771d484f9Schristos extern int __uselibcstub; 17871d484f9Schristos 17962e0939eSad struct pthread__waiter { 18062e0939eSad struct pthread__waiter *volatile next; 18162e0939eSad lwpid_t volatile lid; 18262e0939eSad }; 18362e0939eSad 184c62a74e6Sthorpej /* Flag to be used in a ucontext_t's uc_flags indicating that 185c62a74e6Sthorpej * the saved register state is "user" state only, not full 186c62a74e6Sthorpej * trap state. 187c62a74e6Sthorpej */ 188c62a74e6Sthorpej #define _UC_USER_BIT 30 189c62a74e6Sthorpej #define _UC_USER (1LU << _UC_USER_BIT) 190c62a74e6Sthorpej 191c62a74e6Sthorpej /* Utility functions */ 1922bcb8bf1Sad void pthread__unpark_all(pthread_queue_t *, pthread_t, pthread_mutex_t *) 19315e9cec1Sad PTHREAD_HIDE; 1942bcb8bf1Sad void pthread__unpark(pthread_queue_t *, pthread_t, pthread_mutex_t *) 1952bcb8bf1Sad PTHREAD_HIDE; 1962bcb8bf1Sad int pthread__park(pthread_t, pthread_mutex_t *, pthread_queue_t *, 197bc77394cSad const struct timespec *, int) PTHREAD_HIDE; 1982bcb8bf1Sad pthread_mutex_t *pthread__hashlock(volatile const void *) PTHREAD_HIDE; 1991ac6a89bSad 200c62a74e6Sthorpej /* Internal locking primitives */ 20115e9cec1Sad void pthread__lockprim_init(void) PTHREAD_HIDE; 20215e9cec1Sad void pthread_lockinit(pthread_spin_t *) PTHREAD_HIDE; 20315e9cec1Sad 204c6409540Schristos static inline void pthread__spinlock(pthread_t, pthread_spin_t *) 205c6409540Schristos __attribute__((__always_inline__)); 20615e9cec1Sad static inline void 20715e9cec1Sad pthread__spinlock(pthread_t self, pthread_spin_t *lock) 20815e9cec1Sad { 20915e9cec1Sad if (__predict_true((*self->pt_lockops.plo_try)(lock))) 21015e9cec1Sad return; 21115e9cec1Sad (*self->pt_lockops.plo_lock)(lock); 21215e9cec1Sad } 21315e9cec1Sad 214c6409540Schristos static inline int pthread__spintrylock(pthread_t, pthread_spin_t *) 215c6409540Schristos __attribute__((__always_inline__)); 21615e9cec1Sad static inline int 21715e9cec1Sad pthread__spintrylock(pthread_t self, pthread_spin_t *lock) 21815e9cec1Sad { 21915e9cec1Sad return (*self->pt_lockops.plo_try)(lock); 22015e9cec1Sad } 22115e9cec1Sad 222c6409540Schristos static inline void pthread__spinunlock(pthread_t, pthread_spin_t *) 223c6409540Schristos __attribute__((__always_inline__)); 22415e9cec1Sad static inline void 22515e9cec1Sad pthread__spinunlock(pthread_t self, pthread_spin_t *lock) 22615e9cec1Sad { 22715e9cec1Sad (*self->pt_lockops.plo_unlock)(lock); 22815e9cec1Sad } 229c62a74e6Sthorpej 230c62a74e6Sthorpej extern const struct pthread_lock_ops *pthread__lock_ops; 231c62a74e6Sthorpej 23215e9cec1Sad int pthread__simple_locked_p(__cpu_simple_lock_t *) PTHREAD_HIDE; 233d32ed989Sskrll #define pthread__simple_lock_init(alp) (*pthread__lock_ops->plo_init)(alp) 234d32ed989Sskrll #define pthread__simple_lock_try(alp) (*pthread__lock_ops->plo_try)(alp) 235d32ed989Sskrll #define pthread__simple_unlock(alp) (*pthread__lock_ops->plo_unlock)(alp) 236c62a74e6Sthorpej 23715e9cec1Sad void pthread__testcancel(pthread_t) PTHREAD_HIDE; 23815e9cec1Sad int pthread__find(pthread_t) PTHREAD_HIDE; 239c62a74e6Sthorpej 240c62a74e6Sthorpej #ifndef PTHREAD_MD_INIT 241c62a74e6Sthorpej #define PTHREAD_MD_INIT 242c62a74e6Sthorpej #endif 243c62a74e6Sthorpej 244c62a74e6Sthorpej #ifndef _INITCONTEXT_U_MD 245c62a74e6Sthorpej #define _INITCONTEXT_U_MD(ucp) 246c62a74e6Sthorpej #endif 247c62a74e6Sthorpej 248c62a74e6Sthorpej #define _INITCONTEXT_U(ucp) do { \ 249c62a74e6Sthorpej (ucp)->uc_flags = _UC_CPU | _UC_STACK; \ 250c62a74e6Sthorpej _INITCONTEXT_U_MD(ucp) \ 251388550b0Srillig } while (0) 252c62a74e6Sthorpej 253c62a74e6Sthorpej 2548050d45dSjoerg #if !defined(__HAVE_TLS_VARIANT_I) && !defined(__HAVE_TLS_VARIANT_II) 2558050d45dSjoerg #error Either __HAVE_TLS_VARIANT_I or __HAVE_TLS_VARIANT_II must be defined 2568050d45dSjoerg #endif 2578050d45dSjoerg 258082d249aSpooka #ifdef _PTHREAD_GETTCB_EXT 259082d249aSpooka struct tls_tcb *_PTHREAD_GETTCB_EXT(void); 260082d249aSpooka #endif 261082d249aSpooka 262aad59997Sjoerg static inline pthread_t __constfunc 263aad59997Sjoerg pthread__self(void) 264aad59997Sjoerg { 265082d249aSpooka #if defined(_PTHREAD_GETTCB_EXT) 266082d249aSpooka struct tls_tcb * const tcb = _PTHREAD_GETTCB_EXT(); 267082d249aSpooka #elif defined(__HAVE___LWP_GETTCB_FAST) 268def13dadSmatt struct tls_tcb * const tcb = __lwp_gettcb_fast(); 269def13dadSmatt #else 270def13dadSmatt struct tls_tcb * const tcb = __lwp_getprivate_fast(); 271def13dadSmatt #endif 272aad59997Sjoerg return (pthread_t)tcb->tcb_pthread; 273aad59997Sjoerg } 274877f8985Snathanw 275143f5a27Schristos #define pthread__abort() \ 276143f5a27Schristos pthread__assertfunc(__FILE__, __LINE__, __func__, "unreachable") 277143f5a27Schristos 278df277271Snathanw #define pthread__assert(e) do { \ 279df277271Snathanw if (__predict_false(!(e))) \ 280df277271Snathanw pthread__assertfunc(__FILE__, __LINE__, __func__, #e); \ 281388550b0Srillig } while (0) 282df277271Snathanw 283df277271Snathanw #define pthread__error(err, msg, e) do { \ 284df277271Snathanw if (__predict_false(!(e))) { \ 285df277271Snathanw pthread__errorfunc(__FILE__, __LINE__, __func__, msg); \ 286df277271Snathanw return (err); \ 287df277271Snathanw } \ 288388550b0Srillig } while (0) 289df277271Snathanw 290331480e6Skamil void *pthread_tsd_init(size_t *) PTHREAD_HIDE; 29115e9cec1Sad void pthread__destroy_tsd(pthread_t) PTHREAD_HIDE; 292939c050dSchristos void pthread__copy_tsd(pthread_t) PTHREAD_HIDE; 293939c050dSchristos 29467f518f4Sjoerg __dead void pthread__assertfunc(const char *, int, const char *, const char *) 29515e9cec1Sad PTHREAD_HIDE; 29634a4ae72Sjoerg void pthread__errorfunc(const char *, int, const char *, const char *, ...) 29734a4ae72Sjoerg __printflike(4, 5) PTHREAD_HIDE; 29815e9cec1Sad char *pthread__getenv(const char *) PTHREAD_HIDE; 29967f518f4Sjoerg __dead void pthread__cancelled(void) PTHREAD_HIDE; 30062e0939eSad void pthread__mutex_deferwake(pthread_t, pthread_mutex_t *, 30162e0939eSad struct pthread__waiter *) PTHREAD_HIDE; 302cbd43ffaSad int pthread__checkpri(int) PTHREAD_HIDE; 30355f47ec3Schristos int pthread__add_specific(pthread_t, pthread_key_t, const void *) PTHREAD_HIDE; 304f4fd6b79Sad 305a6ed47a5Sad #ifndef pthread__smt_pause 30621ee6fc1Sriastradh #define pthread__smt_pause() __nothing 30750fa8db4Sad #endif 3082a673dcfSriastradh #ifndef pthread__smt_wait 3092a673dcfSriastradh #define pthread__smt_wait() __nothing 3102a673dcfSriastradh #endif 3112f1e74f8Smatt #ifndef pthread__smt_wake 31221ee6fc1Sriastradh #define pthread__smt_wake() __nothing 3132f1e74f8Smatt #endif 31450fa8db4Sad 315f4fd6b79Sad /* 316f4fd6b79Sad * Bits in the owner field of the lock that indicate lock state. If the 317f4fd6b79Sad * WRITE_LOCKED bit is clear, then the owner field is actually a count of 318f4fd6b79Sad * the number of readers. 319f4fd6b79Sad */ 320f4fd6b79Sad #define RW_HAS_WAITERS 0x01 /* lock has waiters */ 321f4fd6b79Sad #define RW_WRITE_WANTED 0x02 /* >= 1 waiter is a writer */ 322f4fd6b79Sad #define RW_WRITE_LOCKED 0x04 /* lock is currently write locked */ 323f4fd6b79Sad #define RW_UNUSED 0x08 /* currently unused */ 324f4fd6b79Sad 325f4fd6b79Sad #define RW_FLAGMASK 0x0f 326f4fd6b79Sad 327f4fd6b79Sad #define RW_READ_COUNT_SHIFT 4 328f4fd6b79Sad #define RW_READ_INCR (1 << RW_READ_COUNT_SHIFT) 329f4fd6b79Sad #define RW_THREAD ((uintptr_t)-RW_READ_INCR) 330f4fd6b79Sad 331c62a74e6Sthorpej #endif /* _LIB_PTHREAD_INT_H */ 332