diff options
Diffstat (limited to 'include/tib.h')
-rw-r--r-- | include/tib.h | 258 |
1 files changed, 258 insertions, 0 deletions
diff --git a/include/tib.h b/include/tib.h new file mode 100644 index 0000000..8d9216f --- /dev/null +++ b/include/tib.h @@ -0,0 +1,258 @@ +/* $OpenBSD: tib.h,v 1.7 2019/05/10 13:29:21 guenther Exp $ */ +/* + * Copyright (c) 2011,2014 Philip Guenther <guenther@openbsd.org> + * + * Permission to use, copy, modify, and distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +/* + * Thread Information Block (TIB) and Thread Local Storage (TLS) handling + * (the TCB, Thread Control Block, is part of the TIB) + */ + +#ifndef _TIB_H_ +#define _TIB_H_ + +#include <sys/types.h> +#include <machine/tcb.h> + +#include <stddef.h> + + +/* + * This header defines struct tib and at least eight macros: + * TLS_VARIANT + * Either 1 or 2 (Actually defined by <machine/tcb.h>) + * + * TCB_SET(tcb) + * Set the TCB pointer for this thread to 'tcb' + * + * TCB_GET() + * Return the TCB pointer for this thread + * + * TCB_TO_TIB(tcb) + * Given a TCB pointer, return the matching TIB pointer + * + * TIB_TO_TCB(tib) + * Given a TIB pointer, return the matching TCB pointer + * + * TIB_INIT(tib, dtv, thread) + * Initializes a TIB for a new thread, using the supplied + * values for its dtv and thread pointers + * + * TIB_GET() + * Short-hand for TCB_TO_TIB(TCB_GET()) + * + * TIB_EXTRA_ALIGN + * On TLS varaint 2 archs, what alignment is sufficient + * for the extra space that will be used for struct pthread? + * + * The following functions are provided by either ld.so (dynamic) or + * libc (static) for allocating and freeing a common memory block that + * will hold both the TIB and the pthread structure: + * _dl_allocate_tib(sizeof(struct pthread)) + * Allocates a combined TIB and pthread memory region. + * The argument is the amount of space to reserve + * for the pthread structure. Returns a pointer to + * the TIB inside the allocated block. + * + * _dl_free_tib(tib, sizeof(struct pthread)) + * Frees a TIB and pthread block previously allocated + * with _dl_allocate_tib(). Must be passed the return + * value of that previous call. + */ + +/* + * Regarding <machine/tcb.h>: + * - it must define the TLS_VARIANT macro + * - it may define TCB_OFFSET if the TCB address in the kernel and/or + * register is offset from the actual TCB address. TCB_OFFSET > 0 + * means the kernel/register points to *after* the real data. + * - if there's a faster way to get or set the TCB pointer for the thread + * than the __{get,set}_tcb() syscalls, it should define either or both + * the TCB_{GET,SET} macros to do so. + */ + + +/* All archs but mips64 have fast TCB_GET() and don't need caching */ +#ifndef __mips64__ +# define TCB_HAVE_MD_GET 1 +#endif +#ifdef TCB_SET +# define TCB_HAVE_MD_SET 1 +#else +# define TCB_SET(tcb) __set_tcb(tcb) +#endif +#ifndef TCB_OFFSET +# define TCB_OFFSET 0 +#endif + +/* + * tib_cantcancel values is non-zero if the thread should skip all + * cancellation processing + */ +#define CANCEL_DISABLED 1 +#define CANCEL_DYING 2 + +/* + * tib_cancel_point is non-zero if we're in a cancel point; its modified + * by the cancel point code and read by the cancellation signal handler + */ +#define CANCEL_POINT 1 +#define CANCEL_POINT_DELAYED 2 + + +#if TLS_VARIANT == 1 +/* + * ABI specifies that the static TLS data starts two words after the + * (notional) thread pointer, with the first of those two words being + * the TLS dtv pointer. The other (second) word is reserved for the + * implementation, so we place the pointer to the thread structure there, + * but we place our actual thread bits before the TCB, at negative offsets + * from the TCB pointer. Ergo, memory is laid out, low to high, as: + * + * [pthread structure] + * TIB { + * ...cancelation and other int-sized info... + * int errno + * void *locale + * TCB (- TCB_OFFSET) { + * void *dtv + * struct pthread *thread + * } + * } + * static TLS data + */ + +struct tib { + void *tib_atexit; + int tib_thread_flags; /* internal to libpthread */ + pid_t tib_tid; + int tib_cantcancel; + int tib_cancel_point; + int tib_canceled; + int tib_errno; + void *tib_locale; + void *tib_dtv; /* internal to the runtime linker */ + void *tib_thread; +}; + + +#elif TLS_VARIANT == 2 +/* + * ABI specifies that the static TLS data occupies the memory before + * the TCB pointer, at negative offsets, and that on i386 and amd64 + * the word the TCB points to contains a pointer to itself. So, + * we place errno and our thread bits after that. Memory is laid + * out, low to high, as: + * static TLS data + * TIB { + * TCB (- TCB_OFFSET) { + * self pointer [i386/amd64 only] + * void *dtv + * } + * struct pthread *thread + * void *locale + * int errno + * ...cancelation and other int-sized info... + * } + * [pthread structure] + */ + +struct tib { +#if defined(__i386) || defined(__amd64) + struct tib *__tib_self; +# define __tib_tcb __tib_self +#endif + void *tib_dtv; /* internal to the runtime linker */ + void *tib_thread; + void *tib_locale; + int tib_errno; + int tib_canceled; + int tib_cancel_point; + int tib_cantcancel; + pid_t tib_tid; + int tib_thread_flags; /* internal to libpthread */ + void *tib_atexit; +}; + +#if defined(__i386) || defined(__amd64) +# define _TIB_PREP(tib) \ + ((void)((tib)->__tib_self = (tib))) +#endif + +#define TIB_EXTRA_ALIGN sizeof(void *) + +#else +# error "unknown TLS variant" +#endif + +/* nothing to do by default */ +#ifndef _TIB_PREP +# define _TIB_PREP(tib) ((void)0) +#endif + +#define TIB_INIT(tib, dtv, thread) do { \ + (tib)->tib_thread = (thread); \ + (tib)->tib_atexit = NULL; \ + (tib)->tib_locale = NULL; \ + (tib)->tib_cantcancel = 0; \ + (tib)->tib_cancel_point = 0; \ + (tib)->tib_canceled = 0; \ + (tib)->tib_dtv = (dtv); \ + (tib)->tib_errno = 0; \ + _TIB_PREP(tib); \ + } while (0) + +#ifndef __tib_tcb +# define __tib_tcb tib_dtv +#endif +#define _TIBO_TCB (offsetof(struct tib, __tib_tcb) + TCB_OFFSET) + +#define TCB_TO_TIB(tcb) ((struct tib *)((char *)(tcb) - _TIBO_TCB)) +#define TIB_TO_TCB(tib) ((char *)(tib) + _TIBO_TCB) +#define TIB_GET() TCB_TO_TIB(TCB_GET()) + + +__BEGIN_DECLS +struct dl_info; +struct dl_phdr_info; +struct dl_cb_0 { + void *(*dl_allocate_tib)(size_t); + void (*dl_free_tib)(void *, size_t); + void (*dl_clean_boot)(void); + void *(*dlopen)(const char *, int); + int (*dlclose)(void *); + void *(*dlsym)(void *, const char *); + int (*dladdr)(const void *, struct dl_info *); + int (*dlctl)(void *, int, void *); + char *(*dlerror)(void); + int (*dl_iterate_phdr)(int (*)(struct dl_phdr_info *, + size_t, void *), void *); +}; + +#define DL_CB_CUR 0 +typedef struct dl_cb_0 dl_cb; + +/* type of function passed to init functions that returns a dl_cb */ +typedef const void *dl_cb_cb(int _version); + +void *_dl_allocate_tib(size_t _extra) __dso_public; +void _dl_free_tib(void *_tib, size_t _extra) __dso_public; + +/* The actual syscalls */ +void *__get_tcb(void); +void __set_tcb(void *_tcb); +__END_DECLS + +#endif /* _TIB_H_ */ |