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"
27 #include "osl/doublecheckedlocking.h"
28 #include "osl/getglobalmutex.hxx"
32 /** A non-broken version of the double-checked locking pattern.
35 <http://www.cs.umd.edu/~pugh/java/memoryModel/DoubleCheckedLocking.html>
36 for a description of double-checked locking, why it is broken, and how it
37 can be fixed. Always use this template instead of spelling out the
38 double-checked locking pattern explicitly, and only in those rare cases
39 where that is not possible and you have to spell it out explicitly, at
40 least call OSL_DOUBLE_CHECKED_LOCKING_MEMORY_BARRIER() at the right
41 places. That way, all platform-dependent code to make double-checked
42 locking work can be kept in one place.
46 1 Static instance (most common case)
52 static T * pInstance = 0;
55 ::osl::MutexGuard aGuard(::osl::Mutex::getGlobalMutex());
59 pInstance = &aInstance;
67 #include <rtl/instance.hxx>
68 #include <osl/getglobalmutex.hxx>
83 return rtl_Instance< T, Init, ::osl::MutexGuard,
84 ::osl::GetGlobalMutex >::create(
85 Init(), ::osl::GetGlobalMutex());
94 static T * pInstance = 0;
97 ::osl::MutexGuard aGuard(::osl::Mutex::getGlobalMutex());
106 #include <rtl/instance.hxx>
107 #include <osl/getglobalmutex.hxx>
121 return rtl_Instance< T, Init, ::osl::MutexGuard,
122 ::osl::GetGlobalMutex >::create(
123 Init(), ::osl::GetGlobalMutex());
132 static T * pInstance = 0;
135 SomeGuard aGuard(pSomeMutex);
139 pInstance = &aInstance;
147 #include <rtl/instance.hxx>
161 SomeMutex * operator()()
170 return rtl_Instance< T, InitInstance,
171 SomeGuard, InitGuard >::create(
172 InitInstance(), InitMutex());
175 4 Calculate extra data
181 static T * pInstance = 0;
185 ::osl::MutexGuard aGuard(::osl::Mutex::getGlobalMutex());
188 static T aInstance(aData);
189 pInstance = &aInstance;
197 #include <rtl/instance.hxx>
198 #include <osl/getglobalmutex.hxx>
212 Data const & operator()()
221 return rtl_Instance< T, InitInstance,
222 ::osl::MutexGuard, ::osl::GetGlobalMutex,
223 Data, InitData >::create(
224 InitInstance(), ::osl::GetGlobalMutex(), InitData());
229 For any instantiation of rtl_Instance, at most one call to a create method
230 may occur in the program code: Each occurrence of a create method within
231 the program code is supposed to return a fresh object instance on the
232 first call, and that same object instance on subsequent calls; but
233 independent occurrences of create methods are supposed to return
234 independent object instances. Since there is a one-to-one correspondence
235 between object instances and instantiations of rtl_Instance, the
236 requirement should be clear. One measure to enforce the requirement is
237 that rtl_Instance lives in an unnamed namespace, so that instantiations of
238 rtl_Instance in different translation units will definitely be different
239 instantiations. A drawback of that measure is that the name of the class
240 needs a funny "hand coded" prefix "rtl_" instead of a proper namespace
241 prefix like "::rtl::".
243 A known problem with this template is when two occurrences of calls to
244 create methods with identical template arguments appear in one translation
245 unit. Those two places will share a single object instance. This can be
246 avoided by using different Init structs (see the above code samples) in
249 There is no need to make m_pInstance volatile, in order to avoid usage of
250 stale copies of m_pInstance: At the first check, a thread will see that
251 m_pInstance contains either 0 or a valid pointer. If it contains a valid
252 pointer, it cannot be stale, and that pointer is used. If it contains 0,
253 acquiring the mutex will ensure that the second check sees a non-stale
256 On some compilers, the create methods would not be inlined if they
257 contained any static variables, so m_pInstance is made a class member
258 instead (and the create methods are inlined). But on MSC, the definition
259 of the class member m_pInstance would cause compilation to fail with an
260 internal compiler error. Since MSC is able to inline methods containing
261 static variables, m_pInstance is moved into the methods there. Note that
262 this only works well because for any instantiation of rtl_Instance at most
263 one call to a create method should be present, anyway.
265 template< typename Inst
, typename InstCtor
,
266 typename Guard
, typename GuardCtor
,
267 typename Data
= int, typename DataCtor
= int >
271 static Inst
* create(InstCtor aInstCtor
, GuardCtor aGuardCtor
)
274 static Inst
* m_pInstance
= 0;
276 Inst
* p
= m_pInstance
;
279 Guard
aGuard(aGuardCtor());
284 OSL_DOUBLE_CHECKED_LOCKING_MEMORY_BARRIER();
290 OSL_DOUBLE_CHECKED_LOCKING_MEMORY_BARRIER();
295 static Inst
* create(InstCtor aInstCtor
, GuardCtor aGuardCtor
,
299 static Inst
* m_pInstance
= 0;
301 Inst
* p
= m_pInstance
;
304 Data
aData(aDataCtor());
305 Guard
aGuard(aGuardCtor());
309 p
= aInstCtor(aData
);
310 OSL_DOUBLE_CHECKED_LOCKING_MEMORY_BARRIER();
316 OSL_DOUBLE_CHECKED_LOCKING_MEMORY_BARRIER();
321 static Inst
* create(InstCtor aInstCtor
, GuardCtor aGuardCtor
,
325 static Inst
* m_pInstance
= 0;
327 Inst
* p
= m_pInstance
;
330 Guard
aGuard(aGuardCtor());
334 p
= aInstCtor(rData
);
335 OSL_DOUBLE_CHECKED_LOCKING_MEMORY_BARRIER();
341 OSL_DOUBLE_CHECKED_LOCKING_MEMORY_BARRIER();
347 #if !defined _MSC_VER
348 static Inst
* m_pInstance
;
352 #if !defined _MSC_VER
353 template< typename Inst
, typename InstCtor
,
354 typename Guard
, typename GuardCtor
,
355 typename Data
, typename DataCtor
>
357 rtl_Instance
< Inst
, InstCtor
, Guard
, GuardCtor
, Data
, DataCtor
>::m_pInstance
365 /** Helper base class for a late-initialized (default-constructed)
366 static variable, implementing the double-checked locking pattern correctly.
369 Derive from this class (common practice), e.g.
371 struct MyStatic : public rtl::Static<MyType, MyStatic> {};
373 MyType & rStatic = MyStatic::get();
380 Implementation trick to make the inner static holder unique,
381 using the outer class
382 (the one that derives from this base class)
384 #if defined LIBO_INTERNAL_ONLY
385 template<typename T
, typename Unique
>
388 /** Gets the static. Mutual exclusion is implied by a functional
400 template<typename T
, typename Unique
>
403 /** Gets the static. Mutual exclusion is performed using the
410 return *rtl_Instance
<
412 ::osl::MutexGuard
, ::osl::GetGlobalMutex
>::create(
413 StaticInstance(), ::osl::GetGlobalMutex() );
416 struct StaticInstance
{
425 /** Helper base class for a late-initialized (default-constructed)
426 static variable, implementing the double-checked locking pattern correctly.
429 Derive from this class (common practice), e.g.
431 struct MyStatic : public rtl::Static<MyType, MyStatic> {};
433 MyType & rStatic = MyStatic::get();
440 Implementation trick to make the inner static holder unique,
441 using the outer class
442 (the one that derives from this base class)
444 #if defined LIBO_INTERNAL_ONLY
445 template<typename T
, typename Data
, typename Unique
>
446 class StaticWithArg
{
448 /** Gets the static. Mutual exclusion is implied by a functional
454 static T
& get(const Data
& rData
) {
455 static T
instance(rData
);
459 /** Gets the static. Mutual exclusion is implied by a functional
465 static T
& get(Data
& rData
) {
466 static T
instance(rData
);
471 template<typename T
, typename Data
, typename Unique
>
472 class StaticWithArg
{
474 /** Gets the static. Mutual exclusion is performed using the
480 static T
& get(const Data
& rData
) {
481 return *rtl_Instance
<
482 T
, StaticInstanceWithArg
,
483 ::osl::MutexGuard
, ::osl::GetGlobalMutex
,
484 Data
>::create( StaticInstanceWithArg(),
485 ::osl::GetGlobalMutex(),
489 /** Gets the static. Mutual exclusion is performed using the
495 static T
& get(Data
& rData
) {
496 return *rtl_Instance
<
497 T
, StaticInstanceWithArg
,
498 ::osl::MutexGuard
, ::osl::GetGlobalMutex
,
499 Data
>::create( StaticInstanceWithArg(),
500 ::osl::GetGlobalMutex(),
504 struct StaticInstanceWithArg
{
505 T
* operator () (const Data
& rData
) {
506 static T
instance(rData
);
510 T
* operator () (Data
& rData
) {
511 static T
instance(rData
);
518 /** Helper class for a late-initialized static aggregate, e.g. an array,
519 implementing the double-checked locking pattern correctly.
522 aggregate's element type
523 @tparam InitAggregate
524 initializer functor class
526 #if defined LIBO_INTERNAL_ONLY
527 template<typename T
, typename InitAggregate
>
528 class StaticAggregate
{
530 /** Gets the static aggregate, late-initializing.
531 Mutual exclusion is implied by a functional
538 static T
*instance
= InitAggregate()();
543 template<typename T
, typename InitAggregate
>
544 class StaticAggregate
{
546 /** Gets the static aggregate, late-initializing.
547 Mutual exclusion is performed using the osl global mutex.
555 ::osl::MutexGuard
, ::osl::GetGlobalMutex
>::create(
556 InitAggregate(), ::osl::GetGlobalMutex() );
560 /** Helper base class for a late-initialized static variable,
561 implementing the double-checked locking pattern correctly.
564 Derive from this class (common practice),
565 providing an initializer functor class, e.g.
567 struct MyStatic : public rtl::StaticWithInit<MyType, MyStatic> {
568 MyType operator () () {
570 return MyType( ... );
574 MyType & rStatic = MyStatic::get();
581 initializer functor class
583 Implementation trick to make the inner static holder unique,
584 using the outer class
585 (the one that derives from this base class).
586 Default is InitData (common practice).
588 Initializer functor's return type.
589 Default is T (common practice).
591 #if defined LIBO_INTERNAL_ONLY
592 template<typename T
, typename InitData
,
593 typename Unique
= InitData
, typename Data
= T
>
594 class StaticWithInit
{
596 /** Gets the static. Mutual exclusion is implied by a functional
603 static T instance
= InitData()();
608 template<typename T
, typename InitData
,
609 typename Unique
= InitData
, typename Data
= T
>
610 class StaticWithInit
{
612 /** Gets the static. Mutual exclusion is performed using the
619 return *rtl_Instance
<
620 T
, StaticInstanceWithInit
,
621 ::osl::MutexGuard
, ::osl::GetGlobalMutex
,
622 Data
, InitData
>::create( StaticInstanceWithInit(),
623 ::osl::GetGlobalMutex(),
627 struct StaticInstanceWithInit
{
628 T
* operator () ( Data d
) {
629 static T
instance(d
);
637 #endif // INCLUDED_RTL_INSTANCE_HXX
639 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */