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