1 /* Definition for thread-local data handling. 2 Copyright (C) 2022 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 <https://www.gnu.org/licenses/>. */ 18 19 #ifndef _LOONGARCH_TLS_H 20 #define _LOONGARCH_TLS_H 1 21 22 #include <dl-sysdep.h> 23 24 #ifndef __ASSEMBLER__ 25 #include <stdbool.h> 26 #include <stddef.h> 27 #include <stdint.h> 28 #include <dl-dtv.h> 29 30 register void *__thread_self asm ("$tp"); 31 #define READ_THREAD_POINTER() ({ __thread_self; }) 32 33 /* Get system call information. */ 34 #include <sysdep.h> 35 36 /* The TP points to the start of the thread blocks. */ 37 #define TLS_DTV_AT_TP 1 38 #define TLS_TCB_AT_TP 0 39 40 /* Get the thread descriptor definition. */ 41 #include <nptl/descr.h> 42 43 typedef struct 44 { 45 dtv_t *dtv; 46 void *private; 47 } tcbhead_t; 48 49 /* This is the size of the initial TCB. Because our TCB is before the thread 50 pointer, we don't need this. */ 51 #define TLS_INIT_TCB_SIZE 0 52 53 /* Alignment requirements for the initial TCB. */ 54 #define TLS_INIT_TCB_ALIGN __alignof__(struct pthread) 55 56 /* This is the size of the TCB. Because our TCB is before the thread 57 pointer, we don't need this. */ 58 #define TLS_TCB_SIZE 0 59 60 /* Alignment requirements for the TCB. */ 61 #define TLS_TCB_ALIGN __alignof__(struct pthread) 62 63 /* This is the size we need before TCB - actually, it includes the TCB. */ 64 #define TLS_PRE_TCB_SIZE \ 65 (sizeof (struct pthread) \ 66 + ((sizeof (tcbhead_t) + TLS_TCB_ALIGN - 1) & ~(TLS_TCB_ALIGN - 1))) 67 68 /* The thread pointer tp points to the end of the TCB. 69 The pthread_descr structure is immediately in front of the TCB. */ 70 #define TLS_TCB_OFFSET 0 71 72 /* Install the dtv pointer. The pointer passed is to the element with 73 index -1 which contain the length. */ 74 #define INSTALL_DTV(tcbp, dtvp) (((tcbhead_t *) (tcbp))[-1].dtv = (dtvp) + 1) 75 76 /* Install new dtv for current thread. */ 77 #define INSTALL_NEW_DTV(dtv) (THREAD_DTV () = (dtv)) 78 79 /* Return dtv of given thread descriptor. */ 80 #define GET_DTV(tcbp) (((tcbhead_t *) (tcbp))[-1].dtv) 81 82 /* Code to initially initialize the thread pointer. */ 83 #define TLS_INIT_TP(tcbp) \ 84 ({ \ 85 __thread_self = (char *) tcbp + TLS_TCB_OFFSET; \ 86 NULL; \ 87 }) 88 89 /* Return the address of the dtv for the current thread. */ 90 #define THREAD_DTV() \ 91 (((tcbhead_t *) (READ_THREAD_POINTER () - TLS_TCB_OFFSET))[-1].dtv) 92 93 /* Return the thread descriptor for the current thread. */ 94 #define THREAD_SELF \ 95 ((struct pthread *) (READ_THREAD_POINTER () - TLS_TCB_OFFSET \ 96 - TLS_PRE_TCB_SIZE)) 97 98 /* Value passed to 'clone' for initialization of the thread register. */ 99 #define TLS_DEFINE_INIT_TP(tp, pd) \ 100 void *tp = (void *) (pd) + TLS_TCB_OFFSET + TLS_PRE_TCB_SIZE 101 102 /* Informs libthread_db that the thread pointer is register 2, which is used 103 * to know how to do THREAD_SELF. */ 104 #define DB_THREAD_SELF \ 105 REGISTER (64, 64, 2 * 8, -TLS_TCB_OFFSET - TLS_PRE_TCB_SIZE) 106 107 /* Access to data in the thread descriptor is easy. */ 108 # include <tcb-access.h> 109 110 /* l_tls_offset == 0 is perfectly valid, so we have to use some different 111 value to mean unset l_tls_offset. */ 112 #define NO_TLS_OFFSET -1 113 114 /* Get and set the global scope generation counter in struct pthread. */ 115 #define THREAD_GSCOPE_IN_TCB 1 116 #define THREAD_GSCOPE_FLAG_UNUSED 0 117 #define THREAD_GSCOPE_FLAG_USED 1 118 #define THREAD_GSCOPE_FLAG_WAIT 2 119 #define THREAD_GSCOPE_RESET_FLAG() \ 120 do \ 121 { \ 122 int __res = atomic_exchange_rel (&THREAD_SELF->header.gscope_flag, \ 123 THREAD_GSCOPE_FLAG_UNUSED); \ 124 if (__res == THREAD_GSCOPE_FLAG_WAIT) \ 125 lll_futex_wake (&THREAD_SELF->header.gscope_flag, 1, LLL_PRIVATE); \ 126 } \ 127 while (0) 128 #define THREAD_GSCOPE_SET_FLAG() \ 129 do \ 130 { \ 131 THREAD_SELF->header.gscope_flag = THREAD_GSCOPE_FLAG_USED; \ 132 atomic_write_barrier (); \ 133 } \ 134 while (0) 135 136 #endif /* __ASSEMBLER__ */ 137 138 #endif /* tls.h */ 139