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