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

Generated by: LCOV version 1.10