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 34int _rthread_debug_level; 35 36static int _threads_inited; 37 38struct pthread _initial_thread = { 39 .flags_lock = _SPINLOCK_UNLOCKED, 40 .name = "Original thread", 41}; 42 43/* 44 * internal support functions 45 */ 46void 47_spinlock(volatile _atomic_lock_t *lock) 48{ 49 while (_atomic_lock(lock)) 50 sched_yield(); 51 membar_enter_after_atomic(); 52} 53DEF_STRONG(_spinlock); 54 55int 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 65void 66_spinunlock(volatile _atomic_lock_t *lock) 67{ 68 membar_exit(); 69 *lock = _ATOMIC_LOCK_UNLOCKED; 70} 71DEF_STRONG(_spinunlock); 72 73static 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 */ 111pthread_t 112pthread_self(void) 113{ 114 if (__predict_false(!_threads_inited)) 115 _rthread_init(); 116 117 return TIB_GET()->tib_thread; 118} 119DEF_STRONG(pthread_self); 120 121void 122pthread_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} 158DEF_STRONG(pthread_exit); 159 160int 161pthread_equal(pthread_t t1, pthread_t t2) 162{ 163 return (t1 == t2); 164} 165 166