1 /* $OpenBSD: rthread.c,v 1.9 2020/10/12 22:06:51 deraadt Exp $ */ 2 /* 3 * Copyright (c) 2004,2005 Ted Unangst <tedu@openbsd.org> 4 * All Rights Reserved. 5 * 6 * Permission to use, copy, modify, and distribute this software for any 7 * purpose with or without fee is hereby granted, provided that the above 8 * copyright notice and this permission notice appear in all copies. 9 * 10 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 11 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 12 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 13 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 14 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 15 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 16 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 17 */ 18 /* 19 * The infrastructure of rthreads 20 */ 21 22 #include <sys/types.h> 23 #include <sys/atomic.h> 24 25 #include <pthread.h> 26 #include <stdlib.h> 27 #include <tib.h> 28 #include <unistd.h> 29 30 #include "rthread.h" 31 32 #define RTHREAD_ENV_DEBUG "RTHREAD_DEBUG" 33 34 int _rthread_debug_level; 35 36 static int _threads_inited; 37 38 struct pthread _initial_thread = { 39 .flags_lock = _SPINLOCK_UNLOCKED, 40 .name = "Original thread", 41 }; 42 43 /* 44 * internal support functions 45 */ 46 void 47 _spinlock(volatile _atomic_lock_t *lock) 48 { 49 while (_atomic_lock(lock)) 50 sched_yield(); 51 membar_enter_after_atomic(); 52 } 53 DEF_STRONG(_spinlock); 54 55 int 56 _spinlocktry(volatile _atomic_lock_t *lock) 57 { 58 if (_atomic_lock(lock) == 0) { 59 membar_enter_after_atomic(); 60 return 1; 61 } 62 return 0; 63 } 64 65 void 66 _spinunlock(volatile _atomic_lock_t *lock) 67 { 68 membar_exit(); 69 *lock = _ATOMIC_LOCK_UNLOCKED; 70 } 71 DEF_STRONG(_spinunlock); 72 73 static void 74 _rthread_init(void) 75 { 76 pthread_t thread = &_initial_thread; 77 struct tib *tib; 78 79 if (_threads_inited) 80 return; 81 82 tib = TIB_GET(); 83 tib->tib_thread = thread; 84 thread->tib = tib; 85 86 thread->donesem.lock = _SPINLOCK_UNLOCKED; 87 tib->tib_thread_flags = TIB_THREAD_INITIAL_STACK; 88 89 /* 90 * Set the debug level from an environment string. 91 * Bogus values are silently ignored. 92 */ 93 if (!issetugid()) { 94 char *envp = getenv(RTHREAD_ENV_DEBUG); 95 96 if (envp != NULL) { 97 char *rem; 98 99 _rthread_debug_level = (int) strtol(envp, &rem, 0); 100 if (*rem != '\0' || _rthread_debug_level < 0) 101 _rthread_debug_level = 0; 102 } 103 } 104 105 _threads_inited = 1; 106 } 107 108 /* 109 * real pthread functions 110 */ 111 pthread_t 112 pthread_self(void) 113 { 114 if (__predict_false(!_threads_inited)) 115 _rthread_init(); 116 117 return TIB_GET()->tib_thread; 118 } 119 DEF_STRONG(pthread_self); 120 121 void 122 pthread_exit(void *retval) 123 { 124 struct rthread_cleanup_fn *clfn; 125 struct tib *tib; 126 pthread_t thread = pthread_self(); 127 128 tib = thread->tib; 129 130 if (tib->tib_cantcancel & CANCEL_DYING) { 131 /* 132 * Called pthread_exit() from destructor or cancelation 133 * handler: blow up. XXX write something to stderr? 134 */ 135 abort(); 136 //_exit(42); 137 } 138 139 tib->tib_cantcancel |= CANCEL_DYING; 140 141 thread->retval = retval; 142 143 for (clfn = thread->cleanup_fns; clfn; ) { 144 struct rthread_cleanup_fn *oclfn = clfn; 145 clfn = clfn->next; 146 oclfn->fn(oclfn->arg); 147 free(oclfn); 148 } 149 _thread_finalize(); 150 _rthread_tls_destructors(thread); 151 152 if (_thread_cb.tc_thread_release != NULL) 153 _thread_cb.tc_thread_release(thread); 154 155 __threxit(&tib->tib_tid); 156 for(;;); 157 } 158 DEF_STRONG(pthread_exit); 159 160 int 161 pthread_equal(pthread_t t1, pthread_t t2) 162 { 163 return (t1 == t2); 164 } 165 166