1 /* Definition for thread-local data handling.  NPTL/SH version.
2    Copyright (C) 2003-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 _TLS_H
20 #define _TLS_H
21 
22 # include <dl-sysdep.h>
23 
24 #ifndef __ASSEMBLER__
25 # include <stdbool.h>
26 # include <stddef.h>
27 # include <stdint.h>
28 # include <stdlib.h>
29 # include <list.h>
30 # include <sysdep.h>
31 # include <dl-dtv.h>
32 
33 typedef struct
34 {
35   dtv_t *dtv;
36   uintptr_t pointer_guard;
37 } tcbhead_t;
38 
39 # define TLS_MULTIPLE_THREADS_IN_TCB 1
40 
41 #else /* __ASSEMBLER__ */
42 # include <tcb-offsets.h>
43 #endif /* __ASSEMBLER__ */
44 
45 
46 #ifndef __ASSEMBLER__
47 
48 /* Get system call information.  */
49 # include <sysdep.h>
50 
51 /* This is the size of the initial TCB.  */
52 # define TLS_INIT_TCB_SIZE sizeof (tcbhead_t)
53 
54 /* This is the size of the TCB.  */
55 # define TLS_TCB_SIZE sizeof (tcbhead_t)
56 
57 /* This is the size we need before TCB.  */
58 # define TLS_PRE_TCB_SIZE sizeof (struct pthread)
59 
60 /* The TLS blocks start right after the TCB.  */
61 # define TLS_DTV_AT_TP	1
62 # define TLS_TCB_AT_TP	0
63 
64 /* Get the thread descriptor definition.  */
65 # include <nptl/descr.h>
66 
67 /* Install the dtv pointer.  The pointer passed is to the element with
68    index -1 which contain the length.  */
69 # define INSTALL_DTV(tcbp, dtvp) \
70   ((tcbhead_t *) (tcbp))->dtv = (dtvp) + 1
71 
72 /* Install new dtv for current thread.  */
73 # define INSTALL_NEW_DTV(dtv) \
74   ({ tcbhead_t *__tcbp;							      \
75      __asm __volatile ("stc gbr,%0" : "=r" (__tcbp));			      \
76      __tcbp->dtv = (dtv);})
77 
78 /* Return dtv of given thread descriptor.  */
79 # define GET_DTV(tcbp) \
80   (((tcbhead_t *) (tcbp))->dtv)
81 
82 /* Code to initially initialize the thread pointer.  This might need
83    special attention since 'errno' is not yet available and if the
84    operation can cause a failure 'errno' must not be touched.  */
85 # define TLS_INIT_TP(tcbp) \
86   ({ __asm __volatile ("ldc %0,gbr" : : "r" (tcbp)); NULL; })
87 
88 # define TLS_DEFINE_INIT_TP(tp, pd) void *tp = (pd) + 1
89 
90 /* Return the address of the dtv for the current thread.  */
91 # define THREAD_DTV() \
92   ({ tcbhead_t *__tcbp;							      \
93      __asm __volatile ("stc gbr,%0" : "=r" (__tcbp));			      \
94      __tcbp->dtv;})
95 
96 /* Return the thread descriptor for the current thread.
97    The contained asm must *not* be marked volatile since otherwise
98    assignments like
99 	struct pthread *self = thread_self();
100    do not get optimized away.  */
101 # define THREAD_SELF \
102   ({ struct pthread *__self;						      \
103      __asm ("stc gbr,%0" : "=r" (__self));				      \
104      __self - 1;})
105 
106 /* Magic for libthread_db to know how to do THREAD_SELF.  */
107 # define DB_THREAD_SELF \
108   REGISTER (32, 32, REG_GBR * 4, -sizeof (struct pthread))
109 
110 # include <tcb-access.h>
111 
112 #define THREAD_GET_POINTER_GUARD() \
113   ({ tcbhead_t *__tcbp;							      \
114      __asm __volatile ("stc gbr,%0" : "=r" (__tcbp));			      \
115      __tcbp->pointer_guard;})
116  #define THREAD_SET_POINTER_GUARD(value) \
117   ({ tcbhead_t *__tcbp;							      \
118      __asm __volatile ("stc gbr,%0" : "=r" (__tcbp));			      \
119      __tcbp->pointer_guard = (value);})
120 #define THREAD_COPY_POINTER_GUARD(descr) \
121   ({ tcbhead_t *__tcbp;							      \
122      __asm __volatile ("stc gbr,%0" : "=r" (__tcbp));			      \
123      ((tcbhead_t *) (descr + 1))->pointer_guard	= __tcbp->pointer_guard;})
124 
125 /* Get and set the global scope generation counter in struct pthread.  */
126 #define THREAD_GSCOPE_FLAG_UNUSED 0
127 #define THREAD_GSCOPE_FLAG_USED   1
128 #define THREAD_GSCOPE_FLAG_WAIT   2
129 #define THREAD_GSCOPE_RESET_FLAG() \
130   do									     \
131     { int __res								     \
132 	= atomic_exchange_rel (&THREAD_SELF->header.gscope_flag,	     \
133 			       THREAD_GSCOPE_FLAG_UNUSED);		     \
134       if (__res == THREAD_GSCOPE_FLAG_WAIT)				     \
135 	lll_futex_wake (&THREAD_SELF->header.gscope_flag, 1, LLL_PRIVATE);   \
136     }									     \
137   while (0)
138 #define THREAD_GSCOPE_SET_FLAG() \
139   do									     \
140     {									     \
141       THREAD_SELF->header.gscope_flag = THREAD_GSCOPE_FLAG_USED;	     \
142       atomic_write_barrier ();						     \
143     }									     \
144   while (0)
145 
146 #endif /* __ASSEMBLER__ */
147 
148 #endif	/* tls.h */
149