1 /* Definition for thread-local data handling. NPTL/ARC version. 2 * 3 * Copyright (C) 2013 Synopsys, Inc. (www.synopsys.com) 4 * 5 * Licensed under the LGPL v2.1 or later, see the file COPYING.LIB in this tarball. 6 */ 7 8 #ifndef _TLS_H 9 #define _TLS_H 10 11 #ifndef __ASSEMBLER__ 12 # include <stdbool.h> 13 # include <stddef.h> 14 # include <stdint.h> 15 # include <stdlib.h> 16 # include <list.h> 17 # include <sysdep.h> 18 # include <bits/kernel-features.h> 19 20 /* Type for the dtv. */ 21 typedef union dtv 22 { 23 size_t counter; 24 struct 25 { 26 void *val; 27 bool is_static; 28 } pointer; 29 } dtv_t; 30 31 typedef struct 32 { 33 dtv_t *dtv; 34 uintptr_t pointer_guard; 35 } tcbhead_t; 36 37 # define TLS_MULTIPLE_THREADS_IN_TCB 1 38 39 #else /* __ASSEMBLER__ */ 40 # include <tcb-offsets.h> 41 42 .macro THREAD_SELF reg 43 # struct pthread is just ahead of TCB 44 sub \reg, r25, TLS_PRE_TCB_SIZE 45 .endm 46 47 .macro SET_TP tcb 48 mov r25, \tcb 49 .endm 50 51 #endif /* __ASSEMBLER__ */ 52 53 54 /* We require TLS support in the tools. */ 55 #define HAVE_TLS_SUPPORT 56 #define HAVE___THREAD 1 57 #define HAVE_TLS_MODEL_ATTRIBUTE 1 58 /* Signal that TLS support is available. */ 59 # define USE_TLS 1 60 61 #ifndef __ASSEMBLER__ 62 63 /* Get system call information. */ 64 # include <sysdep.h> 65 66 /* This is the size of the initial TCB. */ 67 # define TLS_INIT_TCB_SIZE sizeof (tcbhead_t) 68 69 /* Alignment requirements for the initial TCB. */ 70 # define TLS_INIT_TCB_ALIGN __alignof__ (tcbhead_t) 71 72 /* This is the size of the TCB. */ 73 #ifndef TLS_TCB_SIZE 74 # define TLS_TCB_SIZE sizeof (tcbhead_t) 75 #endif 76 77 /* This is the size we need before TCB. */ 78 # define TLS_PRE_TCB_SIZE sizeof (struct pthread) 79 80 /* Alignment requirements for the TCB. */ 81 # define TLS_TCB_ALIGN __alignof__ (struct pthread) 82 83 /* The TLS blocks start right after the TCB. */ 84 # define TLS_DTV_AT_TP 1 85 86 /* Get the thread descriptor definition. */ 87 # include <descr.h> 88 89 /* Install the dtv pointer. The pointer passed is to the element with 90 index -1 which contain the length. */ 91 # define INSTALL_DTV(tcbp, dtvp) \ 92 ((tcbhead_t *) (tcbp))->dtv = (dtvp) + 1 93 94 /* Install new dtv for current thread. */ 95 # define INSTALL_NEW_DTV(dtv) \ 96 (THREAD_DTV() = (dtv)) 97 98 /* Return dtv of given thread descriptor. */ 99 # define GET_DTV(tcbp) \ 100 (((tcbhead_t *) (tcbp))->dtv) 101 102 /* Code to initially initialize the thread pointer. This might need 103 special attention since 'errno' is not yet available and if the 104 operation can cause a failure 'errno' must not be touched. */ 105 # define TLS_INIT_TP(tcbp, secondcall) \ 106 ({ \ 107 long result_var; \ 108 __builtin_set_thread_pointer(tcbp); \ 109 result_var = INTERNAL_SYSCALL (arc_settls, err, 1, (tcbp)); \ 110 INTERNAL_SYSCALL_ERROR_P (result_var, err) \ 111 ? "unknown error" : NULL; \ 112 }) 113 114 /* Return the address of the dtv for the current thread. 115 TP points to TCB where 1st item is dtv pointer */ 116 # define THREAD_DTV() \ 117 (((tcbhead_t *)__builtin_thread_pointer())->dtv) 118 119 /* Return the thread descriptor for the current thread. 120 pthread sits right before TCB */ 121 # define THREAD_SELF \ 122 ((struct pthread *)__builtin_thread_pointer() - 1) 123 124 /* Magic for libthread_db to know how to do THREAD_SELF. */ 125 # define DB_THREAD_SELF \ 126 CONST_THREAD_AREA (32, sizeof (struct pthread)) 127 128 /* Access to data in the thread descriptor is easy. */ 129 #define THREAD_GETMEM(descr, member) \ 130 descr->member 131 #define THREAD_GETMEM_NC(descr, member, idx) \ 132 descr->member[idx] 133 #define THREAD_SETMEM(descr, member, value) \ 134 descr->member = (value) 135 #define THREAD_SETMEM_NC(descr, member, idx, value) \ 136 descr->member[idx] = (value) 137 138 /* Get and set the global scope generation counter in struct pthread. */ 139 #define THREAD_GSCOPE_FLAG_UNUSED 0 140 #define THREAD_GSCOPE_FLAG_USED 1 141 #define THREAD_GSCOPE_FLAG_WAIT 2 142 #define THREAD_GSCOPE_RESET_FLAG() \ 143 do \ 144 { int __res \ 145 = atomic_exchange_rel (&THREAD_SELF->header.gscope_flag, \ 146 THREAD_GSCOPE_FLAG_UNUSED); \ 147 if (__res == THREAD_GSCOPE_FLAG_WAIT) \ 148 lll_futex_wake (&THREAD_SELF->header.gscope_flag, 1, LLL_PRIVATE); \ 149 } \ 150 while (0) 151 #define THREAD_GSCOPE_SET_FLAG() \ 152 do \ 153 { \ 154 THREAD_SELF->header.gscope_flag = THREAD_GSCOPE_FLAG_USED; \ 155 atomic_write_barrier (); \ 156 } \ 157 while (0) 158 #define THREAD_GSCOPE_WAIT() \ 159 GL(dl_wait_lookup_done) () 160 161 #endif /* __ASSEMBLER__ */ 162 163 #endif /* tls.h */ 164