00001 /* -*- mode:C++; c-basic-offset:4 -*- 00002 Shore-MT -- Multi-threaded port of the SHORE storage manager 00003 00004 Copyright (c) 2007-2009 00005 Data Intensive Applications and Systems Labaratory (DIAS) 00006 Ecole Polytechnique Federale de Lausanne 00007 00008 All Rights Reserved. 00009 00010 Permission to use, copy, modify and distribute this software and 00011 its documentation is hereby granted, provided that both the 00012 copyright notice and this permission notice appear in all copies of 00013 the software, derivative works or modified versions, and any 00014 portions thereof, and that both notices appear in supporting 00015 documentation. 00016 00017 This code is distributed in the hope that it will be useful, but 00018 WITHOUT ANY WARRANTY; without even the implied warranty of 00019 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. THE AUTHORS 00020 DISCLAIM ANY LIABILITY OF ANY KIND FOR ANY DAMAGES WHATSOEVER 00021 RESULTING FROM THE USE OF THIS SOFTWARE. 00022 */ 00023 00024 // -*- mode:c++; c-basic-offset:4 -*- 00025 /*<std-header orig-src='shore' incl-file-exclusion='TLS_H'> 00026 00027 $Id: tls.h,v 1.4 2012/01/02 17:02:13 nhall Exp $ 00028 00029 SHORE -- Scalable Heterogeneous Object REpository 00030 00031 Copyright (c) 1994-99 Computer Sciences Department, University of 00032 Wisconsin -- Madison 00033 All Rights Reserved. 00034 00035 Permission to use, copy, modify and distribute this software and its 00036 documentation is hereby granted, provided that both the copyright 00037 notice and this permission notice appear in all copies of the 00038 software, derivative works or modified versions, and any portions 00039 thereof, and that both notices appear in supporting documentation. 00040 00041 THE AUTHORS AND THE COMPUTER SCIENCES DEPARTMENT OF THE UNIVERSITY 00042 OF WISCONSIN - MADISON ALLOW FREE USE OF THIS SOFTWARE IN ITS 00043 "AS IS" CONDITION, AND THEY DISCLAIM ANY LIABILITY OF ANY KIND 00044 FOR ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE. 00045 00046 This software was developed with support by the Advanced Research 00047 Project Agency, ARPA order number 018 (formerly 8230), monitored by 00048 the U.S. Army Research Laboratory under contract DAAB07-91-C-Q518. 00049 Further funding for this work was provided by DARPA through 00050 Rome Research Laboratory Contract No. F30602-97-2-0247. 00051 00052 */ 00053 #ifndef __TLS_H 00054 #define __TLS_H 00055 00056 #include <pthread.h> 00057 #include <new> 00058 00059 /**\file tls.h 00060 * Cause macro definitions to show up in doxygen-generated 00061 * pages 00062 *\ingroup MACROS 00063 * */ 00064 00065 /**\addtogroup TLS 00066 * The following are some of the thread-local variables 00067 * defined in the storage manager libraries. (This is far from 00068 * a complete list.) 00069 * 00070 * Each use of \ref TLS_STRUCT creates a thread_local object. 00071 * 00072 * See also \ref tls_tricks. 00073 * 00074 */ 00075 00076 /**\brief A namespace for thread-local storage tricks. 00077 * 00078 * See also the following macros: 00079 * - #DECLARE_TLS(Type,Name) 00080 * - #DECLARE_TLS_SCHWARZ(Name) 00081 * - #DEFINE_TLS_SCHWARZ(Type,Name) 00082 */ 00083 namespace tls_tricks { 00084 00085 /**\brief A management class for non-POD thread-local storage. 00086 * 00087 * The programmer 00088 * declares thread-local variables via DECLARE_TLS macro, and every 00089 * thread which calls thread_init/fini at entry/exit will have its 00090 * thread-local variables initialized and destroyed by their no-arg 00091 * constructor and destructor. 00092 * 00093 * \attention NOTE: the main thread automatically initializes its own TLS before 00094 * entering main(), but if the main thread exits without ending the 00095 * program it should call tls_manager::thread_fini like any other 00096 * thread. 00097 * 00098 * \attention WARNING: for now this API does not support TLS declared within a 00099 * function. 00100 * 00101 * \attention WARNING: Similar to static initialization, the programmer cannot 00102 * make any assumptions about the order in which two thread-local 00103 * variables get initialized unless they are declared in the same file 00104 * or declared using a DECLARE_TLS_SCHWARZ/DEFINE_TLS_SCHWARZ pair. 00105 */ 00106 class tls_manager { 00107 public: 00108 static void global_init(); 00109 static void global_fini(); 00110 static void register_tls(void (*init)(), void (*fini)()); 00111 static void thread_init(); 00112 static void thread_fini(); 00113 static __thread bool _thread_initialized; // note: thread-local 00114 }; 00115 00116 /**\brief Static struct to make 00117 * sure tls_manager's global init() and fini() are called. 00118 * 00119 * \relates tls_manager 00120 * This is a so-called "schwarz counter", included in the .h file 00121 * and included here (first) so that it guarantees that the 00122 * tls_manager is indeed initialized before any other 00123 * schwarz counter or static declaration uses register_tls. 00124 */ 00125 struct tls_manager_schwarz { 00126 /**\brief Constructor: invokes global init of all registered tls initializers */ 00127 tls_manager_schwarz() { tls_manager::global_init(); } 00128 /**\brief Destructor: invokes global init of all registered tls destructors */ 00129 ~tls_manager_schwarz() { tls_manager::global_fini(); } 00130 } ; 00131 static struct tls_manager_schwarz tlsm_schwarz_one_and_only; 00132 00133 /** \brief Wrapper for a type, used by TLS_STRUCT helper macro 00134 * 00135 * All thread-local variables declared by TLS_STRUCT are actually 00136 * just a bunch of bytes... until init() and fini() are called, 00137 * that is. After that the tls_blob acts like a smart pointer. 00138 */ 00139 template<typename T> 00140 struct tls_blob { 00141 enum { MAX_BYTES_NEEDED = sizeof(T)+sizeof(long)-1, 00142 ARRAY_SIZE = MAX_BYTES_NEEDED/sizeof(long) }; 00143 00144 // force proper alignment... 00145 long _reserved_space[ARRAY_SIZE]; 00146 00147 /** Placement new, using _reserved_space, to make the type T's 00148 * constructor get called. 00149 */ 00150 void init() { new (get()) T; } 00151 /** 00152 * Call T's destructor */ 00153 void fini() { get()->~T(); } 00154 00155 00156 /** \brief Used by fini() and init() and directly by macros */ 00157 T* get() { 00158 union { long* a; T* t; } u = {_reserved_space}; 00159 return u.t; 00160 } 00161 }; 00162 00163 /* WARNING: These thread-local variables essentially use the namespace 00164 of types, not variables for the purposes of detecting naming 00165 collisions. So, just as the following two declarations could lead 00166 to serious and hard-to-identify bugs: 00167 00168 -- file1.cpp -- 00169 struct foo { 00170 int a; int b; 00171 }; 00172 -- file2.cpp -- 00173 00174 struct foo { 00175 double a; char* b; 00176 }; 00177 00178 So, too, would the following: 00179 00180 -- file1.cpp -- 00181 DECLARE_TLS(foo, my_tls); 00182 -- file2.cpp -- 00183 DECLARE_TLS(bar, my_tls); 00184 00185 If you are lucky and the two types have different names the 00186 compiler may notice, otherwise you're on your own. 00187 */ 00188 00189 /**\def TLS_STRUCT(Type,Name,InitFn) 00190 *\brief Helper macro for DECLARE_TLS. Do not use directly. 00191 * 00192 *\addindex TLS_STRUCT 00193 *\relates tls_blob 00194 *\relates DECLARE_TLS 00195 *\relates DEFINE_TLS_SCHWARZ 00196 * 00197 * 00198 * A helper macro for DECLARE_TLS. 00199 * \attention Do not use this macro directly. 00200 * 00201 * Creates a "smart pointer" structure with the given Name; 00202 * the pointer is to an object of the given Type. Actually, 00203 * it's a pointer to a tls_blob, which is a bunch of untyped 00204 * bytes, but they get initialized via placement new when 00205 * a thread starts and 00206 * "destructed" when the thread goes away. 00207 * Passing in the InitFn allows us to register a 00208 * non-trivial constructor, i.e., it allows us to 00209 * use non-POD types in thread-local storage. 00210 * This *only* lets us use a default constructor, but 00211 * the compiler's idea of trivial is more strict than 00212 * just having a default constructor. 00213 */ 00214 #define TLS_STRUCT(Type, Name, InitFn) \ 00215 struct Name { \ 00216 typedef tls_tricks::tls_blob< Type > Wrapper; \ 00217 Type &operator*() { return *get(); } \ 00218 Type* operator->() { return get(); } \ 00219 operator Type*() { return get(); } \ 00220 static Wrapper* get_wrapper() { \ 00221 static __thread Wrapper val; \ 00222 return &val; \ 00223 } \ 00224 static Type* get() { return get_wrapper()->get(); } \ 00225 static void init() { get_wrapper()->init(); } \ 00226 static void fini() { get_wrapper()->fini(); } \ 00227 InitFn() { \ 00228 static bool initialized = false; \ 00229 if(initialized) \ 00230 return; \ 00231 tls_tricks::tls_manager::register_tls(&init, &fini); \ 00232 initialized = true; \ 00233 } \ 00234 } 00235 00236 00237 /**\def DECLARE_TLS(Type,Name) 00238 *\brief Cause non-POD TLS object of Type to be created and initialized. 00239 * 00240 * This macro declares a static "smart pointer" 00241 * named * Name_tls_wrapper to a 00242 * thread-local variable of the given Type. 00243 * When this static struct get initialized at static-init time, 00244 * it registers with the tls manager its init and fini methods. 00245 * Those methods invoke the init and fini methods of the item to 00246 * which this "smart pointer" points, which is the actual TLS entity: 00247 * a tls_tricks::tls_blobType. 00248 * 00249 *\addindex DECLARE_TLS 00250 */ 00251 #define DECLARE_TLS(Type, Name) \ 00252 static \ 00253 TLS_STRUCT(Type, Name##_tls_wrapper, Name##_tls_wrapper) Name 00254 00255 00256 /**\def DECLARE_TLS_SCHWARZ(Name) 00257 *\brief Cause a Schwarz counter to be declared (for use in header files). 00258 * 00259 *\relates DEFINE_TLS_STRUCT 00260 *\addindex DECLARE_TLS_SCHWARZ 00261 * 00262 * Make a Schwarz counter (in a .h) 00263 * to force initialization of the TLS 00264 * defined in a .cpp by DEFINE_TLS_SCHWARZ. This is useful if there is 00265 * a dependency between 2+ TLS variables so the correct one is 00266 * initialized first. 00267 * The only way you can control their order is to make sure their 00268 * DECLARE_TLS_SCHWARZ macros are in the correct order b/c C++ guarantees 00269 * static init order only for objects in the same translation unit. 00270 * Note that the counter is really in the tls wrapper. 00271 */ 00272 #define DECLARE_TLS_SCHWARZ(Name) \ 00273 static struct Name##_tls_wrapper_schwarz { \ 00274 Name##_tls_wrapper_schwarz(); \ 00275 } Name##_schwarz 00276 00277 /**\def DEFINE_TLS_SCHWARZ(Type,Name) 00278 *\brief Cause a Schwarz counter to be defined (for use in .cpp files). 00279 * 00280 *\addindex DEFINE_TLS_SCHWARZ 00281 *\relates DECLARE_TLS_STRUCT 00282 * 00283 * Define the TLS struct that DECLARE_TLS_SCHWARZ expects to initialize. 00284 */ 00285 #define DEFINE_TLS_SCHWARZ(Type, Name) \ 00286 static TLS_STRUCT(Type, Name##_tls_wrapper, static void init_wrapper) Name; \ 00287 Name##_tls_wrapper_schwarz::Name##_tls_wrapper_schwarz() { \ 00288 Name##_tls_wrapper::init_wrapper(); \ 00289 } 00290 00291 } /* namespace tls_tricks */ 00292 00293 #endif