1 /************************************************************************* 2 * 3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. 4 * 5 * Copyright 2000, 2010 Oracle and/or its affiliates. 6 * 7 * OpenOffice.org - a multi-platform office productivity suite 8 * 9 * This file is part of OpenOffice.org. 10 * 11 * OpenOffice.org is free software: you can redistribute it and/or modify 12 * it under the terms of the GNU Lesser General Public License version 3 13 * only, as published by the Free Software Foundation. 14 * 15 * OpenOffice.org is distributed in the hope that it will be useful, 16 * but WITHOUT ANY WARRANTY; without even the implied warranty of 17 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 18 * GNU Lesser General Public License version 3 for more details 19 * (a copy is included in the LICENSE file that accompanied this code). 20 * 21 * You should have received a copy of the GNU Lesser General Public License 22 * version 3 along with OpenOffice.org. If not, see 23 * <http://www.openoffice.org/license.html> 24 * for a copy of the LGPLv3 License. 25 * 26 ************************************************************************/ 27 28 #if !defined INCLUDED_RTL_INSTANCE_HXX 29 #define INCLUDED_RTL_INSTANCE_HXX 30 31 #include "osl/doublecheckedlocking.h" 32 #include "osl/getglobalmutex.hxx" 33 34 namespace { 35 36 /** A non-broken version of the double-checked locking pattern. 37 38 See 39 <http://www.cs.umd.edu/~pugh/java/memoryModel/DoubleCheckedLocking.html> 40 for a description of double-checked locking, why it is broken, and how it 41 can be fixed. Always use this template instead of spelling out the 42 double-checked locking pattern explicitly, and only in those rare cases 43 where that is not possible and you have to spell it out explicitly, at 44 least call OSL_DOUBLE_CHECKED_LOCKING_MEMORY_BARRIER() at the right 45 places. That way, all platform-dependent code to make double-checked 46 locking work can be kept in one place. 47 48 Usage scenarios: 49 50 1 Static instance (most common case) 51 52 Pattern: 53 54 T * getInstance() 55 { 56 static T * pInstance = 0; 57 if (!pInstance) 58 { 59 ::osl::MutexGuard aGuard(::osl::Mutex::getGlobalMutex()); 60 if (!pInstance) 61 { 62 static T aInstance; 63 pInstance = &aInstance; 64 } 65 } 66 return pInstance; 67 } 68 69 Code: 70 71 #include "rtl/instance.hxx" 72 #include "osl/getglobalmutex.hxx" 73 74 namespace { 75 struct Init 76 { 77 T * operator()() 78 { 79 static T aInstance; 80 return &aInstance; 81 } 82 }; 83 } 84 85 T * getInstance() 86 { 87 return rtl_Instance< T, Init, ::osl::MutexGuard, 88 ::osl::GetGlobalMutex >::create( 89 Init(), ::osl::GetGlobalMutex()); 90 } 91 92 2 Dynamic instance 93 94 Pattern: 95 96 T * getInstance() 97 { 98 static T * pInstance = 0; 99 if (!pInstance) 100 { 101 ::osl::MutexGuard aGuard(::osl::Mutex::getGlobalMutex()); 102 if (!pInstance) 103 pInstance = new T; 104 } 105 return pInstance; 106 } 107 108 Code: 109 110 #include "rtl/instance.hxx" 111 #include "osl/getglobalmutex.hxx" 112 113 namespace { 114 struct Init 115 { 116 T * operator()() 117 { 118 return new T; 119 } 120 }; 121 } 122 123 T * getInstance() 124 { 125 return rtl_Instance< T, Init, ::osl::MutexGuard, 126 ::osl::GetGlobalMutex >::create( 127 Init(), ::osl::GetGlobalMutex()); 128 } 129 130 3 Other guard/mutex 131 132 Pattern: 133 134 T * getInstance() 135 { 136 static T * pInstance = 0; 137 if (!pInstance) 138 { 139 SomeGuard aGuard(pSomeMutex); 140 if (!pInstance) 141 { 142 static T aInstance; 143 pInstance = &aInstance; 144 } 145 } 146 return pInstance; 147 } 148 149 Code: 150 151 #include "rtl/instance.hxx" 152 153 namespace { 154 struct InitInstance 155 { 156 T * operator()() 157 { 158 static T aInstance; 159 return &aInstance; 160 } 161 }; 162 163 struct InitGuard 164 { 165 SomeMutex * operator()() 166 { 167 return pSomeMutex; 168 } 169 }; 170 } 171 172 T * getInstance() 173 { 174 return rtl_Instance< T, InitInstance, 175 SomeGuard, InitGuard >::create( 176 InitInstance(), InitMutex()); 177 } 178 179 4 Calculate extra data 180 181 Pattern: 182 183 T * getInstance() 184 { 185 static T * pInstance = 0; 186 if (!pInstance) 187 { 188 Data aData(...); 189 ::osl::MutexGuard aGuard(::osl::Mutex::getGlobalMutex()); 190 if (!pInstance) 191 { 192 static T aInstance(aData); 193 pInstance = &aInstance; 194 } 195 } 196 return pInstance; 197 } 198 199 Code: 200 201 #include "rtl/instance.hxx" 202 #include "osl/getglobalmutex.hxx" 203 204 namespace { 205 struct InitInstance 206 { 207 T * operator()() 208 { 209 static T aInstance; 210 return &aInstance; 211 } 212 } 213 214 struct InitData 215 { 216 Data const & operator()() 217 { 218 return ...; 219 } 220 } 221 } 222 223 T * getInstance() 224 { 225 return rtl_Instance< T, InitInstance, 226 ::osl::Mutex, ::osl::GetGlobalMutex, 227 Data, InitData >::create( 228 InitInstance(), ::osl::GetGlobalMutex(), InitData()); 229 } 230 231 Some comments: 232 233 For any instantiation of rtl_Instance, at most one call to a create method 234 may occur in the program code: Each occurance of a create method within 235 the program code is supposed to return a fresh object instance on the 236 first call, and that same object instance on subsequent calls; but 237 independent occurances of create methods are supposed to return 238 independent object instances. Since there is a one-to-one correspondence 239 between object instances and instantiations of rtl_Instance, the 240 requirement should be clear. One measure to enforce the requirement is 241 that rtl_Instance lives in an unnamed namespace, so that instantiations of 242 rtl_Instance in different translation units will definitely be different 243 instantiations. A drawback of that measure is that the name of the class 244 needs a funny "hand coded" prefix "rtl_" instead of a proper namespace 245 prefix like "::rtl::". 246 247 A known problem with this template is when two occurences of calls to 248 create methods with identical template arguments appear in one translation 249 unit. Those two places will share a single object instance. This can be 250 avoided by using different Init structs (see the above code samples) in 251 the two places. 252 253 There is no need to make m_pInstance volatile, in order to avoid usage of 254 stale copies of m_pInstance: At the first check, a thread will see that 255 m_pInstance contains either 0 or a valid pointer. If it contains a valid 256 pointer, it cannot be stale, and that pointer is used. If it contains 0, 257 acquiring the mutex will ensure that the second check sees a non-stale 258 value in all cases. 259 260 On some compilers, the create methods would not be inlined if they 261 contained any static variables, so m_pInstance is made a class member 262 instead (and the create methods are inlined). But on MSC, the definition 263 of the class member m_pInstance would cause compilation to fail with an 264 internal compiler error. Since MSC is able to inline methods containing 265 static variables, m_pInstance is moved into the methods there. Note that 266 this only works well because for any instantiation of rtl_Instance at most 267 one call to a create method should be present, anyway. 268 */ 269 template< typename Inst, typename InstCtor, 270 typename Guard, typename GuardCtor, 271 typename Data = int, typename DataCtor = int > 272 class rtl_Instance 273 { 274 public: 275 static inline Inst * create(InstCtor aInstCtor, GuardCtor aGuardCtor) 276 { 277 #if defined _MSC_VER 278 static Inst * m_pInstance = 0; 279 #endif // _MSC_VER 280 Inst * p = m_pInstance; 281 if (!p) 282 { 283 Guard aGuard(aGuardCtor()); 284 p = m_pInstance; 285 if (!p) 286 { 287 p = aInstCtor(); 288 OSL_DOUBLE_CHECKED_LOCKING_MEMORY_BARRIER(); 289 m_pInstance = p; 290 } 291 } 292 else 293 { 294 OSL_DOUBLE_CHECKED_LOCKING_MEMORY_BARRIER(); 295 } 296 return p; 297 } 298 299 static inline Inst * create(InstCtor aInstCtor, GuardCtor aGuardCtor, 300 DataCtor aDataCtor) 301 { 302 #if defined _MSC_VER 303 static Inst * m_pInstance = 0; 304 #endif // _MSC_VER 305 Inst * p = m_pInstance; 306 if (!p) 307 { 308 Data aData(aDataCtor()); 309 Guard aGuard(aGuardCtor()); 310 p = m_pInstance; 311 if (!p) 312 { 313 p = aInstCtor(aData); 314 OSL_DOUBLE_CHECKED_LOCKING_MEMORY_BARRIER(); 315 m_pInstance = p; 316 } 317 } 318 else 319 { 320 OSL_DOUBLE_CHECKED_LOCKING_MEMORY_BARRIER(); 321 } 322 return p; 323 } 324 325 private: 326 #if !defined _MSC_VER 327 static Inst * m_pInstance; 328 #endif // _MSC_VER 329 }; 330 331 #if !defined _MSC_VER 332 template< typename Inst, typename InstCtor, 333 typename Guard, typename GuardCtor, 334 typename Data, typename DataCtor > 335 Inst * 336 rtl_Instance< Inst, InstCtor, Guard, GuardCtor, Data, DataCtor >::m_pInstance 337 = 0; 338 #endif // _MSC_VER 339 340 } 341 342 namespace rtl { 343 344 /** Helper base class for a late-initialized (default-constructed) 345 static variable, implementing the double-checked locking pattern correctly. 346 347 @derive 348 Derive from this class (common practice), e.g. 349 <pre> 350 struct MyStatic : public rtl::Static<MyType, MyStatic> {}; 351 ... 352 MyType & rStatic = MyStatic::get(); 353 ... 354 </pre> 355 356 @tplparam T 357 variable's type 358 @tplparam Unique 359 Implementation trick to make the inner static holder unique, 360 using the outer class 361 (the one that derives from this base class) 362 */ 363 template<typename T, typename Unique> 364 class Static { 365 public: 366 /** Gets the static. Mutual exclusion is performed using the 367 osl global mutex. 368 369 @return 370 static variable 371 */ 372 static T & get() { 373 return *rtl_Instance< 374 T, StaticInstance, 375 ::osl::MutexGuard, ::osl::GetGlobalMutex >::create( 376 StaticInstance(), ::osl::GetGlobalMutex() ); 377 } 378 private: 379 struct StaticInstance { 380 T * operator () () { 381 static T instance; 382 return &instance; 383 } 384 }; 385 }; 386 387 /** Helper class for a late-initialized static aggregate, e.g. an array, 388 implementing the double-checked locking pattern correctly. 389 390 @tplparam T 391 aggregate's element type 392 @tplparam InitAggregate 393 initializer functor class 394 */ 395 template<typename T, typename InitAggregate> 396 class StaticAggregate { 397 public: 398 /** Gets the static aggregate, late-initializing. 399 Mutual exclusion is performed using the osl global mutex. 400 401 @return 402 aggregate 403 */ 404 static T * get() { 405 return rtl_Instance< 406 T, InitAggregate, 407 ::osl::MutexGuard, ::osl::GetGlobalMutex >::create( 408 InitAggregate(), ::osl::GetGlobalMutex() ); 409 } 410 }; 411 412 /** Helper base class for a late-initialized static variable, 413 implementing the double-checked locking pattern correctly. 414 415 @derive 416 Derive from this class (common practice), 417 providing an initializer functor class, e.g. 418 <pre> 419 struct MyStatic : public rtl::StaticWithInit<MyType, MyStatic> { 420 MyType operator () () { 421 ... 422 return MyType( ... ); 423 } 424 }; 425 ... 426 MyType & rStatic = MyStatic::get(); 427 ... 428 </pre> 429 430 @tplparam T 431 variable's type 432 @tplparam InitData 433 initializer functor class 434 @tplparam Unique 435 Implementation trick to make the inner static holder unique, 436 using the outer class 437 (the one that derives from this base class). 438 Default is InitData (common practice). 439 @tplparam Data 440 Initializer functor's return type. 441 Default is T (common practice). 442 */ 443 template<typename T, typename InitData, 444 typename Unique = InitData, typename Data = T> 445 class StaticWithInit { 446 public: 447 /** Gets the static. Mutual exclusion is performed using the 448 osl global mutex. 449 450 @return 451 static variable 452 */ 453 static T & get() { 454 return *rtl_Instance< 455 T, StaticInstanceWithInit, 456 ::osl::MutexGuard, ::osl::GetGlobalMutex, 457 Data, InitData >::create( StaticInstanceWithInit(), 458 ::osl::GetGlobalMutex(), 459 InitData() ); 460 } 461 private: 462 struct StaticInstanceWithInit { 463 T * operator () ( Data d ) { 464 static T instance(d); 465 return &instance; 466 } 467 }; 468 }; 469 470 } // namespace rtl 471 472 #endif // INCLUDED_RTL_INSTANCE_HXX 473