xref: /openbsd-src/lib/libc/thread/rthread.c (revision ae3cb403620ab940fbaabb3055fac045a63d56b7)
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