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