1 /**************************************************************
2  *
3  * Licensed to the Apache Software Foundation (ASF) under one
4  * or more contributor license agreements.  See the NOTICE file
5  * distributed with this work for additional information
6  * regarding copyright ownership.  The ASF licenses this file
7  * to you under the Apache License, Version 2.0 (the
8  * "License"); you may not use this file except in compliance
9  * with the License.  You may obtain a copy of the License at
10  *
11  *   http://www.apache.org/licenses/LICENSE-2.0
12  *
13  * Unless required by applicable law or agreed to in writing,
14  * software distributed under the License is distributed on an
15  * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
16  * KIND, either express or implied.  See the License for the
17  * specific language governing permissions and limitations
18  * under the License.
19  *
20  *************************************************************/
21 
22 
23 
24 #ifndef _SALHELPER_SINGLETONREF_HXX_
25 #define _SALHELPER_SINGLETONREF_HXX_
26 
27 //_______________________________________________
28 // includes
29 
30 #include <osl/mutex.hxx>
31 #include "rtl/instance.hxx"
32 #include "osl/diagnose.h"
33 #include "osl/getglobalmutex.hxx"
34 
35 //_______________________________________________
36 // namespace
37 
38 namespace salhelper{
39 
40 //_______________________________________________
41 // definitions
42 
43 /** @short  template for implementing singleton classes.
44 
45     @descr  Such classes can be instanciated everytimes they
46             are needed. But the internal wrapped object will
47             be created one times only. Of course its used
48             resources are referenced one times only too.
49             This template hold it alive till the last
50             reference is gone. Further all operations
51             on this reference are threadsafe. Only
52             calls directly to the internal object (which modify
53             its state) must be made threadsafe by the object itself
54             or from outside.
55 
56     @attention  To prevent the code against race conditions, its not
57                 allowed to start operations inside the ctor
58                 of the internal wrapped object - especialy operations
59                 which needs a reference to the same singleton too.
60 
61                 The only chance to supress such strange constellations
62                 is a lazy-init mechanism.
63 
64                 <ul>
65                     <li>a) The singleton class can provide a special init()
66                            method, which must be called as first after creation.</li>
67                     <li>b) The singleton class can call a special impl_init()
68                            method implicit for every called interface method.</li>
69                 </ul>
70 
71                 Note further that this singleton pattern can work only, if
72                 all user of such singleton are located inside the same library!
73                 Because static values cant be exported - e.g. from windows libraries.
74  */
75 template< class SingletonClass >
76 class SingletonRef
77 {
78     //-------------------------------------------
79     // member
80 
81     private :
82 
83         /** @short  pointer to the internal wrapped singleton. */
84         static SingletonClass* m_pInstance;
85 
86         /** @short  ref count, which regulate creation and removing of m_pInstance. */
87         static sal_Int32 m_nRef;
88 
89     //-------------------------------------------
90     // interface
91 
92     public :
93 
94         //---------------------------------------
95 
96         /** @short  standard ctor.
97 
98             @descr  The internal wrapped object is created only,
99                     if its ref count was 0. Otherwhise this method
100                     does nothing ... except increasing of the internal
101                     ref count!
102          */
SingletonRef()103         SingletonRef()
104         {
105             // GLOBAL SAFE ->
106             ::osl::MutexGuard aLock(SingletonRef::ownStaticLock());
107 
108             // must be increased before(!) the check is done.
109             // Otherwhise this check can fail inside the same thread ...
110             ++m_nRef;
111             if (m_nRef == 1)
112                 m_pInstance = new SingletonClass();
113 
114             OSL_ENSURE(m_nRef>0 && m_pInstance, "Race? Ref count of singleton >0, but instance is NULL!");
115             // <- GLOBAL SAFE
116         }
117 
118         //---------------------------------------
119 
120         /** @short  standard dtor.
121 
122             @descr  The internal wrapped object is removed only,
123                     if its ref count wil be 0. Otherwhise this method
124                     does nothing ... except decreasing of the internal
125                     ref count!
126          */
~SingletonRef()127         ~SingletonRef()
128         {
129             // GLOBAL SAFE ->
130             ::osl::MutexGuard aLock(SingletonRef::ownStaticLock());
131 
132             // must be decreased before(!) the check is done.
133             // Otherwhise this check can fail inside the same thread ...
134             --m_nRef;
135             if (m_nRef == 0)
136             {
137                 delete m_pInstance;
138                 m_pInstance = 0;
139             }
140             // <- GLOBAL SAFE
141         }
142 
143         //---------------------------------------
144 
145         /** @short  Allows rSingle->someBodyOp().
146          */
operator ->() const147         SingletonClass* operator->() const
148         {
149             // GLOBAL SAFE ->
150             ::osl::MutexGuard aLock(SingletonRef::ownStaticLock());
151             return m_pInstance;
152             // <- GLOBAL SAFE
153         }
154 
155         //---------------------------------------
156 
157         /** @short  Allows (*rSingle).someBodyOp().
158          */
operator *() const159         SingletonClass& operator*() const
160         {
161             // GLOBAL SAFE ->
162             ::osl::MutexGuard aLock(SingletonRef::ownStaticLock());
163             return *m_pInstance;
164             // <- GLOBAL SAFE
165         }
166 
167     //-------------------------------------------
168     // helper
169 
170     private :
171 
172         //---------------------------------------
173 
174         /** @short  creates an own mutex for guarding static contents.
175 
176             @descr  The global mutex the osl library is used one times
177                     only to create an own static mutex, which can be used
178                     next time to guard own static member operations.
179          */
180         struct SingletonLockInit
181         {
operator ()salhelper::SingletonRef::SingletonLockInit182             ::osl::Mutex* operator()()
183             {
184                 static ::osl::Mutex aInstance;
185                 return &aInstance;
186             }
187         };
188 
ownStaticLock() const189         ::osl::Mutex& ownStaticLock() const
190         {
191             return *rtl_Instance< ::osl::Mutex,
192                                   SingletonLockInit,
193                                   ::osl::MutexGuard,
194                                   ::osl::GetGlobalMutex >::create(SingletonLockInit(), ::osl::GetGlobalMutex());
195         }
196 };
197 
198 template< class SingletonClass >
199 SingletonClass* SingletonRef< SingletonClass >::m_pInstance = 0;
200 
201 template< class SingletonClass >
202 sal_Int32 SingletonRef< SingletonClass >::m_nRef = 0;
203 
204 } // namespace salhelper
205 
206 #endif // _SALHELPER_SINGLETONREF_HXX_
207