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 #if ! HAVE_THREADSAFE_STATICS
29 #include <osl/getglobalmutex.hxx>
34 /** A non-broken version of the double-checked locking pattern.
37 <http://www.cs.umd.edu/~pugh/java/memoryModel/DoubleCheckedLocking.html>
38 for a description of double-checked locking, why it is broken, and how it
39 can be fixed. Always use this template instead of spelling out the
40 double-checked locking pattern explicitly, and only in those rare cases
41 where that is not possible and you have to spell it out explicitly, at
42 least call OSL_DOUBLE_CHECKED_LOCKING_MEMORY_BARRIER() at the right
43 places. That way, all platform-dependent code to make double-checked
44 locking work can be kept in one place.
48 1 Static instance (most common case)
54 static T * pInstance = 0;
57 ::osl::MutexGuard aGuard(::osl::Mutex::getGlobalMutex());
61 pInstance = &aInstance;
69 #include <rtl/instance.hxx>
70 #include <osl/getglobalmutex.hxx>
85 return rtl_Instance< T, Init, ::osl::MutexGuard,
86 ::osl::GetGlobalMutex >::create(
87 Init(), ::osl::GetGlobalMutex());
96 static T * pInstance = 0;
99 ::osl::MutexGuard aGuard(::osl::Mutex::getGlobalMutex());
108 #include <rtl/instance.hxx>
109 #include <osl/getglobalmutex.hxx>
123 return rtl_Instance< T, Init, ::osl::MutexGuard,
124 ::osl::GetGlobalMutex >::create(
125 Init(), ::osl::GetGlobalMutex());
134 static T * pInstance = 0;
137 SomeGuard aGuard(pSomeMutex);
141 pInstance = &aInstance;
149 #include <rtl/instance.hxx>
163 SomeMutex * operator()()
172 return rtl_Instance< T, InitInstance,
173 SomeGuard, InitGuard >::create(
174 InitInstance(), InitMutex());
177 4 Calculate extra data
183 static T * pInstance = 0;
187 ::osl::MutexGuard aGuard(::osl::Mutex::getGlobalMutex());
190 static T aInstance(aData);
191 pInstance = &aInstance;
199 #include <rtl/instance.hxx>
200 #include <osl/getglobalmutex.hxx>
214 Data const & operator()()
223 return rtl_Instance< T, InitInstance,
224 ::osl::Mutex, ::osl::GetGlobalMutex,
225 Data, InitData >::create(
226 InitInstance(), ::osl::GetGlobalMutex(), InitData());
231 For any instantiation of rtl_Instance, at most one call to a create method
232 may occur in the program code: Each occurrence of a create method within
233 the program code is supposed to return a fresh object instance on the
234 first call, and that same object instance on subsequent calls; but
235 independent occurrences of create methods are supposed to return
236 independent object instances. Since there is a one-to-one correspondence
237 between object instances and instantiations of rtl_Instance, the
238 requirement should be clear. One measure to enforce the requirement is
239 that rtl_Instance lives in an unnamed namespace, so that instantiations of
240 rtl_Instance in different translation units will definitely be different
241 instantiations. A drawback of that measure is that the name of the class
242 needs a funny "hand coded" prefix "rtl_" instead of a proper namespace
243 prefix like "::rtl::".
245 A known problem with this template is when two occurrences of calls to
246 create methods with identical template arguments appear in one translation
247 unit. Those two places will share a single object instance. This can be
248 avoided by using different Init structs (see the above code samples) in
251 There is no need to make m_pInstance volatile, in order to avoid usage of
252 stale copies of m_pInstance: At the first check, a thread will see that
253 m_pInstance contains either 0 or a valid pointer. If it contains a valid
254 pointer, it cannot be stale, and that pointer is used. If it contains 0,
255 acquiring the mutex will ensure that the second check sees a non-stale
258 On some compilers, the create methods would not be inlined if they
259 contained any static variables, so m_pInstance is made a class member
260 instead (and the create methods are inlined). But on MSC, the definition
261 of the class member m_pInstance would cause compilation to fail with an
262 internal compiler error. Since MSC is able to inline methods containing
263 static variables, m_pInstance is moved into the methods there. Note that
264 this only works well because for any instantiation of rtl_Instance at most
265 one call to a create method should be present, anyway.
267 template< typename Inst
, typename InstCtor
,
268 typename Guard
, typename GuardCtor
,
269 typename Data
= int, typename DataCtor
= int >
273 static inline Inst
* create(InstCtor aInstCtor
, GuardCtor aGuardCtor
)
276 static Inst
* m_pInstance
= 0;
278 Inst
* p
= m_pInstance
;
281 Guard
aGuard(aGuardCtor());
286 OSL_DOUBLE_CHECKED_LOCKING_MEMORY_BARRIER();
292 OSL_DOUBLE_CHECKED_LOCKING_MEMORY_BARRIER();
297 static inline Inst
* create(InstCtor aInstCtor
, GuardCtor aGuardCtor
,
301 static Inst
* m_pInstance
= 0;
303 Inst
* p
= m_pInstance
;
306 Data
aData(aDataCtor());
307 Guard
aGuard(aGuardCtor());
311 p
= aInstCtor(aData
);
312 OSL_DOUBLE_CHECKED_LOCKING_MEMORY_BARRIER();
318 OSL_DOUBLE_CHECKED_LOCKING_MEMORY_BARRIER();
323 static inline Inst
* create(InstCtor aInstCtor
, GuardCtor aGuardCtor
,
327 static Inst
* m_pInstance
= 0;
329 Inst
* p
= m_pInstance
;
332 Guard
aGuard(aGuardCtor());
336 p
= aInstCtor(rData
);
337 OSL_DOUBLE_CHECKED_LOCKING_MEMORY_BARRIER();
343 OSL_DOUBLE_CHECKED_LOCKING_MEMORY_BARRIER();
349 #if !defined _MSC_VER
350 static Inst
* m_pInstance
;
354 #if !defined _MSC_VER
355 template< typename Inst
, typename InstCtor
,
356 typename Guard
, typename GuardCtor
,
357 typename Data
, typename DataCtor
>
359 rtl_Instance
< Inst
, InstCtor
, Guard
, GuardCtor
, Data
, DataCtor
>::m_pInstance
367 /** Helper base class for a late-initialized (default-constructed)
368 static variable, implementing the double-checked locking pattern correctly.
371 Derive from this class (common practice), e.g.
373 struct MyStatic : public rtl::Static<MyType, MyStatic> {};
375 MyType & rStatic = MyStatic::get();
382 Implementation trick to make the inner static holder unique,
383 using the outer class
384 (the one that derives from this base class)
386 #if HAVE_THREADSAFE_STATICS
387 template<typename T
, typename Unique
>
390 /** Gets the static. Mutual exclusion is implied by a functional
402 template<typename T
, typename Unique
>
405 /** Gets the static. Mutual exclusion is performed using the
412 return *rtl_Instance
<
414 ::osl::MutexGuard
, ::osl::GetGlobalMutex
>::create(
415 StaticInstance(), ::osl::GetGlobalMutex() );
418 struct StaticInstance
{
427 /** Helper base class for a late-initialized (default-constructed)
428 static variable, implementing the double-checked locking pattern correctly.
431 Derive from this class (common practice), e.g.
433 struct MyStatic : public rtl::Static<MyType, MyStatic> {};
435 MyType & rStatic = MyStatic::get();
442 Implementation trick to make the inner static holder unique,
443 using the outer class
444 (the one that derives from this base class)
446 #if HAVE_THREADSAFE_STATICS
447 template<typename T
, typename Data
, typename Unique
>
448 class StaticWithArg
{
450 /** Gets the static. Mutual exclusion is implied by a functional
456 static T
& get(const Data
& rData
) {
457 static T
instance(rData
);
461 /** Gets the static. Mutual exclusion is implied by a functional
467 static T
& get(Data
& rData
) {
468 static T
instance(rData
);
473 template<typename T
, typename Data
, typename Unique
>
474 class StaticWithArg
{
476 /** Gets the static. Mutual exclusion is performed using the
482 static T
& get(const Data
& rData
) {
483 return *rtl_Instance
<
484 T
, StaticInstanceWithArg
,
485 ::osl::MutexGuard
, ::osl::GetGlobalMutex
,
486 Data
>::create( StaticInstanceWithArg(),
487 ::osl::GetGlobalMutex(),
491 /** Gets the static. Mutual exclusion is performed using the
497 static T
& get(Data
& rData
) {
498 return *rtl_Instance
<
499 T
, StaticInstanceWithArg
,
500 ::osl::MutexGuard
, ::osl::GetGlobalMutex
,
501 Data
>::create( StaticInstanceWithArg(),
502 ::osl::GetGlobalMutex(),
506 struct StaticInstanceWithArg
{
507 T
* operator () (const Data
& rData
) {
508 static T
instance(rData
);
512 T
* operator () (Data
& rData
) {
513 static T
instance(rData
);
520 /** Helper class for a late-initialized static aggregate, e.g. an array,
521 implementing the double-checked locking pattern correctly.
524 aggregate's element type
525 @tparam InitAggregate
526 initializer functor class
528 #if HAVE_THREADSAFE_STATICS
529 template<typename T
, typename InitAggregate
>
530 class StaticAggregate
{
532 /** Gets the static aggregate, late-initializing.
533 Mutual exclusion is implied by a functional
540 static T
*instance
= InitAggregate()();
545 template<typename T
, typename InitAggregate
>
546 class StaticAggregate
{
548 /** Gets the static aggregate, late-initializing.
549 Mutual exclusion is performed using the osl global mutex.
557 ::osl::MutexGuard
, ::osl::GetGlobalMutex
>::create(
558 InitAggregate(), ::osl::GetGlobalMutex() );
562 /** Helper base class for a late-initialized static variable,
563 implementing the double-checked locking pattern correctly.
566 Derive from this class (common practice),
567 providing an initializer functor class, e.g.
569 struct MyStatic : public rtl::StaticWithInit<MyType, MyStatic> {
570 MyType operator () () {
572 return MyType( ... );
576 MyType & rStatic = MyStatic::get();
583 initializer functor class
585 Implementation trick to make the inner static holder unique,
586 using the outer class
587 (the one that derives from this base class).
588 Default is InitData (common practice).
590 Initializer functor's return type.
591 Default is T (common practice).
593 #if HAVE_THREADSAFE_STATICS
594 template<typename T
, typename InitData
,
595 typename Unique
= InitData
, typename Data
= T
>
596 class StaticWithInit
{
598 /** Gets the static. Mutual exclusion is implied by a functional
605 static T instance
= InitData()();
610 template<typename T
, typename InitData
,
611 typename Unique
= InitData
, typename Data
= T
>
612 class StaticWithInit
{
614 /** Gets the static. Mutual exclusion is performed using the
621 return *rtl_Instance
<
622 T
, StaticInstanceWithInit
,
623 ::osl::MutexGuard
, ::osl::GetGlobalMutex
,
624 Data
, InitData
>::create( StaticInstanceWithInit(),
625 ::osl::GetGlobalMutex(),
629 struct StaticInstanceWithInit
{
630 T
* operator () ( Data d
) {
631 static T
instance(d
);
639 #endif // INCLUDED_RTL_INSTANCE_HXX
641 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */