1 /*
   2  * Copyright (c) 1998, 2010, Oracle and/or its affiliates. All rights reserved.
   3  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
   4  *
   5  * This code is free software; you can redistribute it and/or modify it
   6  * under the terms of the GNU General Public License version 2 only, as
   7  * published by the Free Software Foundation.
   8  *
   9  * This code is distributed in the hope that it will be useful, but WITHOUT
  10  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
  11  * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
  12  * version 2 for more details (a copy is included in the LICENSE file that
  13  * accompanied this code).
  14  *
  15  * You should have received a copy of the GNU General Public License version
  16  * 2 along with this work; if not, write to the Free Software Foundation,
  17  * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
  18  *
  19  * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
  20  * or visit www.oracle.com if you need additional information or have any
  21  * questions.
  22  *
  23  */
  24 
  25 #include "precompiled.hpp"
  26 #include "runtime/thread.inline.hpp"
  27 #include "runtime/threadLocalStorage.hpp"
  28 
  29 #ifdef AMD64
  30 extern "C" Thread*  fs_load(ptrdiff_t tlsOffset);
  31 extern "C" intptr_t fs_thread();
  32 #else
  33 // From solaris_i486.s
  34 extern "C" Thread*  gs_load(ptrdiff_t tlsOffset);
  35 extern "C" intptr_t gs_thread();
  36 #endif // AMD64
  37 
  38 // tlsMode encoding:
  39 //
  40 // pd_tlsAccessUndefined : uninitialized
  41 // pd_tlsAccessSlow      : not available
  42 // pd_tlsAccessIndirect  :
  43 //   old-style indirect access - present in "T1" libthread.
  44 //   use thr_slot_sync_allocate() to attempt to allocate a slot.
  45 // pd_tlsAccessDirect    :
  46 //   new-style direct access - present in late-model "T2" libthread.
  47 //   Allocate the offset (slot) via _thr_slot_offset() or by
  48 //   defining an IE- or LE-mode TLS/TSD slot in the launcher and then passing
  49 //   that offset into libjvm.so.
  50 //   See http://sac.eng/Archives/CaseLog/arc/PSARC/2003/159/.
  51 //
  52 // Note that we have a capability gap - some early model T2 forms
  53 // (e.g., unpatched S9) have neither _thr_slot_sync_allocate() nor
  54 // _thr_slot_offset().  In that case we revert to the usual
  55 // thr_getspecific accessor.
  56 //
  57 
  58 static ThreadLocalStorage::pd_tlsAccessMode tlsMode = ThreadLocalStorage::pd_tlsAccessUndefined ;
  59 static ptrdiff_t tlsOffset = 0 ;
  60 static thread_key_t tlsKey ;
  61 
  62 typedef int (*TSSA_Entry) (ptrdiff_t *, int, int) ;
  63 typedef ptrdiff_t (*TSO_Entry) (int) ;
  64 
  65 ThreadLocalStorage::pd_tlsAccessMode ThreadLocalStorage::pd_getTlsAccessMode ()
  66 {
  67    guarantee (tlsMode != pd_tlsAccessUndefined, "tlsMode not set") ;
  68    return tlsMode ;
  69 }
  70 
  71 ptrdiff_t ThreadLocalStorage::pd_getTlsOffset () {
  72    guarantee (tlsMode != pd_tlsAccessUndefined, "tlsMode not set") ;
  73    return tlsOffset ;
  74 }
  75 
  76 // TODO: Consider the following improvements:
  77 //
  78 // 1.   Convert from thr_*specific* to pthread_*specific*.
  79 //      The pthread_ forms are slightly faster.  Also, the
  80 //      pthread_ forms have a pthread_key_delete() API which
  81 //      would aid in clean JVM shutdown and the eventual goal
  82 //      of permitting a JVM to reinstantiate itself withing a process.
  83 //
  84 // 2.   See ThreadLocalStorage::init().  We end up allocating
  85 //      two TLS keys during VM startup.  That's benign, but we could collapse
  86 //      down to one key without too much trouble.
  87 //
  88 // 3.   MacroAssembler::get_thread() currently emits calls to thr_getspecific().
  89 //      Modify get_thread() to call Thread::current() instead.
  90 //
  91 // 4.   Thread::current() currently uses a cache keyed by %gs:[0].
  92 //      (The JVM has PSARC permission to use %g7/%gs:[0]
  93 //      as an opaque temporally unique thread identifier).
  94 //      For C++ access to a thread's reflexive "self" pointer we
  95 //      should consider using one of the following:
  96 //      a. a radix tree keyed by %esp - as in EVM.
  97 //         This requires two loads (the 2nd dependent on the 1st), but
  98 //         is easily inlined and doesn't require a "miss" slow path.
  99 //      b. a fast TLS/TSD slot allocated by _thr_slot_offset
 100 //         or _thr_slot_sync_allocate.
 101 //
 102 // 5.   'generate_code_for_get_thread' is a misnomer.
 103 //      We should change it to something more general like
 104 //      pd_ThreadSelf_Init(), for instance.
 105 //
 106 
 107 static void AllocateTLSOffset ()
 108 {
 109    int rslt ;
 110    TSSA_Entry tssa ;
 111    TSO_Entry  tso ;
 112    ptrdiff_t off ;
 113 
 114    guarantee (tlsMode == ThreadLocalStorage::pd_tlsAccessUndefined, "tlsMode not set") ;
 115    tlsMode = ThreadLocalStorage::pd_tlsAccessSlow ;
 116    tlsOffset = 0 ;
 117 #ifndef AMD64
 118 
 119    tssa = (TSSA_Entry) dlsym (RTLD_DEFAULT, "thr_slot_sync_allocate") ;
 120    if (tssa != NULL) {
 121         off = -1 ;
 122         rslt = (*tssa)(&off, NULL, NULL) ;                // (off,dtor,darg)
 123         if (off != -1) {
 124            tlsOffset = off ;
 125            tlsMode = ThreadLocalStorage::pd_tlsAccessIndirect ;
 126            return ;
 127         }
 128     }
 129 
 130     rslt = thr_keycreate (&tlsKey, NULL) ;
 131     if (rslt != 0) {
 132         tlsMode = ThreadLocalStorage::pd_tlsAccessSlow ;   // revert to slow mode
 133         return ;
 134     }
 135 
 136     tso = (TSO_Entry) dlsym (RTLD_DEFAULT, "_thr_slot_offset") ;
 137     if (tso != NULL) {
 138         off = (*tso)(tlsKey) ;
 139         if (off >= 0) {
 140            tlsOffset = off ;
 141            tlsMode = ThreadLocalStorage::pd_tlsAccessDirect ;
 142            return ;
 143         }
 144     }
 145 
 146     // Failure: Too bad ... we've allocated a TLS slot we don't need and there's
 147     // no provision in the ABI for returning the slot.
 148     //
 149     // If we didn't find a slot then then:
 150     // 1. We might be on liblwp.
 151     // 2. We might be on T2 libthread, but all "fast" slots are already
 152     //    consumed
 153     // 3. We might be on T1, and all TSD (thr_slot_sync_allocate) slots are
 154     //    consumed.
 155     // 4. We might be on T2 libthread, but it's be re-architected
 156     //    so that fast slots are no longer g7-relative.
 157     //
 158 
 159     tlsMode = ThreadLocalStorage::pd_tlsAccessSlow ;
 160     return ;
 161 #endif // AMD64
 162 }
 163 
 164 void ThreadLocalStorage::generate_code_for_get_thread() {
 165     AllocateTLSOffset() ;
 166 }
 167 
 168 void ThreadLocalStorage::set_thread_in_slot(Thread *thread) {
 169   guarantee (tlsMode != pd_tlsAccessUndefined, "tlsMode not set") ;
 170   if (tlsMode == pd_tlsAccessIndirect) {
 171 #ifdef AMD64
 172         intptr_t tbase = fs_thread();
 173 #else
 174         intptr_t tbase = gs_thread();
 175 #endif // AMD64
 176         *((Thread**) (tbase + tlsOffset)) = thread ;
 177   } else
 178   if (tlsMode == pd_tlsAccessDirect) {
 179         thr_setspecific (tlsKey, (void *) thread) ;
 180         // set with thr_setspecific and then readback with gs_load to validate.
 181 #ifdef AMD64
 182         guarantee (thread == fs_load(tlsOffset), "tls readback failure") ;
 183 #else
 184         guarantee (thread == gs_load(tlsOffset), "tls readback failure") ;
 185 #endif // AMD64
 186   }
 187 }
 188 
 189 
 190 extern "C" Thread* get_thread() {
 191   return ThreadLocalStorage::thread();
 192 }
--- EOF ---