"Fossies" - the Fresh Open Source Software Archive

Member "Hoard-3.13/src/source/unixtls.cpp" (2 Jan 2019, 10598 Bytes) of package /linux/misc/Hoard-3.13.tar.gz:


As a special service "Fossies" has tried to format the requested source page into HTML format using (guessed) C and C++ source code syntax highlighting (style: standard) with prefixed line numbers and code folding option. Alternatively you can here view or download the uninterpreted source code file. For more information about "unixtls.cpp" see the Fossies "Dox" file reference documentation and the latest Fossies "Diffs" side-by-side code changes report: 3.12_vs_3.13.

    1 /*
    2   The Hoard Multiprocessor Memory Allocator
    3   www.hoard.org
    4 
    5   Author: Emery Berger, http://www.emeryberger.org
    6  
    7   Copyright (c) 1998-2019 Emery Berger
    8 
    9   This program is free software; you can redistribute it and/or modify
   10   it under the terms of the GNU General Public License as published by
   11   the Free Software Foundation; either version 2 of the License, or
   12   (at your option) any later version.
   13   
   14   This program is distributed in the hope that it will be useful,
   15   but WITHOUT ANY WARRANTY; without even the implied warranty of
   16   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
   17   GNU General Public License for more details.
   18   
   19   You should have received a copy of the GNU General Public License
   20   along with this program; if not, write to the Free Software
   21   Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
   22 
   23 */
   24 
   25 /*
   26  * This file leverages compiler support for thread-local variables for
   27  * access to thread-local heaps, when available. It also intercepts
   28  * thread completions to flush these local heaps, returning any unused
   29  * memory to the global Hoard heap. On Windows, this happens in
   30  * DllMain. On Unix platforms, we interpose our own versions of
   31  * pthread_create and pthread_exit.
   32  */
   33 
   34 #if defined(__clang__)
   35 #pragma clang diagnostic push
   36 #pragma clang diagnostic ignored "-Wunused-variable"
   37 #pragma clang diagnostic ignored "-Wunused-value"
   38 #endif
   39 
   40 // For now, we only use thread-local variables (__thread) for certain
   41 // compilers and systems.
   42 
   43 // Compute the version of gcc we're compiling with (if any).
   44 #define GCC_VERSION (__GNUC__ * 10000       \
   45                      + __GNUC_MINOR__ * 100 \
   46                      + __GNUC_PATCHLEVEL__)
   47 
   48 #if (((defined(GCC_VERSION) && (GCC_VERSION >= 30300)) &&   \
   49       !defined(__SVR4) &&                   \
   50       !defined(__APPLE__))                  \
   51      || defined(__SUNPRO_CC)                    \
   52      || defined(__FreeBSD__))
   53 #define USE_THREAD_KEYWORD 1
   54 #endif
   55 
   56 #if !defined(USE_THREAD_KEYWORD)
   57 #include <pthread.h>
   58 #endif
   59 
   60 #if defined(__SVR4)
   61 #include <dlfcn.h>
   62 #endif
   63 
   64 #include <new>
   65 #include <utility>
   66 
   67 
   68 #include "hoard/hoardtlab.h"
   69 
   70 extern Hoard::HoardHeapType * getMainHoardHeap();
   71 
   72 #if defined(USE_THREAD_KEYWORD)
   73 
   74 // Thread-specific buffers and pointers to hold the TLAB.
   75 
   76 // Optimization to accelerate thread-local access. This precludes the
   77 // use of Hoard in a dlopen module, but is MUCH faster.
   78 
   79 #define INITIAL_EXEC_ATTR __attribute__((tls_model ("initial-exec")))
   80 #define BUFFER_SIZE (sizeof(TheCustomHeapType) / sizeof(double) + 1)
   81 
   82 static __thread double tlabBuffer[BUFFER_SIZE] INITIAL_EXEC_ATTR;
   83 static __thread TheCustomHeapType * theTLAB INITIAL_EXEC_ATTR = nullptr;
   84 
   85 // Initialize the TLAB.
   86 
   87 static TheCustomHeapType * initializeCustomHeap() __attribute__((constructor));
   88 
   89 static TheCustomHeapType * initializeCustomHeap() {
   90   auto tlab = theTLAB;
   91   if (tlab == nullptr) {
   92     new (reinterpret_cast<char *>(&tlabBuffer)) TheCustomHeapType(getMainHoardHeap());
   93     tlab = reinterpret_cast<TheCustomHeapType *>(&tlabBuffer);
   94     theTLAB = tlab;
   95   }
   96   return tlab;
   97 }
   98 
   99 // Get the TLAB.
  100 
  101 bool isCustomHeapInitialized() {
  102   return (theTLAB != nullptr);
  103 }
  104 
  105 TheCustomHeapType * getCustomHeap() {
  106   // The pointer to the TLAB itself.
  107   auto tlab = theTLAB;
  108   if (tlab == nullptr) {
  109     tlab = initializeCustomHeap();
  110     theTLAB = tlab;
  111   }
  112   return tlab;
  113 }
  114 
  115 
  116 
  117 #else // !defined(USE_THREAD_KEYWORD)
  118 
  119 
  120 
  121 static pthread_key_t theHeapKey;
  122 static pthread_once_t key_once = PTHREAD_ONCE_INIT;
  123 
  124 // Called when the thread goes away.  This function clears out the
  125 // TLAB and then reclaims the memory allocated to hold it.
  126 
  127 static void deleteThatHeap(void * p) {
  128   auto * heap = reinterpret_cast<TheCustomHeapType *>(p);
  129   heap->clear();
  130   getMainHoardHeap()->free(reinterpret_cast<void *>(heap));
  131 
  132   // Relinquish the assigned heap.
  133   getMainHoardHeap()->releaseHeap();
  134   //  pthread_setspecific(theHeapKey, nullptr);
  135 }
  136 
  137 static void make_heap_key() {
  138   if (pthread_key_create(&theHeapKey, deleteThatHeap) != 0) {
  139     // This should never happen.
  140   }
  141 }
  142 
  143 static void initTSD() __attribute__((constructor));
  144 
  145 static bool initializedTSD = false;
  146 
  147 static void initTSD() {
  148   if (!initializedTSD) {
  149     // Ensure that the key is initialized -- once.
  150     pthread_once(&key_once, make_heap_key);
  151     initializedTSD = true;
  152   }
  153 }
  154 
  155 bool isCustomHeapInitialized() {
  156   return initializedTSD;
  157 }
  158 
  159 static TheCustomHeapType * initializeCustomHeap() {
  160   assert(pthread_getspecific(theHeapKey) == nullptr);
  161   // Allocate a per-thread heap.
  162   size_t sz = sizeof(TheCustomHeapType) + sizeof(double);
  163   auto * mh = reinterpret_cast<char *>(getMainHoardHeap()->malloc(sz));
  164   auto heap = new (mh) TheCustomHeapType(getMainHoardHeap());
  165   // Store it in the appropriate thread-local area.
  166   pthread_setspecific(theHeapKey, reinterpret_cast<void *>(heap));
  167   return heap;
  168 }
  169 
  170 TheCustomHeapType * getCustomHeap() {
  171   TheCustomHeapType * heap;
  172   initTSD();
  173   heap = reinterpret_cast<TheCustomHeapType *>(pthread_getspecific(theHeapKey));
  174   if (heap == nullptr) {
  175     heap = initializeCustomHeap();
  176   }
  177   return heap;
  178 }
  179 
  180 #endif
  181 
  182 
  183 //
  184 // Intercept thread creation and destruction to flush the TLABs.
  185 //
  186 
  187 extern "C" {
  188   typedef void * (*threadFunctionType)(void * arg);
  189 
  190   typedef
  191   int (*pthread_create_function)(pthread_t *thread,
  192                                  const pthread_attr_t *attr,
  193                                  threadFunctionType start_routine,
  194                                  void *arg);
  195 
  196   typedef
  197   void (*pthread_exit_function)(void * arg);
  198 }
  199 
  200 
  201 // A special routine we call on thread exit to free up some resources.
  202 static void exitRoutine() {
  203   auto * heap = initializeCustomHeap();
  204 
  205   // Relinquish the assigned heap.
  206   getMainHoardHeap()->releaseHeap();
  207 
  208   // Clear the heap (via its destructor).
  209   heap->~TheCustomHeapType();
  210 
  211 #if !defined(USE_THREAD_KEYWORD)
  212   // Reclaim the memory associated with the heap (thread-specific data).
  213   pthread_key_delete (theHeapKey);
  214 #endif
  215 }
  216 
  217 extern "C" {
  218   static inline void * startMeUp(void * a) {
  219     initializeCustomHeap();
  220     getMainHoardHeap()->findUnusedHeap();
  221     auto * z = (pair<threadFunctionType, void *> *) a;
  222     
  223     auto f   = z->first;
  224     auto arg = z->second;
  225     auto result = (*f)(arg);
  226 
  227     delete z;
  228 
  229     exitRoutine();
  230 
  231     return result;
  232   }
  233 }
  234 
  235 extern volatile bool anyThreadCreated;
  236 
  237 
  238 // Intercept thread creation. We need this to first associate
  239 // a heap with the thread and instantiate the thread-specific heap
  240 // (TLAB).  When the thread ends, we relinquish the assigned heap and
  241 // free up the TLAB.
  242 
  243 #if defined(__SVR4)
  244 
  245 extern "C" {
  246   typedef
  247   int (*thr_create_function)(void * stack_base,
  248                              size_t stack_size,
  249                              void * (*start_routine)(void *),
  250                              void * arg,
  251                              long flags,
  252                              thread_t * new_thread_id);
  253 
  254   typedef
  255   void (*thr_exit_function)(void * arg);
  256 
  257 }
  258 
  259 extern "C" int thr_create (void * stack_base,
  260                            size_t stack_size,
  261                            void * (*start_routine)(void *),
  262                            void * arg,
  263                            long flags,
  264                            thread_t * new_tid) {
  265   // Force initialization of the TLAB before our first thread is created.
  266   static volatile TheCustomHeapType * t = initializeCustomHeap();
  267 
  268   char fname[] = "_thr_create";
  269 
  270   // Instantiate the pointer to thr_create, if it hasn't been
  271   // instantiated yet.
  272 
  273   // A pointer to the library version of thr_create.
  274   static thr_create_function real_thr_create =
  275     (thr_create_function) dlsym (RTLD_NEXT, fname);
  276 
  277   if (real_thr_create == nullptr) {
  278     // Error. Must fail.
  279     cerr << "Failure at startup: " << dlerror() << endl;
  280     abort();
  281   }
  282 
  283   anyThreadCreated = true;
  284 
  285   typedef pair<threadFunctionType, void *> argsType;
  286   argsType * args =
  287     new (getCustomHeap()->malloc(sizeof(argsType)))
  288     argsType (start_routine, arg);
  289 
  290   int result =
  291     (*real_thr_create)(stack_base, stack_size, startMeUp, args, flags, new_tid);
  292 
  293   return result;
  294 }
  295 
  296 
  297 extern "C" void thr_exit (void * value_ptr) {
  298 #if defined(__linux__) || defined(__APPLE__)
  299   char fname[] = "thr_exit";
  300 #else
  301   char fname[] = "_thr_exit";
  302 #endif
  303 
  304   // Instantiate the pointer to thr_exit, if it hasn't been
  305   // instantiated yet.
  306 
  307   // A pointer to the library version of thr_exit.
  308   static thr_exit_function real_thr_exit =
  309     reinterpret_cast<thr_exit_function>(dlsym (RTLD_NEXT, fname));
  310 
  311   if (real_thr_exit == nullptr) {
  312     // Error. Must fail.
  313     cerr << "Unable to find " << fname << " : " << dlerror() << endl;
  314     abort();
  315   }
  316 
  317   // Do necessary clean-up of the TLAB and get out.
  318 
  319   exitRoutine();
  320   (*real_thr_exit)(value_ptr);
  321 }
  322 
  323 #endif
  324 
  325 
  326 #if defined(__APPLE__)
  327 #error "This file should not be used on Mac OS platforms."
  328 #else
  329 
  330 extern "C" void pthread_exit (void *value_ptr) {
  331 #if defined(__linux__) || defined(__APPLE__)
  332   char fname[] = "pthread_exit";
  333 #else
  334   char fname[] = "_pthread_exit";
  335 #endif
  336 
  337   // Instantiate the pointer to pthread_exit, if it hasn't been
  338   // instantiated yet.
  339 
  340   // A pointer to the library version of pthread_exit.
  341   static pthread_exit_function real_pthread_exit = 
  342     reinterpret_cast<pthread_exit_function>
  343     (reinterpret_cast<intptr_t>(dlsym(RTLD_NEXT, fname)));
  344 
  345   // Do necessary clean-up of the TLAB and get out.
  346   exitRoutine();
  347   (*real_pthread_exit)(value_ptr);
  348 
  349   // We should not get here, but doing so disables a warning.
  350   exit(0);
  351 }
  352 
  353 extern "C" int pthread_create (pthread_t *thread,
  354                                const pthread_attr_t *attr,
  355                                void * (*start_routine)(void *),
  356                                void * arg)
  357 #if !defined(__SUNPRO_CC) && !defined(__APPLE__) && !defined(__FreeBSD__)
  358   throw ()
  359 #endif
  360 {
  361   // Force initialization of the TLAB before our first thread is created.
  362   static volatile TheCustomHeapType * t = initializeCustomHeap();
  363 
  364 #if defined(__linux__) || defined(__APPLE__)
  365   char fname[] = "pthread_create";
  366 #else
  367   char fname[] = "_pthread_create";
  368 #endif
  369 
  370   // A pointer to the library version of pthread_create.
  371   static auto real_pthread_create =
  372     reinterpret_cast<pthread_create_function>
  373     (reinterpret_cast<intptr_t>(dlsym(RTLD_NEXT, fname)));
  374 
  375   anyThreadCreated = true;
  376 
  377   auto * args =
  378     // new (_heap.malloc(sizeof(pair<threadFunctionType, void*>)))
  379     new
  380     pair<threadFunctionType, void *> (start_routine, arg);
  381 
  382   int result = (*real_pthread_create)(thread, attr, startMeUp, args);
  383 
  384   return result;
  385 }
  386 
  387 #if defined(__clang__)
  388 #pragma clang diagnostic pop
  389 #endif
  390 
  391 #endif
  392 
  393