LCOV - code coverage report
Current view: top level - include/rtl - instance.hxx (source / functions) Hit Total Coverage
Test: commit c8344322a7af75b84dd3ca8f78b05543a976dfd5 Lines: 36 36 100.0 %
Date: 2015-06-13 12:38:46 Functions: 1699 2471 68.8 %
Legend: Lines: hit not hit

          Line data    Source code
       1             : /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
       2             : /*
       3             :  * This file is part of the LibreOffice project.
       4             :  *
       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/.
       8             :  *
       9             :  * This file incorporates work covered by the following license notice:
      10             :  *
      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 .
      18             :  */
      19             : 
      20             : #ifndef INCLUDED_RTL_INSTANCE_HXX
      21             : #define INCLUDED_RTL_INSTANCE_HXX
      22             : 
      23             : #include <sal/config.h>
      24             : 
      25             : #include <osl/doublecheckedlocking.h>
      26             : #if ! HAVE_THREADSAFE_STATICS
      27             : #include <osl/getglobalmutex.hxx>
      28             : #endif
      29             : 
      30             : namespace {
      31             : 
      32             : /** A non-broken version of the double-checked locking pattern.
      33             : 
      34             :     See
      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.
      43             : 
      44             :     Usage scenarios:
      45             : 
      46             :     1  Static instance (most common case)
      47             : 
      48             :     Pattern:
      49             : 
      50             :       T * getInstance()
      51             :       {
      52             :           static T * pInstance = 0;
      53             :           if (!pInstance)
      54             :           {
      55             :               ::osl::MutexGuard aGuard(::osl::Mutex::getGlobalMutex());
      56             :               if (!pInstance)
      57             :               {
      58             :                   static T aInstance;
      59             :                   pInstance = &aInstance;
      60             :               }
      61             :           }
      62             :           return pInstance;
      63             :       }
      64             : 
      65             :     Code:
      66             : 
      67             :       #include <rtl/instance.hxx>
      68             :       #include <osl/getglobalmutex.hxx>
      69             : 
      70             :       namespace {
      71             :           struct Init
      72             :           {
      73             :               T * operator()()
      74             :               {
      75             :                   static T aInstance;
      76             :                   return &aInstance;
      77             :               }
      78             :           };
      79             :       }
      80             : 
      81             :       T * getInstance()
      82             :       {
      83             :           return rtl_Instance< T, Init, ::osl::MutexGuard,
      84             :                                ::osl::GetGlobalMutex >::create(
      85             :               Init(), ::osl::GetGlobalMutex());
      86             :       }
      87             : 
      88             :     2  Dynamic instance
      89             : 
      90             :     Pattern:
      91             : 
      92             :       T * getInstance()
      93             :       {
      94             :           static T * pInstance = 0;
      95             :           if (!pInstance)
      96             :           {
      97             :               ::osl::MutexGuard aGuard(::osl::Mutex::getGlobalMutex());
      98             :               if (!pInstance)
      99             :                   pInstance = new T;
     100             :           }
     101             :           return pInstance;
     102             :       }
     103             : 
     104             :     Code:
     105             : 
     106             :       #include <rtl/instance.hxx>
     107             :       #include <osl/getglobalmutex.hxx>
     108             : 
     109             :       namespace {
     110             :           struct Init
     111             :           {
     112             :               T * operator()()
     113             :               {
     114             :                   return new T;
     115             :               }
     116             :           };
     117             :       }
     118             : 
     119             :       T * getInstance()
     120             :       {
     121             :           return rtl_Instance< T, Init, ::osl::MutexGuard,
     122             :                                ::osl::GetGlobalMutex >::create(
     123             :               Init(), ::osl::GetGlobalMutex());
     124             :       }
     125             : 
     126             :     3  Other guard/mutex
     127             : 
     128             :     Pattern:
     129             : 
     130             :       T * getInstance()
     131             :       {
     132             :           static T * pInstance = 0;
     133             :           if (!pInstance)
     134             :           {
     135             :               SomeGuard aGuard(pSomeMutex);
     136             :               if (!pInstance)
     137             :               {
     138             :                   static T aInstance;
     139             :                   pInstance = &aInstance;
     140             :               }
     141             :           }
     142             :           return pInstance;
     143             :       }
     144             : 
     145             :     Code:
     146             : 
     147             :       #include <rtl/instance.hxx>
     148             : 
     149             :       namespace {
     150             :           struct InitInstance
     151             :           {
     152             :               T * operator()()
     153             :               {
     154             :                   static T aInstance;
     155             :                   return &aInstance;
     156             :               }
     157             :           };
     158             : 
     159             :           struct InitGuard
     160             :           {
     161             :               SomeMutex * operator()()
     162             :               {
     163             :                   return pSomeMutex;
     164             :               }
     165             :           };
     166             :       }
     167             : 
     168             :       T * getInstance()
     169             :       {
     170             :           return rtl_Instance< T, InitInstance,
     171             :                                SomeGuard, InitGuard >::create(
     172             :               InitInstance(), InitMutex());
     173             :       }
     174             : 
     175             :     4  Calculate extra data
     176             : 
     177             :     Pattern:
     178             : 
     179             :       T * getInstance()
     180             :       {
     181             :           static T * pInstance = 0;
     182             :           if (!pInstance)
     183             :           {
     184             :               Data aData(...);
     185             :               ::osl::MutexGuard aGuard(::osl::Mutex::getGlobalMutex());
     186             :               if (!pInstance)
     187             :               {
     188             :                   static T aInstance(aData);
     189             :                   pInstance = &aInstance;
     190             :               }
     191             :           }
     192             :           return pInstance;
     193             :       }
     194             : 
     195             :     Code:
     196             : 
     197             :       #include <rtl/instance.hxx>
     198             :       #include <osl/getglobalmutex.hxx>
     199             : 
     200             :       namespace {
     201             :           struct InitInstance
     202             :           {
     203             :               T * operator()()
     204             :               {
     205             :                   static T aInstance;
     206             :                   return &aInstance;
     207             :               }
     208             :           }
     209             : 
     210             :           struct InitData
     211             :           {
     212             :               Data const & operator()()
     213             :               {
     214             :                   return ...;
     215             :               }
     216             :           }
     217             :       }
     218             : 
     219             :       T * getInstance()
     220             :       {
     221             :           return rtl_Instance< T, InitInstance,
     222             :                                ::osl::Mutex, ::osl::GetGlobalMutex,
     223             :                                Data, InitData >::create(
     224             :               InitInstance(), ::osl::GetGlobalMutex(), InitData());
     225             :       }
     226             : 
     227             :     Some comments:
     228             : 
     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::".
     242             : 
     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
     247             :     the two places.
     248             : 
     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
     254             :     value in all cases.
     255             : 
     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.
     264             :  */
     265             : template< typename Inst, typename InstCtor,
     266             :           typename Guard, typename GuardCtor,
     267             :           typename Data = int, typename DataCtor = int >
     268             : class rtl_Instance
     269             : {
     270             : public:
     271     2089445 :     static inline Inst * create(InstCtor aInstCtor, GuardCtor aGuardCtor)
     272             :     {
     273             : #if defined _MSC_VER
     274             :         static Inst * m_pInstance = 0;
     275             : #endif // _MSC_VER
     276     2089445 :         Inst * p = m_pInstance;
     277     2089445 :         if (!p)
     278             :         {
     279         876 :             Guard aGuard(aGuardCtor());
     280         876 :             p = m_pInstance;
     281         876 :             if (!p)
     282             :             {
     283         876 :                 p = aInstCtor();
     284             :                 OSL_DOUBLE_CHECKED_LOCKING_MEMORY_BARRIER();
     285         876 :                 m_pInstance = p;
     286         876 :             }
     287             :         }
     288             :         else
     289             :         {
     290             :             OSL_DOUBLE_CHECKED_LOCKING_MEMORY_BARRIER();
     291             :         }
     292     2089445 :         return p;
     293             :     }
     294             : 
     295         154 :     static inline Inst * create(InstCtor aInstCtor, GuardCtor aGuardCtor,
     296             :                                 DataCtor aDataCtor)
     297             :     {
     298             : #if defined _MSC_VER
     299             :         static Inst * m_pInstance = 0;
     300             : #endif // _MSC_VER
     301         154 :         Inst * p = m_pInstance;
     302         154 :         if (!p)
     303             :         {
     304          77 :             Data aData(aDataCtor());
     305         154 :             Guard aGuard(aGuardCtor());
     306          77 :             p = m_pInstance;
     307          77 :             if (!p)
     308             :             {
     309          77 :                 p = aInstCtor(aData);
     310             :                 OSL_DOUBLE_CHECKED_LOCKING_MEMORY_BARRIER();
     311          77 :                 m_pInstance = p;
     312          77 :             }
     313             :         }
     314             :         else
     315             :         {
     316             :             OSL_DOUBLE_CHECKED_LOCKING_MEMORY_BARRIER();
     317             :         }
     318         154 :         return p;
     319             :     }
     320             : 
     321             :     static inline Inst * create(InstCtor aInstCtor, GuardCtor aGuardCtor,
     322             :                                 const Data &rData)
     323             :     {
     324             : #if defined _MSC_VER
     325             :         static Inst * m_pInstance = 0;
     326             : #endif // _MSC_VER
     327             :         Inst * p = m_pInstance;
     328             :         if (!p)
     329             :         {
     330             :             Guard aGuard(aGuardCtor());
     331             :             p = m_pInstance;
     332             :             if (!p)
     333             :             {
     334             :                 p = aInstCtor(rData);
     335             :                 OSL_DOUBLE_CHECKED_LOCKING_MEMORY_BARRIER();
     336             :                 m_pInstance = p;
     337             :             }
     338             :         }
     339             :         else
     340             :         {
     341             :             OSL_DOUBLE_CHECKED_LOCKING_MEMORY_BARRIER();
     342             :         }
     343             :         return p;
     344             :     }
     345             : 
     346             : private:
     347             : #if !defined _MSC_VER
     348             :     static Inst * m_pInstance;
     349             : #endif // _MSC_VER
     350             : };
     351             : 
     352             : #if !defined _MSC_VER
     353             : template< typename Inst, typename InstCtor,
     354             :           typename Guard, typename GuardCtor,
     355             :           typename Data, typename DataCtor >
     356             : Inst *
     357             : rtl_Instance< Inst, InstCtor, Guard, GuardCtor, Data, DataCtor >::m_pInstance
     358             : = 0;
     359             : #endif // _MSC_VER
     360             : 
     361             : }
     362             : 
     363             : namespace rtl {
     364             : 
     365             : /** Helper base class for a late-initialized (default-constructed)
     366             :     static variable, implementing the double-checked locking pattern correctly.
     367             : 
     368             :     @derive
     369             :     Derive from this class (common practice), e.g.
     370             :     <pre>
     371             :     struct MyStatic : public rtl::Static<MyType, MyStatic> {};
     372             :     ...
     373             :     MyType & rStatic = MyStatic::get();
     374             :     ...
     375             :     </pre>
     376             : 
     377             :     @tparam T
     378             :               variable's type
     379             :     @tparam Unique
     380             :               Implementation trick to make the inner static holder unique,
     381             :               using the outer class
     382             :               (the one that derives from this base class)
     383             : */
     384             : #if HAVE_THREADSAFE_STATICS
     385             : template<typename T, typename Unique>
     386             : class Static {
     387             : public:
     388             :     /** Gets the static.  Mutual exclusion is implied by a functional
     389             :         -fthreadsafe-statics
     390             : 
     391             :         @return
     392             :                 static variable
     393             :     */
     394 15817511691 :     static T & get() {
     395 15817511691 :         static T instance;
     396 15817511695 :         return instance;
     397             :     }
     398             : };
     399             : #else
     400             : template<typename T, typename Unique>
     401             : class Static {
     402             : public:
     403             :     /** Gets the static.  Mutual exclusion is performed using the
     404             :         osl global mutex.
     405             : 
     406             :         @return
     407             :                 static variable
     408             :     */
     409             :     static T & get() {
     410             :         return *rtl_Instance<
     411             :             T, StaticInstance,
     412             :             ::osl::MutexGuard, ::osl::GetGlobalMutex >::create(
     413             :                 StaticInstance(), ::osl::GetGlobalMutex() );
     414             :     }
     415             : private:
     416             :     struct StaticInstance {
     417             :         T * operator () () {
     418             :             static T instance;
     419             :             return &instance;
     420             :         }
     421             :     };
     422             : };
     423             : #endif
     424             : 
     425             : /** Helper base class for a late-initialized (default-constructed)
     426             :     static variable, implementing the double-checked locking pattern correctly.
     427             : 
     428             :     @derive
     429             :     Derive from this class (common practice), e.g.
     430             :     <pre>
     431             :     struct MyStatic : public rtl::Static<MyType, MyStatic> {};
     432             :     ...
     433             :     MyType & rStatic = MyStatic::get();
     434             :     ...
     435             :     </pre>
     436             : 
     437             :     @tparam T
     438             :               variable's type
     439             :     @tparam Unique
     440             :               Implementation trick to make the inner static holder unique,
     441             :               using the outer class
     442             :               (the one that derives from this base class)
     443             : */
     444             : #if HAVE_THREADSAFE_STATICS
     445             : template<typename T, typename Data, typename Unique>
     446             : class StaticWithArg {
     447             : public:
     448             :     /** Gets the static.  Mutual exclusion is implied by a functional
     449             :         -fthreadsafe-statics
     450             : 
     451             :         @return
     452             :                 static variable
     453             :     */
     454    27420580 :     static T & get(const Data& rData) {
     455    27420580 :         static T instance(rData);
     456    27420580 :         return instance;
     457             :     }
     458             : 
     459             :     /** Gets the static.  Mutual exclusion is implied by a functional
     460             :         -fthreadsafe-statics
     461             : 
     462             :         @return
     463             :                 static variable
     464             :     */
     465       25526 :     static T & get(Data& rData) {
     466       25526 :         static T instance(rData);
     467       25526 :         return instance;
     468             :     }
     469             : };
     470             : #else
     471             : template<typename T, typename Data, typename Unique>
     472             : class StaticWithArg {
     473             : public:
     474             :     /** Gets the static.  Mutual exclusion is performed using the
     475             :         osl global mutex.
     476             : 
     477             :         @return
     478             :                 static variable
     479             :     */
     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(),
     486             :                                       rData );
     487             :     }
     488             : 
     489             :     /** Gets the static.  Mutual exclusion is performed using the
     490             :         osl global mutex.
     491             : 
     492             :         @return
     493             :                 static variable
     494             :     */
     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(),
     501             :                                       rData );
     502             :     }
     503             : private:
     504             :     struct StaticInstanceWithArg {
     505             :         T * operator () (const Data& rData) {
     506             :             static T instance(rData);
     507             :             return &instance;
     508             :         }
     509             : 
     510             :         T * operator () (Data& rData) {
     511             :             static T instance(rData);
     512             :             return &instance;
     513             :          }
     514             :     };
     515             : };
     516             : #endif
     517             : 
     518             : /** Helper class for a late-initialized static aggregate, e.g. an array,
     519             :     implementing the double-checked locking pattern correctly.
     520             : 
     521             :     @tparam T
     522             :               aggregate's element type
     523             :     @tparam InitAggregate
     524             :               initializer functor class
     525             : */
     526             : #if HAVE_THREADSAFE_STATICS
     527             : template<typename T, typename InitAggregate>
     528             : class StaticAggregate {
     529             : public:
     530             :     /** Gets the static aggregate, late-initializing.
     531             :         Mutual exclusion is implied by a functional
     532             :         -fthreadsafe-statics
     533             : 
     534             :         @return
     535             :                 aggregate
     536             :     */
     537  1854968687 :     static T * get() {
     538  1854968687 :         static T *instance = InitAggregate()();
     539  1854968687 :         return instance;
     540             :     }
     541             : };
     542             : #else
     543             : template<typename T, typename InitAggregate>
     544             : class StaticAggregate {
     545             : public:
     546             :     /** Gets the static aggregate, late-initializing.
     547             :         Mutual exclusion is performed using the osl global mutex.
     548             : 
     549             :         @return
     550             :                 aggregate
     551             :     */
     552             :     static T * get() {
     553             :         return rtl_Instance<
     554             :             T, InitAggregate,
     555             :             ::osl::MutexGuard, ::osl::GetGlobalMutex >::create(
     556             :                 InitAggregate(), ::osl::GetGlobalMutex() );
     557             :     }
     558             : };
     559             : #endif
     560             : /** Helper base class for a late-initialized static variable,
     561             :     implementing the double-checked locking pattern correctly.
     562             : 
     563             :     @derive
     564             :     Derive from this class (common practice),
     565             :     providing an initializer functor class, e.g.
     566             :     <pre>
     567             :     struct MyStatic : public rtl::StaticWithInit<MyType, MyStatic> {
     568             :         MyType operator () () {
     569             :             ...
     570             :             return MyType( ... );
     571             :         }
     572             :     };
     573             :     ...
     574             :     MyType & rStatic = MyStatic::get();
     575             :     ...
     576             :     </pre>
     577             : 
     578             :     @tparam T
     579             :               variable's type
     580             :     @tparam InitData
     581             :               initializer functor class
     582             :     @tparam Unique
     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).
     587             :     @tparam Data
     588             :               Initializer functor's return type.
     589             :               Default is T (common practice).
     590             : */
     591             : #if HAVE_THREADSAFE_STATICS
     592             : template<typename T, typename InitData,
     593             :          typename Unique = InitData, typename Data = T>
     594             : class StaticWithInit {
     595             : public:
     596             :     /** Gets the static.  Mutual exclusion is implied by a functional
     597             :         -fthreadsafe-statics
     598             : 
     599             :         @return
     600             :                 static variable
     601             :     */
     602  1938743759 :     static T & get() {
     603  1938743759 :         static T instance = InitData()();
     604  1938743759 :         return instance;
     605             :     }
     606             : };
     607             : #else
     608             : template<typename T, typename InitData,
     609             :          typename Unique = InitData, typename Data = T>
     610             : class StaticWithInit {
     611             : public:
     612             :     /** Gets the static.  Mutual exclusion is performed using the
     613             :         osl global mutex.
     614             : 
     615             :         @return
     616             :                 static variable
     617             :     */
     618             :     static T & get() {
     619             :         return *rtl_Instance<
     620             :             T, StaticInstanceWithInit,
     621             :             ::osl::MutexGuard, ::osl::GetGlobalMutex,
     622             :             Data, InitData >::create( StaticInstanceWithInit(),
     623             :                                       ::osl::GetGlobalMutex(),
     624             :                                       InitData() );
     625             :     }
     626             : private:
     627             :     struct StaticInstanceWithInit {
     628             :         T * operator () ( Data d ) {
     629             :             static T instance(d);
     630             :             return &instance;
     631             :         }
     632             :     };
     633             : };
     634             : #endif
     635             : } // namespace rtl
     636             : 
     637             : #endif // INCLUDED_RTL_INSTANCE_HXX
     638             : 
     639             : /* vim:set shiftwidth=4 softtabstop=4 expandtab: */

Generated by: LCOV version 1.11