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