summaryrefslogtreecommitdiff
path: root/framework/inc/threadhelp/fairrwlock.hxx
diff options
context:
space:
mode:
Diffstat (limited to 'framework/inc/threadhelp/fairrwlock.hxx')
-rw-r--r--framework/inc/threadhelp/fairrwlock.hxx286
1 files changed, 286 insertions, 0 deletions
diff --git a/framework/inc/threadhelp/fairrwlock.hxx b/framework/inc/threadhelp/fairrwlock.hxx
new file mode 100644
index 000000000000..0f984c8d03f9
--- /dev/null
+++ b/framework/inc/threadhelp/fairrwlock.hxx
@@ -0,0 +1,286 @@
+/*************************************************************************
+ *
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * Copyright 2000, 2010 Oracle and/or its affiliates.
+ *
+ * OpenOffice.org - a multi-platform office productivity suite
+ *
+ * This file is part of OpenOffice.org.
+ *
+ * OpenOffice.org is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License version 3
+ * only, as published by the Free Software Foundation.
+ *
+ * OpenOffice.org is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License version 3 for more details
+ * (a copy is included in the LICENSE file that accompanied this code).
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * version 3 along with OpenOffice.org. If not, see
+ * <http://www.openoffice.org/license.html>
+ * for a copy of the LGPLv3 License.
+ *
+ ************************************************************************/
+
+#ifndef __FRAMEWORK_THREADHELP_FAIRRWLOCK_HXX_
+#define __FRAMEWORK_THREADHELP_FAIRRWLOCK_HXX_
+
+//_________________________________________________________________________________________________________________
+// my own includes
+//_________________________________________________________________________________________________________________
+
+#include <threadhelp/inoncopyable.h>
+#include <threadhelp/irwlock.h>
+#include <macros/debug.hxx>
+
+//_________________________________________________________________________________________________________________
+// interface includes
+//_________________________________________________________________________________________________________________
+#include <com/sun/star/uno/XInterface.hpp>
+
+//_________________________________________________________________________________________________________________
+// other includes
+//_________________________________________________________________________________________________________________
+#include <osl/mutex.hxx>
+#include <osl/conditn.hxx>
+
+//_________________________________________________________________________________________________________________
+// namespace
+//_________________________________________________________________________________________________________________
+
+namespace framework{
+
+//_________________________________________________________________________________________________________________
+// const
+//_________________________________________________________________________________________________________________
+
+//_________________________________________________________________________________________________________________
+// declarations
+//_________________________________________________________________________________________________________________
+
+/*-************************************************************************************************************//**
+ @short implement a read/write lock with fairness between read/write accessors
+ @descr These implementation never should used as base class! Use it as a member every time.
+ Use ReadGuard and/or WriteGuard in your methods (which work with these lock)
+ to make your code threadsafe.
+ Fair means: All reading or writing threads are synchronized AND serialzed by using one
+ mutex. For reader this mutex is used to access internal variables of this lock only;
+ for writer this mutex is used to have an exclusiv access on your class member!
+ => It's a multi-reader/single-writer lock, which no preferred accessor.
+
+ @implements IRWlock
+ @base INonCopyable
+ IRWLock
+
+ @devstatus ready to use
+*//*-*************************************************************************************************************/
+class FairRWLock : public IRWLock
+ , private INonCopyable
+{
+ //-------------------------------------------------------------------------------------------------------------
+ // public methods
+ //-------------------------------------------------------------------------------------------------------------
+ public:
+
+ /*-****************************************************************************************************//**
+ @short standard ctor
+ @descr Initialize instance with right start values for correct working.
+ no reader could exist => m_nReadCount = 0
+ don't block first comming writer => m_aWriteCondition.set()
+
+ @seealso -
+
+ @param -
+ @return -
+
+ @onerror -
+ *//*-*****************************************************************************************************/
+ inline FairRWLock()
+ : m_nReadCount( 0 )
+ {
+ m_aWriteCondition.set();
+ }
+
+ inline virtual ~FairRWLock()
+ {
+ }
+
+ /*-****************************************************************************************************//**
+ @interface IRWLock
+ @short set lock for reading
+ @descr A guard should call this method to acquire read access on your member.
+ Writing isn't allowed then - but nobody could check it for you!
+
+ @seealso method releaseReadAccess()
+
+ @param -
+ @return -
+
+ @onerror -
+ *//*-*****************************************************************************************************/
+ inline virtual void acquireReadAccess()
+ {
+ // Put call in "SERIALIZE"-queue!
+ // After successful acquiring this mutex we are alone ...
+ ::osl::MutexGuard aSerializeGuard( m_aSerializer );
+
+ // ... but we should synchronize us with other reader!
+ // May be - they will unregister himself by using releaseReadAccess()!
+ ::osl::MutexGuard aAccessGuard( m_aAccessLock );
+
+ // Now we must register us as reader by increasing counter.
+ // If this the first writer we must close door for possible writer.
+ // Other reader don't look for this barrier - they work parallel to us!
+ if( m_nReadCount == 0 )
+ {
+ m_aWriteCondition.reset();
+ }
+ ++m_nReadCount;
+ }
+
+ /*-****************************************************************************************************//**
+ @interface IRWLock
+ @short reset lock for reading
+ @descr A guard should call this method to release read access on your member.
+
+ @seealso method acquireReadAccess()
+
+ @param -
+ @return -
+
+ @onerror -
+ *//*-*****************************************************************************************************/
+ inline virtual void releaseReadAccess()
+ {
+ // The access lock is enough at this point
+ // because it's not allowed to wait for all reader or writer here!
+ // That will cause a deadlock!
+ ::osl::MutexGuard aAccessGuard( m_aAccessLock );
+
+ // Unregister as reader first!
+ // Open writer barrier then if it was the last reader.
+ --m_nReadCount;
+ if( m_nReadCount == 0 )
+ {
+ m_aWriteCondition.set();
+ }
+ }
+
+ /*-****************************************************************************************************//**
+ @interface IRWLock
+ @short set lock for writing
+ @descr A guard should call this method to acquire write access on your member.
+ Reading is allowed too - of course.
+ After successfully calling of this method you are the only writer.
+
+ @seealso method releaseWriteAccess()
+
+ @param -
+ @return -
+
+ @onerror -
+ *//*-*****************************************************************************************************/
+ inline virtual void acquireWriteAccess()
+ {
+ // You have to stand in our serialize-queue till all reader
+ // are registered (not for releasing them!) or writer finished their work!
+ // Don't use a guard to do so - because you must hold the mutex till
+ // you call releaseWriteAccess()!
+ // After succesfull acquire you have to wait for current working reader.
+ // Used condition will open by last gone reader object.
+ m_aSerializer.acquire();
+ m_aWriteCondition.wait();
+
+ #ifdef ENABLE_MUTEXDEBUG
+ // A writer is an exclusiv accessor!
+ LOG_ASSERT2( m_nReadCount!=0, "FairRWLock::acquireWriteAccess()", "No threadsafe code detected ... : Read count != 0!" )
+ #endif
+ }
+
+ /*-****************************************************************************************************//**
+ @interface IRWLock
+ @short reset lock for writing
+ @descr A guard should call this method to release write access on your member.
+
+ @seealso method acquireWriteAccess()
+
+ @param -
+ @return -
+
+ @onerror -
+ *//*-*****************************************************************************************************/
+ inline virtual void releaseWriteAccess()
+ {
+ // The only one you have to do here is to release
+ // hold seriliaze-mutex. All other user of these instance are blocked
+ // by these mutex!
+ // You don't need any other mutex here - you are the only one in the moment!
+
+ #ifdef ENABLE_MUTEXDEBUG
+ // A writer is an exclusiv accessor!
+ LOG_ASSERT2( m_nReadCount!=0, "FairRWLock::releaseWriteAccess()", "No threadsafe code detected ... : Read count != 0!" )
+ #endif
+
+ m_aSerializer.release();
+ }
+
+ /*-****************************************************************************************************//**
+ @interface IRWLock
+ @short downgrade a write access to a read access
+ @descr A guard should call this method to change a write to a read access.
+ New readers can work too - new writer are blocked!
+
+ @attention Don't call this method if you are not a writer!
+ Results are not defined then ...
+ An upgrade can't be implemented realy ... because acquiring new access
+ will be the same - there no differences!
+
+ @seealso -
+
+ @param -
+ @return -
+
+ @onerror -
+ *//*-*****************************************************************************************************/
+ inline virtual void downgradeWriteAccess()
+ {
+ // You must be a writer to call this method!
+ // We can't check it - but otherwise it's your problem ...
+ // Thats why you don't need any mutex here.
+
+ #ifdef ENABLE_MUTEXDEBUG
+ // A writer is an exclusiv accessor!
+ LOG_ASSERT2( m_nReadCount!=0, "FairRWLock::downgradeWriteAccess()", "No threadsafe code detected ... : Read count != 0!" )
+ #endif
+
+ // Register himself as "new" reader.
+ // This value must be 0 before - because we support single writer access only!
+ ++m_nReadCount;
+ // Close barrier for other writer!
+ // Why?
+ // You hold the serializer mutex - next one can be a reader OR a writer.
+ // They must blocked then - because you will be a reader after this call
+ // and writer use this condition to wait for current reader!
+ m_aWriteCondition.reset();
+ // Open door for next waiting thread in serialize queue!
+ m_aSerializer.release();
+ }
+
+ //-------------------------------------------------------------------------------------------------------------
+ // private member
+ //-------------------------------------------------------------------------------------------------------------
+ private:
+
+ ::osl::Mutex m_aAccessLock ; /// regulate access on internal member of this instance
+ ::osl::Mutex m_aSerializer ; /// serialze incoming read/write access threads
+ ::osl::Condition m_aWriteCondition ; /// a writer must wait till current working reader are gone
+ sal_Int32 m_nReadCount ; /// every reader is registered - the last one open the door for waiting writer
+
+}; // class FairRWLock
+
+} // namespace framework
+
+#endif // #ifndef __FRAMEWORK_THREADHELP_FAIRRWLOCK_HXX_