1 /* Definition for thread-local data handling. NPTL/OR1K version. 2 Copyright (C) 2005, 2007, 2011 Free Software Foundation, Inc. 3 This file is part of the GNU C Library. 4 5 The GNU C Library is free software; you can redistribute it and/or 6 modify it under the terms of the GNU Lesser General Public 7 License as published by the Free Software Foundation; either 8 version 2.1 of the License, or (at your option) any later version. 9 10 The GNU C Library is distributed in the hope that it will be useful, 11 but WITHOUT ANY WARRANTY; without even the implied warranty of 12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 13 Lesser General Public License for more details. 14 15 You should have received a copy of the GNU Lesser General Public 16 License along with the GNU C Library. If not, see 17 <http://www.gnu.org/licenses/>. */ 18 19 #ifndef _TLS_H 20 #define _TLS_H 1 21 22 #ifndef __ASSEMBLER__ 23 # include <stdbool.h> 24 # include <stddef.h> 25 # include <stdint.h> 26 27 /* Type for the dtv. */ 28 typedef union dtv 29 { 30 size_t counter; 31 struct 32 { 33 void *val; 34 bool is_static; 35 } pointer; 36 } dtv_t; 37 38 typedef struct 39 { 40 dtv_t *dtv; 41 } tcbhead_t; 42 43 register tcbhead_t *__thread_self __asm__("r10"); 44 45 # define TLS_MULTIPLE_THREADS_IN_TCB 1 46 47 #else /* __ASSEMBLER__ */ 48 # include <tcb-offsets.h> 49 #endif /* __ASSEMBLER__ */ 50 51 /* We require TLS support in the tools. */ 52 #define HAVE_TLS_SUPPORT 1 53 #define HAVE_TLS_MODEL_ATTRIBUTE 1 54 #define HAVE___THREAD 1 55 56 /* Signal that TLS support is available. */ 57 #define USE_TLS 1 58 59 #ifndef __ASSEMBLER__ 60 61 /* Get system call information. */ 62 # include <sysdep.h> 63 64 /* The TP points to the start of the TLS block. 65 * As I understand it, this isn't strictly that "TP points to DTV" - it's 66 * more where to place the TCB in the TLS block. This will place it in 67 * the beginning. 68 * 69 * Layout: 70 * ------------------------------------ 71 * | PRE | TCB | TLS MEMORY .. | 72 * ------------------------------------ 73 * ^ r10 / TP 74 * 75 * PRE is the struct pthread described below 76 * TCB is tcbhead_t 77 * TLS memory is where the TLS program sections are loaded 78 * 79 * See _dl_allocate_tls_storage and __libc_setup_tls for more information. 80 */ 81 # define TLS_DTV_AT_TP 1 82 83 /* Get the thread descriptor definition. */ 84 # include <../../descr.h> 85 86 /* Requirements for the TCB. */ 87 # define TLS_INIT_TCB_SIZE sizeof (tcbhead_t) 88 # define TLS_INIT_TCB_ALIGN __alignof__ (tcbhead_t) 89 90 # define TLS_TCB_SIZE sizeof (tcbhead_t) 91 # define TLS_TCB_ALIGN __alignof__ (tcbhead_t) 92 93 /* This is the size of the TCB. */ 94 95 /* This is the size we need before TCB. 96 * To support THREAD_GETMEM with friends we want to have a 97 * struct pthread available. 98 * Yank it in infront of everything, I'm sure nobody will mind. 99 * 100 * This memory is really allocated PRE the TLS block, so it's possible 101 * to do ((char*)tlsblock) - TLS_PRE_TCB_SIZE to access it. 102 * This is done for THREAD_SELF. */ 103 # define TLS_PRE_TCB_SIZE sizeof (struct pthread) 104 105 106 /* Install the dtv pointer. 107 * When called, dtvp is a pointer not the DTV per say (which should start 108 * with the generation counter) but to the length of the DTV. 109 * We can always index with -1, so we store dtvp[1] 110 */ 111 # define INSTALL_DTV(tcbp, dtvp) \ 112 (((tcbhead_t *) (tcbp))->dtv = (dtvp) + 1) 113 114 /* Install new dtv for current thread 115 * In a logicial world dtv here would also point to the length of the DTV. 116 * However it does not, this time it points to the generation counter, 117 * so just store it. 118 * 119 * Note: -1 is still valid and contains the length. */ 120 # define INSTALL_NEW_DTV(dtv) \ 121 (THREAD_DTV() = (dtv)) 122 123 /* Return dtv of given thread descriptor. */ 124 # define GET_DTV(tcbp) \ 125 (((tcbhead_t *) (tcbp))->dtv) 126 127 /* Code to initially initialize the thread pointer. 128 * 129 * Set TP to the address _after_ tcbhead_t. This will allow us 130 * to change the size of tcbhead_t without having to re-link everything. 131 * 132 * secondcall has something to do with USE__THREAD, 133 * seems to always be 0 so we don't care about it. 134 * 135 * This has to return NULL on success (or a string with the failure text). 136 * It's hard to fail this, so return NULL always. 137 */ 138 # define TLS_INIT_TP(tcbp, secondcall) \ 139 ({__thread_self = ((tcbhead_t *)tcbp + 1); NULL;}) 140 141 /* Return the address of the dtv for the current thread. 142 * 143 * Dereference TP, offset to dtv - really straightforward. 144 * Remember that we made TP point to after tcb, so we need to reverse that. 145 */ 146 # define THREAD_DTV() \ 147 ((((tcbhead_t *)__thread_self)-1)->dtv) 148 149 /* Return the thread descriptor for the current thread. 150 * 151 * Return a pointer to the TLS_PRE area where we allocated space for 152 * a struct pthread. Again, TP points to after tcbhead_t, compensate with 153 * TLS_INIT_TCB_SIZE. 154 * 155 * I regard this is a seperate system from the "normal" TLS. 156 */ 157 # define THREAD_SELF \ 158 ((struct pthread *) ((char *) __thread_self - TLS_INIT_TCB_SIZE \ 159 - TLS_PRE_TCB_SIZE)) 160 161 /* Magic for libthread_db to know how to do THREAD_SELF. */ 162 # define DB_THREAD_SELF \ 163 CONST_THREAD_AREA (32, sizeof (struct pthread)) 164 165 /* Access to data in the thread descriptor is easy. */ 166 #define THREAD_GETMEM(descr, member) \ 167 descr->member 168 #define THREAD_GETMEM_NC(descr, member, idx) \ 169 descr->member[idx] 170 #define THREAD_SETMEM(descr, member, value) \ 171 descr->member = (value) 172 #define THREAD_SETMEM_NC(descr, member, idx, value) \ 173 descr->member[idx] = (value) 174 175 /* Get and set the global scope generation counter in struct pthread. */ 176 #define THREAD_GSCOPE_FLAG_UNUSED 0 177 #define THREAD_GSCOPE_FLAG_USED 1 178 #define THREAD_GSCOPE_FLAG_WAIT 2 179 #define THREAD_GSCOPE_RESET_FLAG() \ 180 do \ 181 { int __res \ 182 = atomic_exchange_rel (&THREAD_SELF->header.gscope_flag, \ 183 THREAD_GSCOPE_FLAG_UNUSED); \ 184 if (__res == THREAD_GSCOPE_FLAG_WAIT) \ 185 lll_futex_wake (&THREAD_SELF->header.gscope_flag, 1, LLL_PRIVATE); \ 186 } \ 187 while (0) 188 #define THREAD_GSCOPE_SET_FLAG() \ 189 do \ 190 { \ 191 THREAD_SELF->header.gscope_flag = THREAD_GSCOPE_FLAG_USED; \ 192 atomic_write_barrier (); \ 193 } \ 194 while (0) 195 #define THREAD_GSCOPE_WAIT() \ 196 GL(dl_wait_lookup_done) () 197 198 #endif /* __ASSEMBLER__ */ 199 200 #endif /* tls.h */ 201 202