1 /*************************************************************************
3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
5 * Copyright 2008 by Sun Microsystems, Inc.
7 * OpenOffice.org - a multi-platform office productivity suite
9 * $RCSfile: instance.hxx,v $
12 * This file is part of OpenOffice.org.
14 * OpenOffice.org is free software: you can redistribute it and/or modify
15 * it under the terms of the GNU Lesser General Public License version 3
16 * only, as published by the Free Software Foundation.
18 * OpenOffice.org is distributed in the hope that it will be useful,
19 * but WITHOUT ANY WARRANTY; without even the implied warranty of
20 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
21 * GNU Lesser General Public License version 3 for more details
22 * (a copy is included in the LICENSE file that accompanied this code).
24 * You should have received a copy of the GNU Lesser General Public License
25 * version 3 along with OpenOffice.org. If not, see
26 * <http://www.openoffice.org/license.html>
27 * for a copy of the LGPLv3 License.
29 ************************************************************************/
31 #if !defined INCLUDED_RTL_INSTANCE_HXX
32 #define INCLUDED_RTL_INSTANCE_HXX
34 #include "osl/doublecheckedlocking.h"
35 #include "osl/getglobalmutex.hxx"
39 /** A non-broken version of the double-checked locking pattern.
42 <http://www.cs.umd.edu/~pugh/java/memoryModel/DoubleCheckedLocking.html>
43 for a description of double-checked locking, why it is broken, and how it
44 can be fixed. Always use this template instead of spelling out the
45 double-checked locking pattern explicitly, and only in those rare cases
46 where that is not possible and you have to spell it out explicitly, at
47 least call OSL_DOUBLE_CHECKED_LOCKING_MEMORY_BARRIER() at the right
48 places. That way, all platform-dependent code to make double-checked
49 locking work can be kept in one place.
53 1 Static instance (most common case)
59 static T * pInstance = 0;
62 ::osl::MutexGuard aGuard(::osl::Mutex::getGlobalMutex());
66 pInstance = &aInstance;
74 #include "rtl/instance.hxx"
75 #include "osl/getglobalmutex.hxx"
90 return rtl_Instance< T, Init, ::osl::MutexGuard,
91 ::osl::GetGlobalMutex >::create(
92 Init(), ::osl::GetGlobalMutex());
101 static T * pInstance = 0;
104 ::osl::MutexGuard aGuard(::osl::Mutex::getGlobalMutex());
113 #include "rtl/instance.hxx"
114 #include "osl/getglobalmutex.hxx"
128 return rtl_Instance< T, Init, ::osl::MutexGuard,
129 ::osl::GetGlobalMutex >::create(
130 Init(), ::osl::GetGlobalMutex());
139 static T * pInstance = 0;
142 SomeGuard aGuard(pSomeMutex);
146 pInstance = &aInstance;
154 #include "rtl/instance.hxx"
168 SomeMutex * operator()()
177 return rtl_Instance< T, InitInstance,
178 SomeGuard, InitGuard >::create(
179 InitInstance(), InitMutex());
182 4 Calculate extra data
188 static T * pInstance = 0;
192 ::osl::MutexGuard aGuard(::osl::Mutex::getGlobalMutex());
195 static T aInstance(aData);
196 pInstance = &aInstance;
204 #include "rtl/instance.hxx"
205 #include "osl/getglobalmutex.hxx"
219 Data const & operator()()
228 return rtl_Instance< T, InitInstance,
229 ::osl::Mutex, ::osl::GetGlobalMutex,
230 Data, InitData >::create(
231 InitInstance(), ::osl::GetGlobalMutex(), InitData());
236 For any instantiation of rtl_Instance, at most one call to a create method
237 may occur in the program code: Each occurance of a create method within
238 the program code is supposed to return a fresh object instance on the
239 first call, and that same object instance on subsequent calls; but
240 independent occurances of create methods are supposed to return
241 independent object instances. Since there is a one-to-one correspondence
242 between object instances and instantiations of rtl_Instance, the
243 requirement should be clear. One measure to enforce the requirement is
244 that rtl_Instance lives in an unnamed namespace, so that instantiations of
245 rtl_Instance in different translation units will definitely be different
246 instantiations. A drawback of that measure is that the name of the class
247 needs a funny "hand coded" prefix "rtl_" instead of a proper namespace
248 prefix like "::rtl::".
250 A known problem with this template is when two occurences of calls to
251 create methods with identical template arguments appear in one translation
252 unit. Those two places will share a single object instance. This can be
253 avoided by using different Init structs (see the above code samples) in
256 There is no need to make m_pInstance volatile, in order to avoid usage of
257 stale copies of m_pInstance: At the first check, a thread will see that
258 m_pInstance contains either 0 or a valid pointer. If it contains a valid
259 pointer, it cannot be stale, and that pointer is used. If it contains 0,
260 acquiring the mutex will ensure that the second check sees a non-stale
263 On some compilers, the create methods would not be inlined if they
264 contained any static variables, so m_pInstance is made a class member
265 instead (and the create methods are inlined). But on MSC, the definition
266 of the class member m_pInstance would cause compilation to fail with an
267 internal compiler error. Since MSC is able to inline methods containing
268 static variables, m_pInstance is moved into the methods there. Note that
269 this only works well because for any instantiation of rtl_Instance at most
270 one call to a create method should be present, anyway.
272 template< typename Inst
, typename InstCtor
,
273 typename Guard
, typename GuardCtor
,
274 typename Data
= int, typename DataCtor
= int >
278 static inline Inst
* create(InstCtor aInstCtor
, GuardCtor aGuardCtor
)
281 static Inst
* m_pInstance
= 0;
283 Inst
* p
= m_pInstance
;
286 Guard
aGuard(aGuardCtor());
291 OSL_DOUBLE_CHECKED_LOCKING_MEMORY_BARRIER();
297 OSL_DOUBLE_CHECKED_LOCKING_MEMORY_BARRIER();
302 static inline Inst
* create(InstCtor aInstCtor
, GuardCtor aGuardCtor
,
306 static Inst
* m_pInstance
= 0;
308 Inst
* p
= m_pInstance
;
311 Data
aData(aDataCtor());
312 Guard
aGuard(aGuardCtor());
316 p
= aInstCtor(aData
);
317 OSL_DOUBLE_CHECKED_LOCKING_MEMORY_BARRIER();
323 OSL_DOUBLE_CHECKED_LOCKING_MEMORY_BARRIER();
329 #if !defined _MSC_VER
330 static Inst
* m_pInstance
;
334 #if !defined _MSC_VER
335 template< typename Inst
, typename InstCtor
,
336 typename Guard
, typename GuardCtor
,
337 typename Data
, typename DataCtor
>
339 rtl_Instance
< Inst
, InstCtor
, Guard
, GuardCtor
, Data
, DataCtor
>::m_pInstance
347 /** Helper base class for a late-initialized (default-constructed)
348 static variable, implementing the double-checked locking pattern correctly.
351 Derive from this class (common practice), e.g.
353 struct MyStatic : public rtl::Static<MyType, MyStatic> {};
355 MyType & rStatic = MyStatic::get();
362 Implementation trick to make the inner static holder unique,
363 using the outer class
364 (the one that derives from this base class)
366 template<typename T
, typename Unique
>
369 /** Gets the static. Mutual exclusion is performed using the
376 return *rtl_Instance
<
378 ::osl::MutexGuard
, ::osl::GetGlobalMutex
>::create(
379 StaticInstance(), ::osl::GetGlobalMutex() );
382 struct StaticInstance
{
390 /** Helper class for a late-initialized static aggregate, e.g. an array,
391 implementing the double-checked locking pattern correctly.
394 aggregate's element type
395 @tplparam InitAggregate
396 initializer functor class
398 template<typename T
, typename InitAggregate
>
399 class StaticAggregate
{
401 /** Gets the static aggregate, late-initializing.
402 Mutual exclusion is performed using the osl global mutex.
410 ::osl::MutexGuard
, ::osl::GetGlobalMutex
>::create(
411 InitAggregate(), ::osl::GetGlobalMutex() );
415 /** Helper base class for a late-initialized static variable,
416 implementing the double-checked locking pattern correctly.
419 Derive from this class (common practice),
420 providing an initializer functor class, e.g.
422 struct MyStatic : public rtl::StaticWithInit<MyType, MyStatic> {
423 MyType operator () () {
425 return MyType( ... );
429 MyType & rStatic = MyStatic::get();
436 initializer functor class
438 Implementation trick to make the inner static holder unique,
439 using the outer class
440 (the one that derives from this base class).
441 Default is InitData (common practice).
443 Initializer functor's return type.
444 Default is T (common practice).
446 template<typename T
, typename InitData
,
447 typename Unique
= InitData
, typename Data
= T
>
448 class StaticWithInit
{
450 /** Gets the static. Mutual exclusion is performed using the
457 return *rtl_Instance
<
458 T
, StaticInstanceWithInit
,
459 ::osl::MutexGuard
, ::osl::GetGlobalMutex
,
460 Data
, InitData
>::create( StaticInstanceWithInit(),
461 ::osl::GetGlobalMutex(),
465 struct StaticInstanceWithInit
{
466 T
* operator () ( Data d
) {
467 static T
instance(d
);
475 #endif // INCLUDED_RTL_INSTANCE_HXX