1 /* Definition for thread-local data handling.  NPTL/s390 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	1
21 
22 #include <dl-sysdep.h>
23 #ifndef __ASSEMBLER__
24 # include <stdbool.h>
25 # include <stddef.h>
26 # include <stdint.h>
27 # include <stdlib.h>
28 # include <list.h>
29 # include <kernel-features.h>
30 # include <dl-dtv.h>
31 
32 typedef struct
33 {
34   void *tcb;		/* Pointer to the TCB.  Not necessary the
35 			   thread descriptor used by libpthread.  */
36   dtv_t *dtv;
37   void *self;		/* Pointer to the thread descriptor.  */
38   int multiple_threads;
39   uintptr_t sysinfo;
40   uintptr_t stack_guard;
41   int gscope_flag;
42   int __glibc_reserved1;
43   /* GCC split stack support.  */
44   void *__private_ss;
45 } tcbhead_t;
46 
47 # ifndef __s390x__
48 #  define TLS_MULTIPLE_THREADS_IN_TCB 1
49 # endif
50 
51 #else /* __ASSEMBLER__ */
52 # include <tcb-offsets.h>
53 #endif
54 
55 
56 /* Alignment requirement for the stack.  For IA-32 this is governed by
57    the SSE memory functions.  */
58 #define STACK_ALIGN	16
59 
60 #ifndef __ASSEMBLER__
61 /* Get system call information.  */
62 # include <sysdep.h>
63 
64 /* This is the size of the initial TCB.  Can't be just sizeof (tcbhead_t),
65    because NPTL getpid, __libc_alloca_cutoff etc. need (almost) the whole
66    struct pthread even when not linked with -lpthread.  */
67 # define TLS_INIT_TCB_SIZE sizeof (struct pthread)
68 
69 /* This is the size of the TCB.  */
70 # define TLS_TCB_SIZE sizeof (struct pthread)
71 
72 /* The TCB can have any size and the memory following the address the
73    thread pointer points to is unspecified.  Allocate the TCB there.  */
74 # define TLS_TCB_AT_TP	1
75 # define TLS_DTV_AT_TP	0
76 
77 /* Get the thread descriptor definition.  */
78 # include <nptl/descr.h>
79 
80 
81 /* Install the dtv pointer.  The pointer passed is to the element with
82    index -1 which contain the length.  */
83 #  define INSTALL_DTV(descr, dtvp) \
84   ((tcbhead_t *) (descr))->dtv = (dtvp) + 1
85 
86 /* Install new dtv for current thread.  */
87 #  define INSTALL_NEW_DTV(dtv) \
88   (((tcbhead_t *) __builtin_thread_pointer ())->dtv = (dtv))
89 
90 /* Return dtv of given thread descriptor.  */
91 #  define GET_DTV(descr) \
92   (((tcbhead_t *) (descr))->dtv)
93 
94 #if defined NEED_DL_SYSINFO && defined SHARED
95 # define INIT_SYSINFO \
96   _head->sysinfo = GLRO(dl_sysinfo)
97 #else
98 # define INIT_SYSINFO
99 #endif
100 
101 /* Code to initially initialize the thread pointer.  This might need
102    special attention since 'errno' is not yet available and if the
103    operation can cause a failure 'errno' must not be touched.  */
104 # define TLS_INIT_TP(thrdescr) \
105   ({ void *_thrdescr = (thrdescr);					      \
106      tcbhead_t *_head = _thrdescr;					      \
107 									      \
108      _head->tcb = _thrdescr;						      \
109      /* For now the thread descriptor is at the same address.  */	      \
110      _head->self = _thrdescr;						      \
111      /* New syscall handling support.  */				      \
112      INIT_SYSINFO;							      \
113 									      \
114     __builtin_set_thread_pointer (_thrdescr);				      \
115     NULL;								      \
116   })
117 
118 /* Value passed to 'clone' for initialization of the thread register.  */
119 # define TLS_DEFINE_INIT_TP(tp, pd) void *tp = (pd)
120 
121 /* Return the address of the dtv for the current thread.  */
122 #  define THREAD_DTV() \
123   (((tcbhead_t *) __builtin_thread_pointer ())->dtv)
124 
125 /* Return the thread descriptor for the current thread.  */
126 # define THREAD_SELF ((struct pthread *) __builtin_thread_pointer ())
127 
128 /* Magic for libthread_db to know how to do THREAD_SELF.  */
129 # define DB_THREAD_SELF REGISTER (32, 32, 18 * 4, 0) \
130 			REGISTER (64, __WORDSIZE, 18 * 8, 0)
131 
132 # include <tcb-access.h>
133 
134 /* Set the stack guard field in TCB head.  */
135 #define THREAD_SET_STACK_GUARD(value) \
136   do									      \
137    {									      \
138      __asm__ __volatile__ ("" : : : "a0", "a1");			      \
139      THREAD_SETMEM (THREAD_SELF, header.stack_guard, value);		      \
140    }									      \
141   while (0)
142 #define THREAD_COPY_STACK_GUARD(descr) \
143   ((descr)->header.stack_guard						      \
144    = THREAD_GETMEM (THREAD_SELF, header.stack_guard))
145 
146 /* s390 doesn't have HP_TIMING_*, so for the time being
147    use stack_guard as pointer_guard.  */
148 #define THREAD_GET_POINTER_GUARD() \
149   THREAD_GETMEM (THREAD_SELF, header.stack_guard)
150 #define THREAD_SET_POINTER_GUARD(value)	((void) (value))
151 #define THREAD_COPY_POINTER_GUARD(descr)
152 
153 /* Get and set the global scope generation counter in struct pthread.  */
154 #define THREAD_GSCOPE_FLAG_UNUSED 0
155 #define THREAD_GSCOPE_FLAG_USED   1
156 #define THREAD_GSCOPE_FLAG_WAIT   2
157 #define THREAD_GSCOPE_RESET_FLAG() \
158   do									     \
159     { int __res								     \
160 	= atomic_exchange_rel (&THREAD_SELF->header.gscope_flag,	     \
161 			       THREAD_GSCOPE_FLAG_UNUSED);		     \
162       if (__res == THREAD_GSCOPE_FLAG_WAIT)				     \
163 	lll_futex_wake (&THREAD_SELF->header.gscope_flag, 1, LLL_PRIVATE);   \
164     }									     \
165   while (0)
166 #define THREAD_GSCOPE_SET_FLAG() \
167   do									     \
168     {									     \
169       THREAD_SELF->header.gscope_flag = THREAD_GSCOPE_FLAG_USED;	     \
170       atomic_write_barrier ();						     \
171     }									     \
172   while (0)
173 
174 #endif /* __ASSEMBLER__ */
175 
176 #endif	/* tls.h */
177