tls.h

Go to the documentation of this file.
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.3 2010/06/23 23:42:57 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;
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 Swatchz 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

Generated on Wed Jul 7 17:22:32 2010 for Shore Storage Manager by  doxygen 1.4.7