xref: /openbsd-src/lib/libc/thread/rthread.c (revision ce775b4f526bf06da26b3a79c6d7fe719b89f7b8)
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
_spinlock(volatile _atomic_lock_t * lock)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
_spinlocktry(volatile _atomic_lock_t * lock)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
_spinunlock(volatile _atomic_lock_t * lock)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
_rthread_init(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
pthread_self(void)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
pthread_exit(void * retval)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
pthread_equal(pthread_t t1,pthread_t t2)161 pthread_equal(pthread_t t1, pthread_t t2)
162 {
163 	return (t1 == t2);
164 }
165 
166