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*fe38b55cSguenthersingle_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*fe38b55cSguenthersingle_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