1*b1cdbd2cSJim Jagielski /**************************************************************
2*b1cdbd2cSJim Jagielski  *
3*b1cdbd2cSJim Jagielski  * Licensed to the Apache Software Foundation (ASF) under one
4*b1cdbd2cSJim Jagielski  * or more contributor license agreements.  See the NOTICE file
5*b1cdbd2cSJim Jagielski  * distributed with this work for additional information
6*b1cdbd2cSJim Jagielski  * regarding copyright ownership.  The ASF licenses this file
7*b1cdbd2cSJim Jagielski  * to you under the Apache License, Version 2.0 (the
8*b1cdbd2cSJim Jagielski  * "License"); you may not use this file except in compliance
9*b1cdbd2cSJim Jagielski  * with the License.  You may obtain a copy of the License at
10*b1cdbd2cSJim Jagielski  *
11*b1cdbd2cSJim Jagielski  *   http://www.apache.org/licenses/LICENSE-2.0
12*b1cdbd2cSJim Jagielski  *
13*b1cdbd2cSJim Jagielski  * Unless required by applicable law or agreed to in writing,
14*b1cdbd2cSJim Jagielski  * software distributed under the License is distributed on an
15*b1cdbd2cSJim Jagielski  * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
16*b1cdbd2cSJim Jagielski  * KIND, either express or implied.  See the License for the
17*b1cdbd2cSJim Jagielski  * specific language governing permissions and limitations
18*b1cdbd2cSJim Jagielski  * under the License.
19*b1cdbd2cSJim Jagielski  *
20*b1cdbd2cSJim Jagielski  *************************************************************/
21*b1cdbd2cSJim Jagielski 
22*b1cdbd2cSJim Jagielski 
23*b1cdbd2cSJim Jagielski 
24*b1cdbd2cSJim Jagielski #ifndef __FRAMEWORK_THREADHELP_FAIRRWLOCK_HXX_
25*b1cdbd2cSJim Jagielski #define __FRAMEWORK_THREADHELP_FAIRRWLOCK_HXX_
26*b1cdbd2cSJim Jagielski 
27*b1cdbd2cSJim Jagielski //_________________________________________________________________________________________________________________
28*b1cdbd2cSJim Jagielski //	my own includes
29*b1cdbd2cSJim Jagielski //_________________________________________________________________________________________________________________
30*b1cdbd2cSJim Jagielski 
31*b1cdbd2cSJim Jagielski #include <threadhelp/inoncopyable.h>
32*b1cdbd2cSJim Jagielski #include <threadhelp/irwlock.h>
33*b1cdbd2cSJim Jagielski #include <macros/debug.hxx>
34*b1cdbd2cSJim Jagielski 
35*b1cdbd2cSJim Jagielski //_________________________________________________________________________________________________________________
36*b1cdbd2cSJim Jagielski //	interface includes
37*b1cdbd2cSJim Jagielski //_________________________________________________________________________________________________________________
38*b1cdbd2cSJim Jagielski #include <com/sun/star/uno/XInterface.hpp>
39*b1cdbd2cSJim Jagielski 
40*b1cdbd2cSJim Jagielski //_________________________________________________________________________________________________________________
41*b1cdbd2cSJim Jagielski //	other includes
42*b1cdbd2cSJim Jagielski //_________________________________________________________________________________________________________________
43*b1cdbd2cSJim Jagielski #include <osl/mutex.hxx>
44*b1cdbd2cSJim Jagielski #include <osl/conditn.hxx>
45*b1cdbd2cSJim Jagielski 
46*b1cdbd2cSJim Jagielski //_________________________________________________________________________________________________________________
47*b1cdbd2cSJim Jagielski //	namespace
48*b1cdbd2cSJim Jagielski //_________________________________________________________________________________________________________________
49*b1cdbd2cSJim Jagielski 
50*b1cdbd2cSJim Jagielski namespace framework{
51*b1cdbd2cSJim Jagielski 
52*b1cdbd2cSJim Jagielski //_________________________________________________________________________________________________________________
53*b1cdbd2cSJim Jagielski //	const
54*b1cdbd2cSJim Jagielski //_________________________________________________________________________________________________________________
55*b1cdbd2cSJim Jagielski 
56*b1cdbd2cSJim Jagielski //_________________________________________________________________________________________________________________
57*b1cdbd2cSJim Jagielski //	declarations
58*b1cdbd2cSJim Jagielski //_________________________________________________________________________________________________________________
59*b1cdbd2cSJim Jagielski 
60*b1cdbd2cSJim Jagielski /*-************************************************************************************************************//**
61*b1cdbd2cSJim Jagielski 	@short          implement a read/write lock with fairness between read/write accessors
62*b1cdbd2cSJim Jagielski 	@descr			These implementation never should used as base class! Use it as a member every time.
63*b1cdbd2cSJim Jagielski 					Use ReadGuard and/or WriteGuard in your methods (which work with these lock)
64*b1cdbd2cSJim Jagielski 					to make your code threadsafe.
65*b1cdbd2cSJim Jagielski 					Fair means: All reading or writing threads are synchronized AND serialzed by using one
66*b1cdbd2cSJim Jagielski 					mutex. For reader this mutex is used to access internal variables of this lock only;
67*b1cdbd2cSJim Jagielski 					for writer this mutex is used to have an exclusiv access on your class member!
68*b1cdbd2cSJim Jagielski 					=> It's a multi-reader/single-writer lock, which no preferred accessor.
69*b1cdbd2cSJim Jagielski 
70*b1cdbd2cSJim Jagielski 	@implements		IRWlock
71*b1cdbd2cSJim Jagielski     @base           INonCopyable
72*b1cdbd2cSJim Jagielski 					IRWLock
73*b1cdbd2cSJim Jagielski 
74*b1cdbd2cSJim Jagielski 	@devstatus		ready to use
75*b1cdbd2cSJim Jagielski *//*-*************************************************************************************************************/
76*b1cdbd2cSJim Jagielski class FairRWLock : public  IRWLock
77*b1cdbd2cSJim Jagielski                  , private INonCopyable
78*b1cdbd2cSJim Jagielski {
79*b1cdbd2cSJim Jagielski 	//-------------------------------------------------------------------------------------------------------------
80*b1cdbd2cSJim Jagielski 	//	public methods
81*b1cdbd2cSJim Jagielski 	//-------------------------------------------------------------------------------------------------------------
82*b1cdbd2cSJim Jagielski 	public:
83*b1cdbd2cSJim Jagielski 
84*b1cdbd2cSJim Jagielski         /*-****************************************************************************************************//**
85*b1cdbd2cSJim Jagielski             @short      standard ctor
86*b1cdbd2cSJim Jagielski             @descr      Initialize instance with right start values for correct working.
87*b1cdbd2cSJim Jagielski                         no reader could exist               =>  m_nReadCount   = 0
88*b1cdbd2cSJim Jagielski                         don't block first comming writer    =>  m_aWriteCondition.set()
89*b1cdbd2cSJim Jagielski 
90*b1cdbd2cSJim Jagielski             @seealso    -
91*b1cdbd2cSJim Jagielski 
92*b1cdbd2cSJim Jagielski             @param      -
93*b1cdbd2cSJim Jagielski             @return     -
94*b1cdbd2cSJim Jagielski 
95*b1cdbd2cSJim Jagielski             @onerror    -
96*b1cdbd2cSJim Jagielski         *//*-*****************************************************************************************************/
FairRWLock()97*b1cdbd2cSJim Jagielski         inline FairRWLock()
98*b1cdbd2cSJim Jagielski             : m_nReadCount( 0 )
99*b1cdbd2cSJim Jagielski         {
100*b1cdbd2cSJim Jagielski             m_aWriteCondition.set();
101*b1cdbd2cSJim Jagielski         }
102*b1cdbd2cSJim Jagielski 
~FairRWLock()103*b1cdbd2cSJim Jagielski         inline virtual ~FairRWLock()
104*b1cdbd2cSJim Jagielski         {
105*b1cdbd2cSJim Jagielski         }
106*b1cdbd2cSJim Jagielski 
107*b1cdbd2cSJim Jagielski         /*-****************************************************************************************************//**
108*b1cdbd2cSJim Jagielski             @interface  IRWLock
109*b1cdbd2cSJim Jagielski             @short      set lock for reading
110*b1cdbd2cSJim Jagielski             @descr      A guard should call this method to acquire read access on your member.
111*b1cdbd2cSJim Jagielski                         Writing isn't allowed then - but nobody could check it for you!
112*b1cdbd2cSJim Jagielski 
113*b1cdbd2cSJim Jagielski             @seealso    method releaseReadAccess()
114*b1cdbd2cSJim Jagielski 
115*b1cdbd2cSJim Jagielski             @param      -
116*b1cdbd2cSJim Jagielski             @return     -
117*b1cdbd2cSJim Jagielski 
118*b1cdbd2cSJim Jagielski             @onerror    -
119*b1cdbd2cSJim Jagielski         *//*-*****************************************************************************************************/
acquireReadAccess()120*b1cdbd2cSJim Jagielski         inline virtual void acquireReadAccess()
121*b1cdbd2cSJim Jagielski         {
122*b1cdbd2cSJim Jagielski             // Put call in "SERIALIZE"-queue!
123*b1cdbd2cSJim Jagielski             // After successful acquiring this mutex we are alone ...
124*b1cdbd2cSJim Jagielski             ::osl::MutexGuard aSerializeGuard( m_aSerializer );
125*b1cdbd2cSJim Jagielski 
126*b1cdbd2cSJim Jagielski             // ... but we should synchronize us with other reader!
127*b1cdbd2cSJim Jagielski             // May be - they will unregister himself by using releaseReadAccess()!
128*b1cdbd2cSJim Jagielski             ::osl::MutexGuard aAccessGuard( m_aAccessLock );
129*b1cdbd2cSJim Jagielski 
130*b1cdbd2cSJim Jagielski             // Now we must register us as reader by increasing counter.
131*b1cdbd2cSJim Jagielski             // If this the first writer we must close door for possible writer.
132*b1cdbd2cSJim Jagielski             // Other reader don't look for this barrier - they work parallel to us!
133*b1cdbd2cSJim Jagielski             if( m_nReadCount == 0 )
134*b1cdbd2cSJim Jagielski             {
135*b1cdbd2cSJim Jagielski                 m_aWriteCondition.reset();
136*b1cdbd2cSJim Jagielski             }
137*b1cdbd2cSJim Jagielski             ++m_nReadCount;
138*b1cdbd2cSJim Jagielski         }
139*b1cdbd2cSJim Jagielski 
140*b1cdbd2cSJim Jagielski         /*-****************************************************************************************************//**
141*b1cdbd2cSJim Jagielski             @interface  IRWLock
142*b1cdbd2cSJim Jagielski             @short      reset lock for reading
143*b1cdbd2cSJim Jagielski             @descr      A guard should call this method to release read access on your member.
144*b1cdbd2cSJim Jagielski 
145*b1cdbd2cSJim Jagielski             @seealso    method acquireReadAccess()
146*b1cdbd2cSJim Jagielski 
147*b1cdbd2cSJim Jagielski             @param      -
148*b1cdbd2cSJim Jagielski             @return     -
149*b1cdbd2cSJim Jagielski 
150*b1cdbd2cSJim Jagielski             @onerror    -
151*b1cdbd2cSJim Jagielski         *//*-*****************************************************************************************************/
releaseReadAccess()152*b1cdbd2cSJim Jagielski         inline virtual void releaseReadAccess()
153*b1cdbd2cSJim Jagielski         {
154*b1cdbd2cSJim Jagielski             // The access lock is enough at this point
155*b1cdbd2cSJim Jagielski             // because it's not allowed to wait for all reader or writer here!
156*b1cdbd2cSJim Jagielski             // That will cause a deadlock!
157*b1cdbd2cSJim Jagielski             ::osl::MutexGuard aAccessGuard( m_aAccessLock );
158*b1cdbd2cSJim Jagielski 
159*b1cdbd2cSJim Jagielski             // Unregister as reader first!
160*b1cdbd2cSJim Jagielski             // Open writer barrier then if it was the last reader.
161*b1cdbd2cSJim Jagielski             --m_nReadCount;
162*b1cdbd2cSJim Jagielski             if( m_nReadCount == 0 )
163*b1cdbd2cSJim Jagielski             {
164*b1cdbd2cSJim Jagielski                 m_aWriteCondition.set();
165*b1cdbd2cSJim Jagielski             }
166*b1cdbd2cSJim Jagielski         }
167*b1cdbd2cSJim Jagielski 
168*b1cdbd2cSJim Jagielski         /*-****************************************************************************************************//**
169*b1cdbd2cSJim Jagielski             @interface  IRWLock
170*b1cdbd2cSJim Jagielski             @short      set lock for writing
171*b1cdbd2cSJim Jagielski             @descr      A guard should call this method to acquire write access on your member.
172*b1cdbd2cSJim Jagielski                         Reading is allowed too - of course.
173*b1cdbd2cSJim Jagielski                         After successfully calling of this method you are the only writer.
174*b1cdbd2cSJim Jagielski 
175*b1cdbd2cSJim Jagielski             @seealso    method releaseWriteAccess()
176*b1cdbd2cSJim Jagielski 
177*b1cdbd2cSJim Jagielski             @param      -
178*b1cdbd2cSJim Jagielski             @return     -
179*b1cdbd2cSJim Jagielski 
180*b1cdbd2cSJim Jagielski             @onerror    -
181*b1cdbd2cSJim Jagielski         *//*-*****************************************************************************************************/
acquireWriteAccess()182*b1cdbd2cSJim Jagielski         inline virtual void acquireWriteAccess()
183*b1cdbd2cSJim Jagielski         {
184*b1cdbd2cSJim Jagielski             // You have to stand in our serialize-queue till all reader
185*b1cdbd2cSJim Jagielski             // are registered (not for releasing them!) or writer finished their work!
186*b1cdbd2cSJim Jagielski             // Don't use a guard to do so - because you must hold the mutex till
187*b1cdbd2cSJim Jagielski             // you call releaseWriteAccess()!
188*b1cdbd2cSJim Jagielski             // After succesfull acquire you have to wait for current working reader.
189*b1cdbd2cSJim Jagielski             // Used condition will open by last gone reader object.
190*b1cdbd2cSJim Jagielski             m_aSerializer.acquire();
191*b1cdbd2cSJim Jagielski             m_aWriteCondition.wait();
192*b1cdbd2cSJim Jagielski 
193*b1cdbd2cSJim Jagielski             #ifdef ENABLE_MUTEXDEBUG
194*b1cdbd2cSJim Jagielski             // A writer is an exclusiv accessor!
195*b1cdbd2cSJim Jagielski             LOG_ASSERT2( m_nReadCount!=0, "FairRWLock::acquireWriteAccess()", "No threadsafe code detected ... : Read count != 0!" )
196*b1cdbd2cSJim Jagielski             #endif
197*b1cdbd2cSJim Jagielski         }
198*b1cdbd2cSJim Jagielski 
199*b1cdbd2cSJim Jagielski         /*-****************************************************************************************************//**
200*b1cdbd2cSJim Jagielski             @interface  IRWLock
201*b1cdbd2cSJim Jagielski             @short      reset lock for writing
202*b1cdbd2cSJim Jagielski             @descr      A guard should call this method to release write access on your member.
203*b1cdbd2cSJim Jagielski 
204*b1cdbd2cSJim Jagielski             @seealso    method acquireWriteAccess()
205*b1cdbd2cSJim Jagielski 
206*b1cdbd2cSJim Jagielski             @param      -
207*b1cdbd2cSJim Jagielski             @return     -
208*b1cdbd2cSJim Jagielski 
209*b1cdbd2cSJim Jagielski             @onerror    -
210*b1cdbd2cSJim Jagielski         *//*-*****************************************************************************************************/
releaseWriteAccess()211*b1cdbd2cSJim Jagielski         inline virtual void releaseWriteAccess()
212*b1cdbd2cSJim Jagielski         {
213*b1cdbd2cSJim Jagielski             // The only one you have to do here is to release
214*b1cdbd2cSJim Jagielski             // hold seriliaze-mutex. All other user of these instance are blocked
215*b1cdbd2cSJim Jagielski             // by these mutex!
216*b1cdbd2cSJim Jagielski             // You don't need any other mutex here - you are the only one in the moment!
217*b1cdbd2cSJim Jagielski 
218*b1cdbd2cSJim Jagielski             #ifdef ENABLE_MUTEXDEBUG
219*b1cdbd2cSJim Jagielski             // A writer is an exclusiv accessor!
220*b1cdbd2cSJim Jagielski             LOG_ASSERT2( m_nReadCount!=0, "FairRWLock::releaseWriteAccess()", "No threadsafe code detected ... : Read count != 0!" )
221*b1cdbd2cSJim Jagielski             #endif
222*b1cdbd2cSJim Jagielski 
223*b1cdbd2cSJim Jagielski             m_aSerializer.release();
224*b1cdbd2cSJim Jagielski         }
225*b1cdbd2cSJim Jagielski 
226*b1cdbd2cSJim Jagielski         /*-****************************************************************************************************//**
227*b1cdbd2cSJim Jagielski             @interface  IRWLock
228*b1cdbd2cSJim Jagielski             @short      downgrade a write access to a read access
229*b1cdbd2cSJim Jagielski             @descr      A guard should call this method to change a write to a read access.
230*b1cdbd2cSJim Jagielski                         New readers can work too - new writer are blocked!
231*b1cdbd2cSJim Jagielski 
232*b1cdbd2cSJim Jagielski             @attention  Don't call this method if you are not a writer!
233*b1cdbd2cSJim Jagielski                         Results are not defined then ...
234*b1cdbd2cSJim Jagielski                         An upgrade can't be implemented realy ... because acquiring new access
235*b1cdbd2cSJim Jagielski                         will be the same - there no differences!
236*b1cdbd2cSJim Jagielski 
237*b1cdbd2cSJim Jagielski             @seealso    -
238*b1cdbd2cSJim Jagielski 
239*b1cdbd2cSJim Jagielski             @param      -
240*b1cdbd2cSJim Jagielski             @return     -
241*b1cdbd2cSJim Jagielski 
242*b1cdbd2cSJim Jagielski             @onerror    -
243*b1cdbd2cSJim Jagielski         *//*-*****************************************************************************************************/
downgradeWriteAccess()244*b1cdbd2cSJim Jagielski         inline virtual void downgradeWriteAccess()
245*b1cdbd2cSJim Jagielski         {
246*b1cdbd2cSJim Jagielski             // You must be a writer to call this method!
247*b1cdbd2cSJim Jagielski             // We can't check it - but otherwise it's your problem ...
248*b1cdbd2cSJim Jagielski             // Thats why you don't need any mutex here.
249*b1cdbd2cSJim Jagielski 
250*b1cdbd2cSJim Jagielski             #ifdef ENABLE_MUTEXDEBUG
251*b1cdbd2cSJim Jagielski             // A writer is an exclusiv accessor!
252*b1cdbd2cSJim Jagielski             LOG_ASSERT2( m_nReadCount!=0, "FairRWLock::downgradeWriteAccess()", "No threadsafe code detected ... : Read count != 0!" )
253*b1cdbd2cSJim Jagielski             #endif
254*b1cdbd2cSJim Jagielski 
255*b1cdbd2cSJim Jagielski             // Register himself as "new" reader.
256*b1cdbd2cSJim Jagielski             // This value must be 0 before - because we support single writer access only!
257*b1cdbd2cSJim Jagielski             ++m_nReadCount;
258*b1cdbd2cSJim Jagielski             // Close barrier for other writer!
259*b1cdbd2cSJim Jagielski             // Why?
260*b1cdbd2cSJim Jagielski             // You hold the serializer mutex - next one can be a reader OR a writer.
261*b1cdbd2cSJim Jagielski             // They must blocked then - because you will be a reader after this call
262*b1cdbd2cSJim Jagielski             // and writer use this condition to wait for current reader!
263*b1cdbd2cSJim Jagielski             m_aWriteCondition.reset();
264*b1cdbd2cSJim Jagielski             // Open door for next waiting thread in serialize queue!
265*b1cdbd2cSJim Jagielski             m_aSerializer.release();
266*b1cdbd2cSJim Jagielski         }
267*b1cdbd2cSJim Jagielski 
268*b1cdbd2cSJim Jagielski 	//-------------------------------------------------------------------------------------------------------------
269*b1cdbd2cSJim Jagielski 	//	private member
270*b1cdbd2cSJim Jagielski 	//-------------------------------------------------------------------------------------------------------------
271*b1cdbd2cSJim Jagielski 	private:
272*b1cdbd2cSJim Jagielski 
273*b1cdbd2cSJim Jagielski 		::osl::Mutex		m_aAccessLock		;	/// regulate access on internal member of this instance
274*b1cdbd2cSJim Jagielski 		::osl::Mutex		m_aSerializer		;	/// serialze incoming read/write access threads
275*b1cdbd2cSJim Jagielski 		::osl::Condition	m_aWriteCondition	;	/// a writer must wait till current working reader are gone
276*b1cdbd2cSJim Jagielski 		sal_Int32			m_nReadCount		;	/// every reader is registered - the last one open the door for waiting writer
277*b1cdbd2cSJim Jagielski 
278*b1cdbd2cSJim Jagielski };		//	class FairRWLock
279*b1cdbd2cSJim Jagielski 
280*b1cdbd2cSJim Jagielski }		//	namespace framework
281*b1cdbd2cSJim Jagielski 
282*b1cdbd2cSJim Jagielski #endif	//	#ifndef __FRAMEWORK_THREADHELP_FAIRRWLOCK_HXX_
283