1 /*
2  * This file is subject to the terms and conditions of the LGPL V2.1
3  * License.  See the file "COPYING" in the main directory of this archive
4  * for more details.
5  *
6  * Copyright (C) 2019 Kalray Inc.
7  */
8 
9 #ifndef _TLS_H
10 #define _TLS_H	1
11 
12 #ifndef __ASSEMBLER__
13 # include <stdbool.h>
14 # include <stddef.h>
15 # include <stdint.h>
16 
17 /* Type for the dtv.  */
18 typedef union dtv
19 {
20   size_t counter;
21   struct
22   {
23     void *val;
24     bool is_static;
25   } pointer;
26 } dtv_t;
27 
28 #else /* __ASSEMBLER__ */
29 # include <tcb-offsets.h>
30 #endif /* __ASSEMBLER__ */
31 
32 /* We require TLS support in the tools.  */
33 #define HAVE_TLS_SUPPORT                1
34 #define HAVE_TLS_MODEL_ATTRIBUTE        1
35 #define HAVE___THREAD                   1
36 
37 /* Signal that TLS support is available.  */
38 #define USE_TLS	1
39 
40 #ifndef __ASSEMBLER__
41 
42 /* Get system call information.  */
43 # include <sysdep.h>
44 
45 /* The TP points to the start of the thread blocks.  */
46 # define TLS_DTV_AT_TP	1
47 
48 /* Get the thread descriptor definition.  */
49 # include <../../descr.h>
50 
51 typedef struct
52 {
53   dtv_t *dtv;
54 } tcbhead_t;
55 
56 /* Thread Pointer $tp is $r13 */
57 register tcbhead_t *__thread_self __asm__("$r13");
58 
59 /* This is the size of the initial TCB.  */
60 # define TLS_INIT_TCB_SIZE	sizeof (tcbhead_t)
61 
62 /* Alignment requirements for the initial TCB.  */
63 # define TLS_INIT_TCB_ALIGN	__alignof__ (tcbhead_t)
64 
65 /* This is the size of the TCB.  */
66 # define TLS_TCB_SIZE		sizeof (tcbhead_t)
67 
68 /* This is the size we need before TCB.  */
69 # define TLS_PRE_TCB_SIZE	sizeof (struct pthread)
70 
71 /* Alignment requirements for the TCB.  */
72 # define TLS_TCB_ALIGN		__alignof__ (tcbhead_t)
73 
74 /* Install the dtv pointer.  The pointer passed is to the element with
75    index -1 which contain the length.  */
76 # define INSTALL_DTV(tcbp, dtvp) \
77   (((tcbhead_t *) (tcbp))->dtv = (dtvp) + 1)
78 
79 /* Install new dtv for current thread.  */
80 # define INSTALL_NEW_DTV(dtv) \
81   (THREAD_DTV() = (dtv))
82 
83 /* Return dtv of given thread descriptor.  */
84 # define GET_DTV(tcbp) \
85   (((tcbhead_t *) (tcbp))->dtv)
86 
87 /* Code to initially initialize the thread pointer.
88  *
89  * Set TP to the address _after_ tcbhead_t. This will allow us
90  * to change the size of tcbhead_t without having to re-link everything.
91  *
92  * secondcall has something to do with USE__THREAD,
93  * seems to always be 0 so we don't care about it.
94  *
95  * This has to return NULL on success (or a string with the failure text).
96  * It's hard to fail this, so return NULL always.
97  */
98 # define TLS_INIT_TP(tcbp, secondcall) \
99   ({__thread_self = ((tcbhead_t *)tcbp + 1); NULL;})
100 
101 /* Return the address of the dtv for the current thread.
102  *
103  * Dereference TP, offset to dtv - really straightforward.
104  * Remember that we made TP point to after tcb, so we need to reverse that.
105  */
106 #  define THREAD_DTV() \
107   ((((tcbhead_t *)__thread_self)-1)->dtv)
108 
109 /* Return the thread descriptor for the current thread.
110  *
111  * Return a pointer to the TLS_PRE area where we allocated space for
112  * a struct pthread. Again, TP points to after tcbhead_t, compensate with
113  * TLS_INIT_TCB_SIZE.
114  *
115  * I regard this is a seperate system from the "normal" TLS.
116  */
117 # define THREAD_SELF \
118   ((struct pthread *) ((char *) __thread_self - TLS_INIT_TCB_SIZE \
119     - TLS_PRE_TCB_SIZE))
120 
121 /* Magic for libthread_db to know how to do THREAD_SELF.  */
122 # define DB_THREAD_SELF \
123   CONST_THREAD_AREA (64, sizeof (struct pthread))
124 
125 /* Access to data in the thread descriptor is easy.  */
126 # define THREAD_GETMEM(descr, member) \
127   descr->member
128 # define THREAD_GETMEM_NC(descr, member, idx) \
129   descr->member[idx]
130 # define THREAD_SETMEM(descr, member, value) \
131   descr->member = (value)
132 # define THREAD_SETMEM_NC(descr, member, idx, value) \
133   descr->member[idx] = (value)
134 
135 /* Get and set the global scope generation counter in struct pthread.  */
136 # define THREAD_GSCOPE_FLAG_UNUSED 0
137 # define THREAD_GSCOPE_FLAG_USED   1
138 # define THREAD_GSCOPE_FLAG_WAIT   2
139 # define THREAD_GSCOPE_RESET_FLAG() \
140   do									     \
141     { int __res								     \
142 	= atomic_exchange_rel (&THREAD_SELF->header.gscope_flag,	     \
143 			       THREAD_GSCOPE_FLAG_UNUSED);		     \
144       if (__res == THREAD_GSCOPE_FLAG_WAIT)				     \
145 	lll_futex_wake (&THREAD_SELF->header.gscope_flag, 1, LLL_PRIVATE);   \
146     }									     \
147   while (0)
148 # define THREAD_GSCOPE_SET_FLAG() \
149   do									     \
150     {									     \
151       THREAD_SELF->header.gscope_flag = THREAD_GSCOPE_FLAG_USED;	     \
152       atomic_write_barrier ();						     \
153     }									     \
154   while (0)
155 # define THREAD_GSCOPE_WAIT() \
156   GL(dl_wait_lookup_done) ()
157 
158 # endif /* __ASSEMBLER__ */
159 
160 #endif	/* tls.h */
161