1 /* $OpenBSD: rthread.c,v 1.7 2017/12/05 13:45:31 kettenis 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 <pthread.h> 23 #include <stdlib.h> 24 #include <tib.h> 25 #include <unistd.h> 26 27 #include "rthread.h" 28 29 #define RTHREAD_ENV_DEBUG "RTHREAD_DEBUG" 30 31 int _rthread_debug_level; 32 33 static int _threads_inited; 34 35 struct pthread _initial_thread = { 36 .flags_lock = _SPINLOCK_UNLOCKED, 37 .name = "Original thread", 38 }; 39 40 /* 41 * internal support functions 42 */ 43 void 44 _spinlock(volatile _atomic_lock_t *lock) 45 { 46 while (_atomic_lock(lock)) 47 sched_yield(); 48 } 49 DEF_STRONG(_spinlock); 50 51 int 52 _spinlocktry(volatile _atomic_lock_t *lock) 53 { 54 return 0 == _atomic_lock(lock); 55 } 56 57 void 58 _spinunlock(volatile _atomic_lock_t *lock) 59 { 60 *lock = _ATOMIC_LOCK_UNLOCKED; 61 } 62 DEF_STRONG(_spinunlock); 63 64 static void 65 _rthread_init(void) 66 { 67 pthread_t thread = &_initial_thread; 68 struct tib *tib; 69 70 if (_threads_inited) 71 return; 72 73 tib = TIB_GET(); 74 tib->tib_thread = thread; 75 thread->tib = tib; 76 77 thread->donesem.lock = _SPINLOCK_UNLOCKED; 78 tib->tib_thread_flags = TIB_THREAD_INITIAL_STACK; 79 80 /* 81 * Set the debug level from an environment string. 82 * Bogus values are silently ignored. 83 */ 84 if (! issetugid()) { 85 char *envp = getenv(RTHREAD_ENV_DEBUG); 86 87 if (envp != NULL) { 88 char *rem; 89 90 _rthread_debug_level = (int) strtol(envp, &rem, 0); 91 if (*rem != '\0' || _rthread_debug_level < 0) 92 _rthread_debug_level = 0; 93 } 94 } 95 96 _threads_inited = 1; 97 } 98 99 /* 100 * real pthread functions 101 */ 102 pthread_t 103 pthread_self(void) 104 { 105 if (__predict_false(!_threads_inited)) 106 _rthread_init(); 107 108 return TIB_GET()->tib_thread; 109 } 110 DEF_STRONG(pthread_self); 111 112 void 113 pthread_exit(void *retval) 114 { 115 struct rthread_cleanup_fn *clfn; 116 struct tib *tib; 117 pthread_t thread = pthread_self(); 118 119 tib = thread->tib; 120 121 if (tib->tib_cantcancel & CANCEL_DYING) { 122 /* 123 * Called pthread_exit() from destructor or cancelation 124 * handler: blow up. XXX write something to stderr? 125 */ 126 abort(); 127 //_exit(42); 128 } 129 130 tib->tib_cantcancel |= CANCEL_DYING; 131 132 thread->retval = retval; 133 134 for (clfn = thread->cleanup_fns; clfn; ) { 135 struct rthread_cleanup_fn *oclfn = clfn; 136 clfn = clfn->next; 137 oclfn->fn(oclfn->arg); 138 free(oclfn); 139 } 140 _thread_finalize(); 141 _rthread_tls_destructors(thread); 142 143 if (_thread_cb.tc_thread_release != NULL) 144 _thread_cb.tc_thread_release(thread); 145 146 __threxit(&tib->tib_tid); 147 for(;;); 148 } 149 DEF_STRONG(pthread_exit); 150 151 int 152 pthread_equal(pthread_t t1, pthread_t t2) 153 { 154 return (t1 == t2); 155 } 156 157