diff options
Diffstat (limited to 'lib/libc/gen/errno.c')
-rw-r--r-- | lib/libc/gen/errno.c | 67 |
1 files changed, 59 insertions, 8 deletions
diff --git a/lib/libc/gen/errno.c b/lib/libc/gen/errno.c index 62c0978c6aa..d706b0807a7 100644 --- a/lib/libc/gen/errno.c +++ b/lib/libc/gen/errno.c @@ -1,21 +1,72 @@ -/* $OpenBSD: errno.c,v 1.5 2005/08/08 08:05:34 espie Exp $ */ +/* $OpenBSD: errno.c,v 1.6 2016/05/07 19:05:22 guenther Exp $ */ /* PUBLIC DOMAIN: No Rights Reserved. Marco S Hyman <marc@snafu.org> */ +#include <tib.h> #include <errno.h> -#undef errno +#include <unistd.h> +#include "thread_private.h" + +#ifdef TCB_HAVE_MD_GET /* - * global errno for unthreaded programs. + * If there's an MD TCB_GET() macro, then getting the TCB address is + * cheap enough that we can do it even in single-threaded programs, + * so the tc_errnoptr and tc_tcb callbacks will be unused, and __errno() + * can just use TIB_GET(). */ -int errno; +int * +__errno(void) +{ + return (&TIB_GET()->tib_errno); +} +DEF_STRONG(__errno); +#else /* ! TCB_HAVE_MD_GET */ /* - * weak version of function used by unthreaded programs. + * Otherwise, getting the TCB address requires the __get_tcb() + * syscall. Rather than pay that cost for single-threaded programs, + * the syscall stubs will invoke the tc_errnoptr callback to set errno + * and other code will invoke the tc_tcb callback to get the TCB + * for cancelation checks, etc. The default callbacks will just + * work from the cached location of the initial thread's TCB; + * libpthread can override them to the necessary more expensive + * versions that use __get_tcb(). + */ + +/* cached pointer to the TCB of the only thread in single-threaded programs */ +void *_libc_single_tcb = NULL; + +static inline void * +single_threaded_tcb(void) +{ + if (__predict_false(_libc_single_tcb == NULL)) + _libc_single_tcb = TCB_GET(); + return (_libc_single_tcb); +} + +static int * +single_threaded_errnoptr(void) +{ + return &TCB_TO_TIB(single_threaded_tcb())->tib_errno; +} + +/* + * __errno(): just use the callback to get the applicable current method */ int * -___errno(void) +__errno(void) { - return &errno; + return (_thread_cb.tc_errnoptr()); } +DEF_STRONG(__errno); + +#endif /* !TCB_HAVE_MD_GET */ -__weak_alias(__errno, ___errno); + +struct thread_callbacks _thread_cb = +{ +#ifndef TCB_HAVE_MD_GET + .tc_errnoptr = &single_threaded_errnoptr, + .tc_tcb = &single_threaded_tcb, +#endif +}; |