xref: /openbsd-src/lib/libc/thread/rthread.c (revision ce775b4f526bf06da26b3a79c6d7fe719b89f7b8)
1*ce775b4fSderaadt /*	$OpenBSD: rthread.c,v 1.9 2020/10/12 22:06:51 deraadt Exp $ */
27e321ac1Sguenther /*
37e321ac1Sguenther  * Copyright (c) 2004,2005 Ted Unangst <tedu@openbsd.org>
47e321ac1Sguenther  * All Rights Reserved.
57e321ac1Sguenther  *
67e321ac1Sguenther  * Permission to use, copy, modify, and distribute this software for any
77e321ac1Sguenther  * purpose with or without fee is hereby granted, provided that the above
87e321ac1Sguenther  * copyright notice and this permission notice appear in all copies.
97e321ac1Sguenther  *
107e321ac1Sguenther  * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
117e321ac1Sguenther  * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
127e321ac1Sguenther  * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
137e321ac1Sguenther  * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
147e321ac1Sguenther  * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
157e321ac1Sguenther  * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
167e321ac1Sguenther  * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
177e321ac1Sguenther  */
187e321ac1Sguenther /*
19a5511fa9Sguenther  * The infrastructure of rthreads
207e321ac1Sguenther  */
217e321ac1Sguenther 
2288a78cd1Svisa #include <sys/types.h>
2388a78cd1Svisa #include <sys/atomic.h>
2488a78cd1Svisa 
255be66c01Sguenther #include <pthread.h>
265be66c01Sguenther #include <stdlib.h>
277e321ac1Sguenther #include <tib.h>
285be66c01Sguenther #include <unistd.h>
297e321ac1Sguenther 
307e321ac1Sguenther #include "rthread.h"
317e321ac1Sguenther 
32a5511fa9Sguenther #define RTHREAD_ENV_DEBUG	"RTHREAD_DEBUG"
337e321ac1Sguenther 
34a5511fa9Sguenther int _rthread_debug_level;
357e321ac1Sguenther 
36a5511fa9Sguenther static int _threads_inited;
377e321ac1Sguenther 
38a5511fa9Sguenther struct pthread _initial_thread = {
39a5511fa9Sguenther 	.flags_lock = _SPINLOCK_UNLOCKED,
40a5511fa9Sguenther 	.name = "Original thread",
417e321ac1Sguenther };
427e321ac1Sguenther 
437e321ac1Sguenther /*
447e321ac1Sguenther  * internal support functions
457e321ac1Sguenther  */
467e321ac1Sguenther void
_spinlock(volatile _atomic_lock_t * lock)477e321ac1Sguenther _spinlock(volatile _atomic_lock_t *lock)
487e321ac1Sguenther {
497e321ac1Sguenther 	while (_atomic_lock(lock))
507e321ac1Sguenther 		sched_yield();
5188a78cd1Svisa 	membar_enter_after_atomic();
527e321ac1Sguenther }
53a5511fa9Sguenther DEF_STRONG(_spinlock);
547e321ac1Sguenther 
557e321ac1Sguenther int
_spinlocktry(volatile _atomic_lock_t * lock)567e321ac1Sguenther _spinlocktry(volatile _atomic_lock_t *lock)
577e321ac1Sguenther {
5888a78cd1Svisa 	if (_atomic_lock(lock) == 0) {
5988a78cd1Svisa 		membar_enter_after_atomic();
6088a78cd1Svisa 		return 1;
6188a78cd1Svisa 	}
6288a78cd1Svisa 	return 0;
637e321ac1Sguenther }
647e321ac1Sguenther 
657e321ac1Sguenther void
_spinunlock(volatile _atomic_lock_t * lock)667e321ac1Sguenther _spinunlock(volatile _atomic_lock_t *lock)
677e321ac1Sguenther {
6888a78cd1Svisa 	membar_exit();
697e321ac1Sguenther 	*lock = _ATOMIC_LOCK_UNLOCKED;
707e321ac1Sguenther }
71a5511fa9Sguenther DEF_STRONG(_spinunlock);
727e321ac1Sguenther 
737e321ac1Sguenther static void
_rthread_init(void)747e321ac1Sguenther _rthread_init(void)
757e321ac1Sguenther {
767e321ac1Sguenther 	pthread_t thread = &_initial_thread;
777e321ac1Sguenther 	struct tib *tib;
78a5511fa9Sguenther 
79a5511fa9Sguenther 	if (_threads_inited)
80a5511fa9Sguenther 		return;
817e321ac1Sguenther 
827e321ac1Sguenther 	tib = TIB_GET();
837e321ac1Sguenther 	tib->tib_thread = thread;
847e321ac1Sguenther 	thread->tib = tib;
857e321ac1Sguenther 
867e321ac1Sguenther 	thread->donesem.lock = _SPINLOCK_UNLOCKED;
877e321ac1Sguenther 	tib->tib_thread_flags = TIB_THREAD_INITIAL_STACK;
887e321ac1Sguenther 
897e321ac1Sguenther 	/*
90a5511fa9Sguenther 	 * Set the debug level from an environment string.
91a5511fa9Sguenther 	 * Bogus values are silently ignored.
927e321ac1Sguenther 	 */
93a5511fa9Sguenther 	if (!issetugid()) {
94a5511fa9Sguenther 		char *envp = getenv(RTHREAD_ENV_DEBUG);
957e321ac1Sguenther 
96a5511fa9Sguenther 		if (envp != NULL) {
97a5511fa9Sguenther 			char *rem;
987e321ac1Sguenther 
99a5511fa9Sguenther 			_rthread_debug_level = (int) strtol(envp, &rem, 0);
100a5511fa9Sguenther 			if (*rem != '\0' || _rthread_debug_level < 0)
101a5511fa9Sguenther 				_rthread_debug_level = 0;
102a5511fa9Sguenther 		}
1037e321ac1Sguenther 	}
1047e321ac1Sguenther 
105a5511fa9Sguenther 	_threads_inited = 1;
1067e321ac1Sguenther }
1077e321ac1Sguenther 
1087e321ac1Sguenther /*
1097e321ac1Sguenther  * real pthread functions
1107e321ac1Sguenther  */
1117e321ac1Sguenther pthread_t
pthread_self(void)1127e321ac1Sguenther pthread_self(void)
1137e321ac1Sguenther {
114a5511fa9Sguenther 	if (__predict_false(!_threads_inited))
1157e321ac1Sguenther 		_rthread_init();
1167e321ac1Sguenther 
117a5511fa9Sguenther 	return TIB_GET()->tib_thread;
1187e321ac1Sguenther }
1198ae31f71Sguenther DEF_STRONG(pthread_self);
1207e321ac1Sguenther 
1217e321ac1Sguenther void
pthread_exit(void * retval)1227e321ac1Sguenther pthread_exit(void *retval)
1237e321ac1Sguenther {
124a318b99dSjca 	struct rthread_cleanup_fn *clfn;
125a5511fa9Sguenther 	struct tib *tib;
126a5511fa9Sguenther 	pthread_t thread = pthread_self();
1277e321ac1Sguenther 
128a5511fa9Sguenther 	tib = thread->tib;
1297e321ac1Sguenther 
1307e321ac1Sguenther 	if (tib->tib_cantcancel & CANCEL_DYING) {
1317e321ac1Sguenther 		/*
1327e321ac1Sguenther 		 * Called pthread_exit() from destructor or cancelation
1337e321ac1Sguenther 		 * handler: blow up.  XXX write something to stderr?
1347e321ac1Sguenther 		 */
1357e321ac1Sguenther 		abort();
1367e321ac1Sguenther 		//_exit(42);
1377e321ac1Sguenther 	}
1387e321ac1Sguenther 
1397e321ac1Sguenther 	tib->tib_cantcancel |= CANCEL_DYING;
1407e321ac1Sguenther 
1417e321ac1Sguenther 	thread->retval = retval;
1427e321ac1Sguenther 
143a318b99dSjca 	for (clfn = thread->cleanup_fns; clfn; ) {
144a318b99dSjca 		struct rthread_cleanup_fn *oclfn = clfn;
145a318b99dSjca 		clfn = clfn->next;
146a318b99dSjca 		oclfn->fn(oclfn->arg);
147a318b99dSjca 		free(oclfn);
148a318b99dSjca 	}
1490afcdedaSkettenis 	_thread_finalize();
1507e321ac1Sguenther 	_rthread_tls_destructors(thread);
1517e321ac1Sguenther 
152a5511fa9Sguenther 	if (_thread_cb.tc_thread_release != NULL)
153a5511fa9Sguenther 		_thread_cb.tc_thread_release(thread);
1547e321ac1Sguenther 
1557e321ac1Sguenther 	__threxit(&tib->tib_tid);
1567e321ac1Sguenther 	for(;;);
1577e321ac1Sguenther }
1588ae31f71Sguenther DEF_STRONG(pthread_exit);
1597e321ac1Sguenther 
1607e321ac1Sguenther int
pthread_equal(pthread_t t1,pthread_t t2)1617e321ac1Sguenther pthread_equal(pthread_t t1, pthread_t t2)
1627e321ac1Sguenther {
1637e321ac1Sguenther 	return (t1 == t2);
1647e321ac1Sguenther }
1657e321ac1Sguenther 
166