00001 /* 00002 * PROPRIETARY INFORMATION. This software is proprietary to 00003 * Side Effects Software Inc., and is not to be reproduced, 00004 * transmitted, or disclosed in any way without written permission. 00005 * 00006 * Produced by: 00007 * Side Effects Software Inc 00008 * 123 Front Street West, Suite 1401 00009 * Toronto, Ontario 00010 * Canada M5J 2M2 00011 * 416-504-9876 00012 * 00013 * COMMENTS: 00014 * This class defines a thread-specific pointer that can be used to 00015 * implement thread-local storage. Each thread that accesses the 00016 * pointer will have its own copy of the pointer's value, and the 00017 * initial value for all threads is null. 00018 * 00019 * To replace a global variable like 00020 * 00021 * static int theGlobalValue = 0; 00022 * // use theGlobalValue 00023 * 00024 * to use thread-local storage, you would write something like 00025 * 00026 * static UT_ThreadSpecificValue<int> theGlobalValue; 00027 * // use theGlobalValue.get() 00028 * 00029 * Note that the default constructor for the values will be called. 00030 * (For native data types like ints, floats, pointers, etc., they will 00031 * be initialized to zero/null.) 00032 * 00033 * This class has been tuned for speed. Speed of TLS is surprisingly 00034 * sensitive to changes to this class. 00035 */ 00036 00037 #ifndef __UT_ThreadSpecificValue_h__ 00038 #define __UT_ThreadSpecificValue_h__ 00039 00040 #if defined(GAMEOS) 00041 #define HAS_NO_TLS 00042 #endif 00043 00044 #ifndef HAS_NO_TLS 00045 #include "UT_Thread.h" 00046 #include "UT_Lock.h" 00047 #endif 00048 00049 #include "UT_PtrArray.h" 00050 #include <limits> 00051 00052 #define UT_TYPICAL_MAX_THREADS 16 00053 00054 template <typename T> class ut_IsPointer 00055 { public: static const bool value = false; }; 00056 00057 template <typename U> class ut_IsPointer<U*> 00058 { public: static const bool value = true; }; 00059 00060 // Simple implementation for platforms which have no thread support 00061 template <typename T> 00062 class UT_ThreadSpecificValue 00063 { 00064 public: 00065 UT_ThreadSpecificValue() 00066 { 00067 // If T is an object, the default constructor will have been called. 00068 // Otherwise, initialize the memory to 0. 00069 if (std::numeric_limits<T>::is_specialized || ut_IsPointer<T>::value) 00070 memset(myPreallocatedValues, 0, sizeof(T) * UT_TYPICAL_MAX_THREADS); 00071 } 00072 00073 ~UT_ThreadSpecificValue() 00074 { 00075 for (int i=0; i<myDynamicValues.entries(); ++i) 00076 delete myDynamicValues(i); 00077 } 00078 00079 // getMySequentialThreadIndex() will "allocate" an index for this thread 00080 // if it has never been called from this thread. The thread indices it 00081 // returns start at 0. See UT_Thread.h for more information. 00082 // 00083 // Note that we use a UT_PtrArray instead of a UT_RefArray. This way, 00084 // one thread can call get(), growing myDynamicValues, and hold a reference 00085 // to the result. Then a second thread can call get(), growing 00086 // myDynamicValues again. If we used a UT_RefArray instead of a 00087 // UT_PtrArray, the first thread's reference would become invalid. 00088 T &get() 00089 { 00090 #ifdef HAS_NO_TLS 00091 int index = 0; 00092 #else 00093 int index = UT_Thread::getMySequentialThreadIndex() - 1; 00094 #endif 00095 if (index < UT_TYPICAL_MAX_THREADS) 00096 return myPreallocatedValues[index]; 00097 00098 return growDynamicValues(index); 00099 } 00100 00101 const T &get() const 00102 { 00103 #ifdef HAS_NO_TLS 00104 int index = 0; 00105 #else 00106 int index = UT_Thread::getMySequentialThreadIndex() - 1; 00107 #endif 00108 if (index < UT_TYPICAL_MAX_THREADS) 00109 return myPreallocatedValues[index]; 00110 00111 return growDynamicValues(index); 00112 } 00113 00114 /// Access the value for a particular thread index. 00115 /// Note that the threads you care about may not have 00116 /// been assigned sequentially! Always loop up to the maxthreads 00117 /// value and be able to handle zero-initialized empty data. 00118 T &getValueForThread(int thread_index) 00119 { 00120 // We want to catch cases where people are passing in the default 0 00121 // thread value. However, for HDK users, we will fall back to computing 00122 // it automatically for correctness. 00123 UT_ASSERT(thread_index > 0); 00124 if (thread_index == 0) 00125 thread_index = UT_Thread::getMySequentialThreadIndex() - 1; 00126 else 00127 thread_index--; 00128 00129 if (thread_index < UT_TYPICAL_MAX_THREADS) 00130 return myPreallocatedValues[thread_index]; 00131 00132 return growDynamicValues(thread_index); 00133 } 00134 const T &getValueForThread(int thread_index) const 00135 { 00136 // We want to catch cases where people are passing in the default 0 00137 // thread value. However, for HDK users, we will fall back to computing 00138 // it automatically for correctness. 00139 UT_ASSERT(thread_index > 0); 00140 if (thread_index == 0) 00141 thread_index = UT_Thread::getMySequentialThreadIndex() - 1; 00142 else 00143 thread_index--; 00144 00145 if (thread_index < UT_TYPICAL_MAX_THREADS) 00146 return myPreallocatedValues[thread_index]; 00147 00148 return growDynamicValues(thread_index); 00149 } 00150 00151 /// The highest value of thread index that has been seen by 00152 /// this threadspecific value. Iterating over 0..maxthreads-1 00153 /// will allow you to check all thread output. 00154 int maxThreadsSeen() const 00155 { 00156 // This may be less than the actual number if someone 00157 // is currently writing to myDynamicValues, but then one 00158 // is doing something very questionable. 00159 return UT_TYPICAL_MAX_THREADS + myDynamicValues.entries(); 00160 } 00161 00162 private: 00163 UT_ThreadSpecificValue(const UT_ThreadSpecificValue<T> &); // unimplemented 00164 00165 T &growDynamicValues(int thread_index) const 00166 { 00167 // UT_PtrArray will properly grow the array if necessary and return 00168 // a null pointer. 00169 UT_AutoLock auto_lock(myDynamicValueLock); 00170 T *&value_pointer = 00171 myDynamicValues[thread_index - UT_TYPICAL_MAX_THREADS]; 00172 if (!value_pointer) 00173 value_pointer = new T(); 00174 return *value_pointer; 00175 } 00176 00177 private: 00178 T myPreallocatedValues[UT_TYPICAL_MAX_THREADS]; 00179 mutable UT_PtrArray<T *> myDynamicValues; 00180 mutable UT_Lock myDynamicValueLock; 00181 }; 00182 00183 #undef UT_TYPICAL_MAX_THREADS 00184 00185 #endif
1.5.9