1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
3 * This file is part of the LibreOffice project.
5 * This Source Code Form is subject to the terms of the Mozilla Public
6 * License, v. 2.0. If a copy of the MPL was not distributed with this
7 * file, You can obtain one at http://mozilla.org/MPL/2.0/.
9 * This file incorporates work covered by the following license notice:
11 * Licensed to the Apache Software Foundation (ASF) under one or more
12 * contributor license agreements. See the NOTICE file distributed
13 * with this work for additional information regarding copyright
14 * ownership. The ASF licenses this file to you under the Apache
15 * License, Version 2.0 (the "License"); you may not use this file
16 * except in compliance with the License. You may obtain a copy of
17 * the License at http://www.apache.org/licenses/LICENSE-2.0 .
20 #ifndef INCLUDED_RTL_INSTANCE_HXX
21 #define INCLUDED_RTL_INSTANCE_HXX
23 #include "sal/config.h"
25 #include "osl/doublecheckedlocking.h"
26 #include "osl/getglobalmutex.hxx"
30 /** A non-broken version of the double-checked locking pattern.
33 <http://www.cs.umd.edu/~pugh/java/memoryModel/DoubleCheckedLocking.html>
34 for a description of double-checked locking, why it is broken, and how it
35 can be fixed. Always use this template instead of spelling out the
36 double-checked locking pattern explicitly, and only in those rare cases
37 where that is not possible and you have to spell it out explicitly, at
38 least call OSL_DOUBLE_CHECKED_LOCKING_MEMORY_BARRIER() at the right
39 places. That way, all platform-dependent code to make double-checked
40 locking work can be kept in one place.
44 1 Static instance (most common case)
50 static T * pInstance = 0;
53 ::osl::MutexGuard aGuard(::osl::Mutex::getGlobalMutex());
57 pInstance = &aInstance;
65 #include "rtl/instance.hxx"
66 #include "osl/getglobalmutex.hxx"
81 return rtl_Instance< T, Init, ::osl::MutexGuard,
82 ::osl::GetGlobalMutex >::create(
83 Init(), ::osl::GetGlobalMutex());
92 static T * pInstance = 0;
95 ::osl::MutexGuard aGuard(::osl::Mutex::getGlobalMutex());
104 #include "rtl/instance.hxx"
105 #include "osl/getglobalmutex.hxx"
119 return rtl_Instance< T, Init, ::osl::MutexGuard,
120 ::osl::GetGlobalMutex >::create(
121 Init(), ::osl::GetGlobalMutex());
130 static T * pInstance = 0;
133 SomeGuard aGuard(pSomeMutex);
137 pInstance = &aInstance;
145 #include "rtl/instance.hxx"
159 SomeMutex * operator()()
168 return rtl_Instance< T, InitInstance,
169 SomeGuard, InitGuard >::create(
170 InitInstance(), InitMutex());
173 4 Calculate extra data
179 static T * pInstance = 0;
183 ::osl::MutexGuard aGuard(::osl::Mutex::getGlobalMutex());
186 static T aInstance(aData);
187 pInstance = &aInstance;
195 #include "rtl/instance.hxx"
196 #include "osl/getglobalmutex.hxx"
210 Data const & operator()()
219 return rtl_Instance< T, InitInstance,
220 ::osl::Mutex, ::osl::GetGlobalMutex,
221 Data, InitData >::create(
222 InitInstance(), ::osl::GetGlobalMutex(), InitData());
227 For any instantiation of rtl_Instance, at most one call to a create method
228 may occur in the program code: Each occurrence of a create method within
229 the program code is supposed to return a fresh object instance on the
230 first call, and that same object instance on subsequent calls; but
231 independent occurrences of create methods are supposed to return
232 independent object instances. Since there is a one-to-one correspondence
233 between object instances and instantiations of rtl_Instance, the
234 requirement should be clear. One measure to enforce the requirement is
235 that rtl_Instance lives in an unnamed namespace, so that instantiations of
236 rtl_Instance in different translation units will definitely be different
237 instantiations. A drawback of that measure is that the name of the class
238 needs a funny "hand coded" prefix "rtl_" instead of a proper namespace
239 prefix like "::rtl::".
241 A known problem with this template is when two occurrences of calls to
242 create methods with identical template arguments appear in one translation
243 unit. Those two places will share a single object instance. This can be
244 avoided by using different Init structs (see the above code samples) in
247 There is no need to make m_pInstance volatile, in order to avoid usage of
248 stale copies of m_pInstance: At the first check, a thread will see that
249 m_pInstance contains either 0 or a valid pointer. If it contains a valid
250 pointer, it cannot be stale, and that pointer is used. If it contains 0,
251 acquiring the mutex will ensure that the second check sees a non-stale
254 On some compilers, the create methods would not be inlined if they
255 contained any static variables, so m_pInstance is made a class member
256 instead (and the create methods are inlined). But on MSC, the definition
257 of the class member m_pInstance would cause compilation to fail with an
258 internal compiler error. Since MSC is able to inline methods containing
259 static variables, m_pInstance is moved into the methods there. Note that
260 this only works well because for any instantiation of rtl_Instance at most
261 one call to a create method should be present, anyway.
263 template< typename Inst
, typename InstCtor
,
264 typename Guard
, typename GuardCtor
,
265 typename Data
= int, typename DataCtor
= int >
269 static inline Inst
* create(InstCtor aInstCtor
, GuardCtor aGuardCtor
)
272 static Inst
* m_pInstance
= 0;
274 Inst
* p
= m_pInstance
;
277 Guard
aGuard(aGuardCtor());
282 OSL_DOUBLE_CHECKED_LOCKING_MEMORY_BARRIER();
288 OSL_DOUBLE_CHECKED_LOCKING_MEMORY_BARRIER();
293 static inline Inst
* create(InstCtor aInstCtor
, GuardCtor aGuardCtor
,
297 static Inst
* m_pInstance
= 0;
299 Inst
* p
= m_pInstance
;
302 Data
aData(aDataCtor());
303 Guard
aGuard(aGuardCtor());
307 p
= aInstCtor(aData
);
308 OSL_DOUBLE_CHECKED_LOCKING_MEMORY_BARRIER();
314 OSL_DOUBLE_CHECKED_LOCKING_MEMORY_BARRIER();
319 static inline Inst
* create(InstCtor aInstCtor
, GuardCtor aGuardCtor
,
323 static Inst
* m_pInstance
= 0;
325 Inst
* p
= m_pInstance
;
328 Guard
aGuard(aGuardCtor());
332 p
= aInstCtor(rData
);
333 OSL_DOUBLE_CHECKED_LOCKING_MEMORY_BARRIER();
339 OSL_DOUBLE_CHECKED_LOCKING_MEMORY_BARRIER();
345 #if !defined _MSC_VER
346 static Inst
* m_pInstance
;
350 #if !defined _MSC_VER
351 template< typename Inst
, typename InstCtor
,
352 typename Guard
, typename GuardCtor
,
353 typename Data
, typename DataCtor
>
355 rtl_Instance
< Inst
, InstCtor
, Guard
, GuardCtor
, Data
, DataCtor
>::m_pInstance
363 /** Helper base class for a late-initialized (default-constructed)
364 static variable, implementing the double-checked locking pattern correctly.
367 Derive from this class (common practice), e.g.
369 struct MyStatic : public rtl::Static<MyType, MyStatic> {};
371 MyType & rStatic = MyStatic::get();
378 Implementation trick to make the inner static holder unique,
379 using the outer class
380 (the one that derives from this base class)
382 #if HAVE_THREADSAFE_STATICS
383 template<typename T
, typename Unique
>
386 /** Gets the static. Mutual exclusion is implied by a functional
398 template<typename T
, typename Unique
>
401 /** Gets the static. Mutual exclusion is performed using the
408 return *rtl_Instance
<
410 ::osl::MutexGuard
, ::osl::GetGlobalMutex
>::create(
411 StaticInstance(), ::osl::GetGlobalMutex() );
414 struct StaticInstance
{
423 /** Helper base class for a late-initialized (default-constructed)
424 static variable, implementing the double-checked locking pattern correctly.
427 Derive from this class (common practice), e.g.
429 struct MyStatic : public rtl::Static<MyType, MyStatic> {};
431 MyType & rStatic = MyStatic::get();
438 Implementation trick to make the inner static holder unique,
439 using the outer class
440 (the one that derives from this base class)
442 #if HAVE_THREADSAFE_STATICS
443 template<typename T
, typename Data
, typename Unique
>
444 class StaticWithArg
{
446 /** Gets the static. Mutual exclusion is implied by a functional
452 static T
& get(const Data
& rData
) {
453 static T
instance(rData
);
457 /** Gets the static. Mutual exclusion is implied by a functional
463 static T
& get(Data
& rData
) {
464 static T
instance(rData
);
469 template<typename T
, typename Data
, typename Unique
>
470 class StaticWithArg
{
472 /** Gets the static. Mutual exclusion is performed using the
478 static T
& get(const Data
& rData
) {
479 return *rtl_Instance
<
480 T
, StaticInstanceWithArg
,
481 ::osl::MutexGuard
, ::osl::GetGlobalMutex
,
482 Data
>::create( StaticInstanceWithArg(),
483 ::osl::GetGlobalMutex(),
487 /** Gets the static. Mutual exclusion is performed using the
493 static T
& get(Data
& rData
) {
494 return *rtl_Instance
<
495 T
, StaticInstanceWithArg
,
496 ::osl::MutexGuard
, ::osl::GetGlobalMutex
,
497 Data
>::create( StaticInstanceWithArg(),
498 ::osl::GetGlobalMutex(),
502 struct StaticInstanceWithArg
{
503 T
* operator () (const Data
& rData
) {
504 static T
instance(rData
);
508 T
* operator () (Data
& rData
) {
509 static T
instance(rData
);
516 /** Helper class for a late-initialized static aggregate, e.g. an array,
517 implementing the double-checked locking pattern correctly.
520 aggregate's element type
521 @tparam InitAggregate
522 initializer functor class
524 #if HAVE_THREADSAFE_STATICS
525 template<typename T
, typename InitAggregate
>
526 class StaticAggregate
{
528 /** Gets the static aggregate, late-initializing.
529 Mutual exclusion is implied by a functional
536 static T
*instance
= InitAggregate()();
541 template<typename T
, typename InitAggregate
>
542 class StaticAggregate
{
544 /** Gets the static aggregate, late-initializing.
545 Mutual exclusion is performed using the osl global mutex.
553 ::osl::MutexGuard
, ::osl::GetGlobalMutex
>::create(
554 InitAggregate(), ::osl::GetGlobalMutex() );
558 /** Helper base class for a late-initialized static variable,
559 implementing the double-checked locking pattern correctly.
562 Derive from this class (common practice),
563 providing an initializer functor class, e.g.
565 struct MyStatic : public rtl::StaticWithInit<MyType, MyStatic> {
566 MyType operator () () {
568 return MyType( ... );
572 MyType & rStatic = MyStatic::get();
579 initializer functor class
581 Implementation trick to make the inner static holder unique,
582 using the outer class
583 (the one that derives from this base class).
584 Default is InitData (common practice).
586 Initializer functor's return type.
587 Default is T (common practice).
589 #if HAVE_THREADSAFE_STATICS
590 template<typename T
, typename InitData
,
591 typename Unique
= InitData
, typename Data
= T
>
592 class StaticWithInit
{
594 /** Gets the static. Mutual exclusion is implied by a functional
601 static T instance
= InitData()();
606 template<typename T
, typename InitData
,
607 typename Unique
= InitData
, typename Data
= T
>
608 class StaticWithInit
{
610 /** Gets the static. Mutual exclusion is performed using the
617 return *rtl_Instance
<
618 T
, StaticInstanceWithInit
,
619 ::osl::MutexGuard
, ::osl::GetGlobalMutex
,
620 Data
, InitData
>::create( StaticInstanceWithInit(),
621 ::osl::GetGlobalMutex(),
625 struct StaticInstanceWithInit
{
626 T
* operator () ( Data d
) {
627 static T
instance(d
);
635 #endif // INCLUDED_RTL_INSTANCE_HXX
637 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */