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 .
21 * This file is part of LibreOffice published API.
24 #ifndef INCLUDED_RTL_INSTANCE_HXX
25 #define INCLUDED_RTL_INSTANCE_HXX
27 #include "sal/config.h"
31 #include "osl/doublecheckedlocking.h"
32 #include "osl/getglobalmutex.hxx"
36 /** A non-broken version of the double-checked locking pattern.
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.
50 1 Static instance (most common case)
56 static T * pInstance = 0;
59 ::osl::MutexGuard aGuard(::osl::Mutex::getGlobalMutex());
63 pInstance = &aInstance;
71 #include <rtl/instance.hxx>
72 #include <osl/getglobalmutex.hxx>
87 return rtl_Instance< T, Init, ::osl::MutexGuard,
88 ::osl::GetGlobalMutex >::create(
89 Init(), ::osl::GetGlobalMutex());
98 static T * pInstance = 0;
101 ::osl::MutexGuard aGuard(::osl::Mutex::getGlobalMutex());
110 #include <rtl/instance.hxx>
111 #include <osl/getglobalmutex.hxx>
125 return rtl_Instance< T, Init, ::osl::MutexGuard,
126 ::osl::GetGlobalMutex >::create(
127 Init(), ::osl::GetGlobalMutex());
136 static T * pInstance = 0;
139 SomeGuard aGuard(pSomeMutex);
143 pInstance = &aInstance;
151 #include <rtl/instance.hxx>
165 SomeMutex * operator()()
174 return rtl_Instance< T, InitInstance,
175 SomeGuard, InitGuard >::create(
176 InitInstance(), InitMutex());
179 4 Calculate extra data
185 static T * pInstance = 0;
189 ::osl::MutexGuard aGuard(::osl::Mutex::getGlobalMutex());
192 static T aInstance(aData);
193 pInstance = &aInstance;
201 #include <rtl/instance.hxx>
202 #include <osl/getglobalmutex.hxx>
216 Data const & operator()()
225 return rtl_Instance< T, InitInstance,
226 ::osl::MutexGuard, ::osl::GetGlobalMutex,
227 Data, InitData >::create(
228 InitInstance(), ::osl::GetGlobalMutex(), InitData());
233 For any instantiation of rtl_Instance, at most one call to a create method
234 may occur in the program code: Each occurrence 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 occurrences 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::".
247 A known problem with this template is when two occurrences 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
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
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.
269 template< typename Inst
, typename InstCtor
,
270 typename Guard
, typename GuardCtor
,
271 typename Data
= int, typename DataCtor
= int >
275 static Inst
* create(InstCtor aInstCtor
, GuardCtor aGuardCtor
)
278 static Inst
* m_pInstance
= 0;
280 Inst
* p
= m_pInstance
;
283 Guard
aGuard(aGuardCtor());
288 OSL_DOUBLE_CHECKED_LOCKING_MEMORY_BARRIER();
294 OSL_DOUBLE_CHECKED_LOCKING_MEMORY_BARRIER();
299 static Inst
* create(InstCtor aInstCtor
, GuardCtor aGuardCtor
,
303 static Inst
* m_pInstance
= 0;
305 Inst
* p
= m_pInstance
;
308 Data
aData(aDataCtor());
309 Guard
aGuard(aGuardCtor());
313 p
= aInstCtor(aData
);
314 OSL_DOUBLE_CHECKED_LOCKING_MEMORY_BARRIER();
320 OSL_DOUBLE_CHECKED_LOCKING_MEMORY_BARRIER();
325 static Inst
* create(InstCtor aInstCtor
, GuardCtor aGuardCtor
,
329 static Inst
* m_pInstance
= 0;
331 Inst
* p
= m_pInstance
;
334 Guard
aGuard(aGuardCtor());
338 p
= aInstCtor(rData
);
339 OSL_DOUBLE_CHECKED_LOCKING_MEMORY_BARRIER();
345 OSL_DOUBLE_CHECKED_LOCKING_MEMORY_BARRIER();
351 #if !defined _MSC_VER
352 static Inst
* m_pInstance
;
356 #if !defined _MSC_VER
357 template< typename Inst
, typename InstCtor
,
358 typename Guard
, typename GuardCtor
,
359 typename Data
, typename DataCtor
>
361 rtl_Instance
< Inst
, InstCtor
, Guard
, GuardCtor
, Data
, DataCtor
>::m_pInstance
369 /** Helper base class for a late-initialized (default-constructed)
370 static variable, implementing the double-checked locking pattern correctly.
373 Derive from this class (common practice), e.g.
375 struct MyStatic : public rtl::Static<MyType, MyStatic> {};
377 MyType & rStatic = MyStatic::get();
384 Implementation trick to make the inner static holder unique,
385 using the outer class
386 (the one that derives from this base class)
388 #if defined LIBO_INTERNAL_ONLY
389 template<typename T
, typename Unique
>
392 /** Gets the static. Mutual exclusion is implied by a functional
404 template<typename T
, typename Unique
>
407 /** Gets the static. Mutual exclusion is performed using the
414 return *rtl_Instance
<
416 ::osl::MutexGuard
, ::osl::GetGlobalMutex
>::create(
417 StaticInstance(), ::osl::GetGlobalMutex() );
420 struct StaticInstance
{
429 /** Helper base class for a late-initialized (default-constructed)
430 static variable, implementing the double-checked locking pattern correctly.
433 Derive from this class (common practice), e.g.
435 struct MyStatic : public rtl::Static<MyType, MyStatic> {};
437 MyType & rStatic = MyStatic::get();
444 Implementation trick to make the inner static holder unique,
445 using the outer class
446 (the one that derives from this base class)
448 #if defined LIBO_INTERNAL_ONLY
449 template<typename T
, typename Data
, typename Unique
>
450 class StaticWithArg
{
452 /** Gets the static. Mutual exclusion is implied by a functional
458 static T
& get(const Data
& rData
) {
459 static T
instance(rData
);
463 /** Gets the static. Mutual exclusion is implied by a functional
469 static T
& get(Data
& rData
) {
470 static T
instance(rData
);
475 template<typename T
, typename Data
, typename Unique
>
476 class StaticWithArg
{
478 /** Gets the static. Mutual exclusion is performed using the
484 static T
& get(const Data
& rData
) {
485 return *rtl_Instance
<
486 T
, StaticInstanceWithArg
,
487 ::osl::MutexGuard
, ::osl::GetGlobalMutex
,
488 Data
>::create( StaticInstanceWithArg(),
489 ::osl::GetGlobalMutex(),
493 /** Gets the static. Mutual exclusion is performed using the
499 static T
& get(Data
& rData
) {
500 return *rtl_Instance
<
501 T
, StaticInstanceWithArg
,
502 ::osl::MutexGuard
, ::osl::GetGlobalMutex
,
503 Data
>::create( StaticInstanceWithArg(),
504 ::osl::GetGlobalMutex(),
508 struct StaticInstanceWithArg
{
509 T
* operator () (const Data
& rData
) {
510 static T
instance(rData
);
514 T
* operator () (Data
& rData
) {
515 static T
instance(rData
);
522 /** Helper class for a late-initialized static aggregate, e.g. an array,
523 implementing the double-checked locking pattern correctly.
526 aggregate's element type
527 @tparam InitAggregate
528 initializer functor class
530 #if defined LIBO_INTERNAL_ONLY
531 template<typename T
, typename InitAggregate
>
532 class StaticAggregate
{
534 /** Gets the static aggregate, late-initializing.
535 Mutual exclusion is implied by a functional
542 static T
*instance
= InitAggregate()();
547 template<typename T
, typename InitAggregate
>
548 class StaticAggregate
{
550 /** Gets the static aggregate, late-initializing.
551 Mutual exclusion is performed using the osl global mutex.
559 ::osl::MutexGuard
, ::osl::GetGlobalMutex
>::create(
560 InitAggregate(), ::osl::GetGlobalMutex() );
564 /** Helper base class for a late-initialized static variable,
565 implementing the double-checked locking pattern correctly.
568 Derive from this class (common practice),
569 providing an initializer functor class, e.g.
571 struct MyStatic : public rtl::StaticWithInit<MyType, MyStatic> {
572 MyType operator () () {
574 return MyType( ... );
578 MyType & rStatic = MyStatic::get();
585 initializer functor class
587 Implementation trick to make the inner static holder unique,
588 using the outer class
589 (the one that derives from this base class).
590 Default is InitData (common practice).
592 Initializer functor's return type.
593 Default is T (common practice).
595 #if defined LIBO_INTERNAL_ONLY
596 template<typename T
, typename InitData
,
597 typename Unique
= InitData
, typename Data
= T
>
598 class StaticWithInit
{
600 /** Gets the static. Mutual exclusion is implied by a functional
607 static T instance
= InitData()();
612 template<typename T
, typename InitData
,
613 typename Unique
= InitData
, typename Data
= T
>
614 class StaticWithInit
{
616 /** Gets the static. Mutual exclusion is performed using the
623 return *rtl_Instance
<
624 T
, StaticInstanceWithInit
,
625 ::osl::MutexGuard
, ::osl::GetGlobalMutex
,
626 Data
, InitData
>::create( StaticInstanceWithInit(),
627 ::osl::GetGlobalMutex(),
631 struct StaticInstanceWithInit
{
632 T
* operator () ( Data d
) {
633 static T
instance(d
);
641 #endif // INCLUDED_RTL_INSTANCE_HXX
643 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */