root/mtcp/NOTES-x86_64/tls-x86_64.h

/* [<][>][^][v][top][bottom][index][help] */
   1 /* Definition for thread-local data handling.  nptl/x86_64 version.
   2    Copyright (C) 2002, 2003, 2004, 2005, 2006 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, write to the Free
  17    Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
  18    02111-1307 USA.  */
  19 
  20 #ifndef _TLS_H
  21 #define _TLS_H  1
  22 
  23 #ifndef __ASSEMBLER__
  24 # include <asm/prctl.h> /* For ARCH_SET_FS.  */
  25 # include <stdbool.h>
  26 # include <stddef.h>
  27 # include <stdint.h>
  28 # include <stdlib.h>
  29 
  30 
  31 /* Type for the dtv.  */
  32 typedef union dtv
  33 {
  34   size_t counter;
  35   struct
  36   {
  37     void *val;
  38     bool is_static;
  39   } pointer;
  40 } dtv_t;
  41 
  42 
  43 typedef struct
  44 {
  45   void *tcb;            /* Pointer to the TCB.  Not necessary the
  46                            thread descriptor used by libpthread.  */
  47   dtv_t *dtv;
  48   void *self;           /* Pointer to the thread descriptor.  */
  49   int multiple_threads;
  50   uintptr_t sysinfo;
  51   uintptr_t stack_guard;
  52   uintptr_t pointer_guard;
  53 } tcbhead_t;
  54 
  55 #else /* __ASSEMBLER__ */
  56 # include <tcb-offsets.h>
  57 #endif
  58 
  59 
  60 /* We require TLS support in the tools.  */
  61 #ifndef HAVE_TLS_SUPPORT
  62 # error "TLS support is required."
  63 #endif
  64 
  65 /* Signal that TLS support is available.  */
  66 #define USE_TLS 1
  67 
  68 /* Alignment requirement for the stack.  */
  69 #define STACK_ALIGN     16
  70 
  71 
  72 #ifndef __ASSEMBLER__
  73 /* Get system call information.  */
  74 # include <sysdep.h>
  75 
  76 
  77 /* Get the thread descriptor definition.  */
  78 # include <nptl/descr.h>
  79 
  80 #ifndef LOCK_PREFIX
  81 # ifdef UP
  82 #  define LOCK_PREFIX   /* nothing */
  83 # else
  84 #  define LOCK_PREFIX   "lock;"
  85 # endif
  86 #endif
  87 
  88 /* This is the size of the initial TCB.  Can't be just sizeof (tcbhead_t),
  89    because NPTL getpid, __libc_alloca_cutoff etc. need (almost) the whole
  90    struct pthread even when not linked with -lpthread.  */
  91 # define TLS_INIT_TCB_SIZE sizeof (struct pthread)
  92 
  93 /* Alignment requirements for the initial TCB.  */
  94 # define TLS_INIT_TCB_ALIGN __alignof__ (struct pthread)
  95 
  96 /* This is the size of the TCB.  */
  97 # define TLS_TCB_SIZE sizeof (struct pthread)
  98 
  99 /* Alignment requirements for the TCB.  */
 100 # define TLS_TCB_ALIGN __alignof__ (struct pthread)
 101 
 102 /* The TCB can have any size and the memory following the address the
 103    thread pointer points to is unspecified.  Allocate the TCB there.  */
 104 # define TLS_TCB_AT_TP  1
 105 
 106 
 107 /* Install the dtv pointer.  The pointer passed is to the element with
 108    index -1 which contain the length.  */
 109 # define INSTALL_DTV(descr, dtvp) \
 110   ((tcbhead_t *) (descr))->dtv = (dtvp) + 1
 111 
 112 /* Install new dtv for current thread.  */
 113 # define INSTALL_NEW_DTV(dtvp) \
 114   ({ struct pthread *__pd;                                                    \
 115      THREAD_SETMEM (__pd, header.dtv, (dtvp)); })
 116 
 117 /* Return dtv of given thread descriptor.  */
 118 # define GET_DTV(descr) \
 119   (((tcbhead_t *) (descr))->dtv)
 120 
 121 
 122 /* Macros to load from and store into segment registers.  */
 123 # define TLS_GET_FS() \
 124   ({ int __seg; __asm ("movl %%fs, %0" : "=q" (__seg)); __seg; })
 125 # define TLS_SET_FS(val) \
 126   __asm ("movl %0, %%fs" :: "q" (val))
 127 
 128 
 129 /* Code to initially initialize the thread pointer.  This might need
 130    special attention since 'errno' is not yet available and if the
 131    operation can cause a failure 'errno' must not be touched.
 132 
 133    We have to make the syscall for both uses of the macro since the
 134    address might be (and probably is) different.  */
 135 # define TLS_INIT_TP(thrdescr, secondcall) \
 136   ({ void *_thrdescr = (thrdescr);                                            \
 137      tcbhead_t *_head = _thrdescr;                                            \
 138      int _result;                                                             \
 139                                                                               \
 140      _head->tcb = _thrdescr;                                                  \
 141      /* For now the thread descriptor is at the same address.  */             \
 142      _head->self = _thrdescr;                                                 \
 143                                                                               \
 144      /* It is a simple syscall to set the %fs value for the thread.  */       \
 145      asm volatile ("syscall"                                                  \
 146                    : "=a" (_result)                                           \
 147                    : "0" ((unsigned long int) __NR_arch_prctl),               \
 148                      "D" ((unsigned long int) ARCH_SET_FS),                   \
 149                      "S" (_thrdescr)                                          \
 150                    : "memory", "cc", "r11", "cx");                            \
 151                                                                               \
 152     _result ? "cannot set %fs base address for thread-local storage" : 0;     \
 153   })
 154 
 155 
 156 /* Return the address of the dtv for the current thread.  */
 157 # define THREAD_DTV() \
 158   ({ struct pthread *__pd;                                                    \
 159      THREAD_GETMEM (__pd, header.dtv); })
 160 
 161 
 162 /* Return the thread descriptor for the current thread.
 163 
 164    The contained asm must *not* be marked volatile since otherwise
 165    assignments like
 166         pthread_descr self = thread_self();
 167    do not get optimized away.  */
 168 # define THREAD_SELF \
 169   ({ struct pthread *__self;                                                  \
 170      asm ("movq %%fs:%c1,%q0" : "=r" (__self)                                 \
 171           : "i" (offsetof (struct pthread, header.self)));                    \
 172      __self;})
 173 
 174 /* Magic for libthread_db to know how to do THREAD_SELF.  */
 175 # define DB_THREAD_SELF_INCLUDE  <sys/reg.h> /* For the FS constant.  */
 176 # define DB_THREAD_SELF CONST_THREAD_AREA (64, FS)
 177 
 178 /* Read member of the thread descriptor directly.  */
 179 # define THREAD_GETMEM(descr, member) \
 180   ({ __typeof (descr->member) __value;                                        \
 181      if (sizeof (__value) == 1)                                               \
 182        asm volatile ("movb %%fs:%P2,%b0"                                      \
 183                      : "=q" (__value)                                         \
 184                      : "0" (0), "i" (offsetof (struct pthread, member)));     \
 185      else if (sizeof (__value) == 4)                                          \
 186        asm volatile ("movl %%fs:%P1,%0"                                       \
 187                      : "=r" (__value)                                         \
 188                      : "i" (offsetof (struct pthread, member)));              \
 189      else                                                                     \
 190        {                                                                      \
 191          if (sizeof (__value) != 8)                                           \
 192            /* There should not be any value with a size other than 1,         \
 193               4 or 8.  */                                                     \
 194            abort ();                                                          \
 195                                                                               \
 196          asm volatile ("movq %%fs:%P1,%q0"                                    \
 197                        : "=r" (__value)                                       \
 198                        : "i" (offsetof (struct pthread, member)));            \
 199        }                                                                      \
 200      __value; })
 201 
 202 
 203 /* Same as THREAD_GETMEM, but the member offset can be non-constant.  */
 204 # define THREAD_GETMEM_NC(descr, member, idx) \
 205   ({ __typeof (descr->member[0]) __value;                                     \
 206      if (sizeof (__value) == 1)                                               \
 207        asm volatile ("movb %%fs:%P2(%q3),%b0"                                 \
 208                      : "=q" (__value)                                         \
 209                      : "0" (0), "i" (offsetof (struct pthread, member[0])),   \
 210                        "r" (idx));                                            \
 211      else if (sizeof (__value) == 4)                                          \
 212        asm volatile ("movl %%fs:%P1(,%q2,4),%0"                               \
 213                      : "=r" (__value)                                         \
 214                      : "i" (offsetof (struct pthread, member[0])), "r" (idx));\
 215      else                                                                     \
 216        {                                                                      \
 217          if (sizeof (__value) != 8)                                           \
 218            /* There should not be any value with a size other than 1,         \
 219               4 or 8.  */                                                     \
 220            abort ();                                                          \
 221                                                                               \
 222          asm volatile ("movq %%fs:%P1(,%q2,8),%q0"                            \
 223                        : "=r" (__value)                                       \
 224                        : "i" (offsetof (struct pthread, member[0])),          \
 225                          "r" (idx));                                          \
 226        }                                                                      \
 227      __value; })
 228 
 229 
 230 /* Loading addresses of objects on x86-64 needs to be treated special
 231    when generating PIC code.  */
 232 #ifdef __pic__
 233 # define IMM_MODE "nr"
 234 #else
 235 # define IMM_MODE "ir"
 236 #endif
 237 
 238 
 239 /* Same as THREAD_SETMEM, but the member offset can be non-constant.  */
 240 # define THREAD_SETMEM(descr, member, value) \
 241   ({ if (sizeof (descr->member) == 1)                                         \
 242        asm volatile ("movb %b0,%%fs:%P1" :                                    \
 243                      : "iq" (value),                                          \
 244                        "i" (offsetof (struct pthread, member)));              \
 245      else if (sizeof (descr->member) == 4)                                    \
 246        asm volatile ("movl %0,%%fs:%P1" :                                     \
 247                      : IMM_MODE (value),                                      \
 248                        "i" (offsetof (struct pthread, member)));              \
 249      else                                                                     \
 250        {                                                                      \
 251          if (sizeof (descr->member) != 8)                                     \
 252            /* There should not be any value with a size other than 1,         \
 253               4 or 8.  */                                                     \
 254            abort ();                                                          \
 255                                                                               \
 256          asm volatile ("movq %q0,%%fs:%P1" :                                  \
 257                        : IMM_MODE ((unsigned long int) value),                \
 258                          "i" (offsetof (struct pthread, member)));            \
 259        }})
 260 
 261 
 262 /* Set member of the thread descriptor directly.  */
 263 # define THREAD_SETMEM_NC(descr, member, idx, value) \
 264   ({ if (sizeof (descr->member[0]) == 1)                                      \
 265        asm volatile ("movb %b0,%%fs:%P1(%q2)" :                               \
 266                      : "iq" (value),                                          \
 267                        "i" (offsetof (struct pthread, member[0])),            \
 268                        "r" (idx));                                            \
 269      else if (sizeof (descr->member[0]) == 4)                                 \
 270        asm volatile ("movl %0,%%fs:%P1(,%q2,4)" :                             \
 271                      : IMM_MODE (value),                                      \
 272                        "i" (offsetof (struct pthread, member[0])),            \
 273                        "r" (idx));                                            \
 274      else                                                                     \
 275        {                                                                      \
 276          if (sizeof (descr->member[0]) != 8)                                  \
 277            /* There should not be any value with a size other than 1,         \
 278               4 or 8.  */                                                     \
 279            abort ();                                                          \
 280                                                                               \
 281          asm volatile ("movq %q0,%%fs:%P1(,%q2,8)" :                          \
 282                        : IMM_MODE ((unsigned long int) value),                \
 283                          "i" (offsetof (struct pthread, member[0])),          \
 284                          "r" (idx));                                          \
 285        }})
 286 
 287 
 288 /* Atomic compare and exchange on TLS, returning old value.  */
 289 #define THREAD_ATOMIC_CMPXCHG_VAL(descr, member, newval, oldval) \
 290   ({ __typeof (descr->member) __ret;                                          \
 291      __typeof (oldval) __old = (oldval);                                      \
 292      if (sizeof (descr->member) == 4)                                         \
 293        asm volatile (LOCK_PREFIX "cmpxchgl %2, %%fs:%P3"                      \
 294                      : "=a" (__ret)                                           \
 295                      : "0" (__old), "r" (newval),                             \
 296                        "i" (offsetof (struct pthread, member)));              \
 297      else                                                                     \
 298        /* Not necessary for other sizes in the moment.  */                    \
 299        abort ();                                                              \
 300      __ret; })
 301 
 302 
 303 /* Atomic set bit.  */
 304 #define THREAD_ATOMIC_BIT_SET(descr, member, bit) \
 305   (void) ({ if (sizeof ((descr)->member) == 4)                                \
 306               asm volatile (LOCK_PREFIX "orl %1, %%fs:%P0"                    \
 307                             :: "i" (offsetof (struct pthread, member)),       \
 308                                "ir" (1 << (bit)));                            \
 309             else                                                              \
 310               /* Not necessary for other sizes in the moment.  */             \
 311               abort (); })
 312 
 313 
 314 #define CALL_THREAD_FCT(descr) \
 315   ({ void *__res;                                                             \
 316      asm volatile ("movq %%fs:%P2, %%rdi\n\t"                                 \
 317                    "callq *%%fs:%P1"                                          \
 318                    : "=a" (__res)                                             \
 319                    : "i" (offsetof (struct pthread, start_routine)),          \
 320                      "i" (offsetof (struct pthread, arg))                     \
 321                    : "di", "si", "cx", "dx", "r8", "r9", "r10", "r11",        \
 322                      "memory", "cc");                                         \
 323      __res; })
 324 
 325 
 326 /* Set the stack guard field in TCB head.  */
 327 # define THREAD_SET_STACK_GUARD(value) \
 328     THREAD_SETMEM (THREAD_SELF, header.stack_guard, value)
 329 # define THREAD_COPY_STACK_GUARD(descr) \
 330     ((descr)->header.stack_guard                                              \
 331      = THREAD_GETMEM (THREAD_SELF, header.stack_guard))
 332 
 333 
 334 /* Set the pointer guard field in the TCB head.  */
 335 #define THREAD_SET_POINTER_GUARD(value) \
 336   THREAD_SETMEM (THREAD_SELF, header.pointer_guard, value)
 337 #define THREAD_COPY_POINTER_GUARD(descr) \
 338   ((descr)->header.pointer_guard                                              \
 339    = THREAD_GETMEM (THREAD_SELF, header.pointer_guard))
 340 
 341 
 342 #endif /* __ASSEMBLER__ */
 343 
 344 #endif  /* tls.h */

/* [<][>][^][v][top][bottom][index][help] */