/* $OpenBSD: tib.h,v 1.7 2019/05/10 13:29:21 guenther Exp $ */ /* * Copyright (c) 2011,2014 Philip Guenther * * 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 #include #include /* * This header defines struct tib and at least eight macros: * TLS_VARIANT * Either 1 or 2 (Actually defined by ) * * 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 : * - 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_ */