xref: /openbsd-src/lib/libc/gen/errno.c (revision fe38b55cb0aae270de3f844146814682e8cd345c)
1*fe38b55cSguenther /*	$OpenBSD: errno.c,v 1.6 2016/05/07 19:05:22 guenther Exp $ */
205f229c1Smarc /* PUBLIC DOMAIN: No Rights Reserved.   Marco S Hyman <marc@snafu.org> */
305f229c1Smarc 
4*fe38b55cSguenther #include <tib.h>
50ede50fcSmarc #include <errno.h>
6*fe38b55cSguenther #include <unistd.h>
7*fe38b55cSguenther #include "thread_private.h"
80ede50fcSmarc 
90ede50fcSmarc 
10*fe38b55cSguenther #ifdef TCB_HAVE_MD_GET
110ede50fcSmarc /*
12*fe38b55cSguenther  * If there's an MD TCB_GET() macro, then getting the TCB address is
13*fe38b55cSguenther  * cheap enough that we can do it even in single-threaded programs,
14*fe38b55cSguenther  * so the tc_errnoptr and tc_tcb callbacks will be unused, and __errno()
15*fe38b55cSguenther  * can just use TIB_GET().
160ede50fcSmarc  */
170ede50fcSmarc int *
__errno(void)18*fe38b55cSguenther __errno(void)
190ede50fcSmarc {
20*fe38b55cSguenther 	return (&TIB_GET()->tib_errno);
21*fe38b55cSguenther }
22*fe38b55cSguenther DEF_STRONG(__errno);
23*fe38b55cSguenther 
24*fe38b55cSguenther #else /* ! TCB_HAVE_MD_GET */
25*fe38b55cSguenther /*
26*fe38b55cSguenther  * Otherwise, getting the TCB address requires the __get_tcb()
27*fe38b55cSguenther  * syscall.  Rather than pay that cost for single-threaded programs,
28*fe38b55cSguenther  * the syscall stubs will invoke the tc_errnoptr callback to set errno
29*fe38b55cSguenther  * and other code will invoke the tc_tcb callback to get the TCB
30*fe38b55cSguenther  * for cancelation checks, etc.  The default callbacks will just
31*fe38b55cSguenther  * work from the cached location of the initial thread's TCB;
32*fe38b55cSguenther  * libpthread can override them to the necessary more expensive
33*fe38b55cSguenther  * versions that use __get_tcb().
34*fe38b55cSguenther  */
35*fe38b55cSguenther 
36*fe38b55cSguenther /* cached pointer to the TCB of the only thread in single-threaded programs */
37*fe38b55cSguenther void	*_libc_single_tcb = NULL;
38*fe38b55cSguenther 
39*fe38b55cSguenther static inline void *
single_threaded_tcb(void)40*fe38b55cSguenther single_threaded_tcb(void)
41*fe38b55cSguenther {
42*fe38b55cSguenther 	if (__predict_false(_libc_single_tcb == NULL))
43*fe38b55cSguenther 		_libc_single_tcb = TCB_GET();
44*fe38b55cSguenther 	return (_libc_single_tcb);
450ede50fcSmarc }
460ede50fcSmarc 
47*fe38b55cSguenther static int *
single_threaded_errnoptr(void)48*fe38b55cSguenther single_threaded_errnoptr(void)
49*fe38b55cSguenther {
50*fe38b55cSguenther 	return &TCB_TO_TIB(single_threaded_tcb())->tib_errno;
51*fe38b55cSguenther }
52*fe38b55cSguenther 
53*fe38b55cSguenther /*
54*fe38b55cSguenther  * __errno(): just use the callback to get the applicable current method
55*fe38b55cSguenther  */
56*fe38b55cSguenther int *
__errno(void)57*fe38b55cSguenther __errno(void)
58*fe38b55cSguenther {
59*fe38b55cSguenther 	return (_thread_cb.tc_errnoptr());
60*fe38b55cSguenther }
61*fe38b55cSguenther DEF_STRONG(__errno);
62*fe38b55cSguenther 
63*fe38b55cSguenther #endif /* !TCB_HAVE_MD_GET */
64*fe38b55cSguenther 
65*fe38b55cSguenther 
66*fe38b55cSguenther struct thread_callbacks _thread_cb =
67*fe38b55cSguenther {
68*fe38b55cSguenther #ifndef	TCB_HAVE_MD_GET
69*fe38b55cSguenther 	.tc_errnoptr	= &single_threaded_errnoptr,
70*fe38b55cSguenther 	.tc_tcb		= &single_threaded_tcb,
71*fe38b55cSguenther #endif
72*fe38b55cSguenther };
73