blob: bff517ba7140b36a0bb72da3bc7861ed28afa6ca [file] [log] [blame]
/**************************************************************
*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*
*************************************************************/
#ifndef _SALHELPER_MONITOR_HXX_
#define _SALHELPER_MONITOR_HXX_
#include <sal/types.h>
#include <osl/conditn.hxx>
#include <osl/diagnose.h>
#include <osl/interlck.h>
#include <rtl/ref.hxx>
#include <salhelper/refobj.hxx>
#include <salhelper/future.hxx>
#include <salhelper/futurequeue.hxx>
namespace salhelper
{
//----------------------------------------------------------------------------
#ifndef SALHELPER_COPYCTOR_API
#define SALHELPER_COPYCTOR_API(C) C (const C&); C& operator= (const C&)
#endif
//----------------------------------------------------------------------------
class MonitorCondition : protected osl::Condition
{
/** Representation.
*/
oslInterlockedCount m_nReferenceCount;
/** Not implemented.
*/
SALHELPER_COPYCTOR_API(MonitorCondition);
public:
/** Construction.
*/
inline MonitorCondition() SAL_THROW(()) : m_nReferenceCount (0)
{
Condition::set();
}
/** Destruction.
*/
inline ~MonitorCondition() SAL_THROW(())
{
OSL_ASSERT(m_nReferenceCount == 0);
}
/** Acquire or enter the monitor.
*/
inline void acquire() SAL_THROW(())
{
if (osl_incrementInterlockedCount (&m_nReferenceCount) == 1)
{
Condition::reset();
}
}
/** Release or leave the monitor.
*/
inline void release() SAL_THROW(())
{
if (osl_decrementInterlockedCount (&m_nReferenceCount) == 0)
{
Condition::set();
}
}
/** Wait until all references are released.
*/
inline void wait() SAL_THROW(())
{
Condition::wait();
}
};
//----------------------------------------------------------------------------
class QueuedReaderWriterMonitor : public salhelper::ReferenceObject
{
/** Representation.
*/
typedef salhelper::Future<sal_Int32> future_type;
salhelper::FutureQueue<sal_Int32> m_aQueue;
salhelper::MonitorCondition m_aMonitor;
/** Not implemented.
*/
SALHELPER_COPYCTOR_API(QueuedReaderWriterMonitor);
public:
/** Construction.
*/
inline QueuedReaderWriterMonitor()
{
// Insert the token.
m_aQueue.put(0);
}
/** Acquire read access.
*/
inline void acquireReader()
{
// Obtain the token.
rtl::Reference<future_type> xFuture (m_aQueue.get());
xFuture->get();
// Enter the monitor.
m_aMonitor.acquire();
// Push back the token.
m_aQueue.put(0);
}
/** Release read access.
*/
inline void releaseReader()
{
// Leave the monitor.
m_aMonitor.release();
}
/** Acquire write access.
*/
inline void acquireWriter()
{
// Obtain the token.
rtl::Reference<future_type> xFuture (m_aQueue.get());
xFuture->get();
// Wait until all readers have left.
m_aMonitor.wait();
}
/** Release write access.
*/
inline void releaseWriter()
{
// Push back the token.
m_aQueue.put(0);
}
protected:
/** Destruction.
*/
virtual ~QueuedReaderWriterMonitor()
{}
};
//----------------------------------------------------------------------------
template<class monitor_type>
class ReaderGuard
{
/** Representation.
*/
monitor_type *m_pMonitor;
/** Not implemented.
*/
SALHELPER_COPYCTOR_API(ReaderGuard<monitor_type>);
public:
/** Construction. Acquire monitor read access.
*/
inline ReaderGuard (monitor_type & rMonitor) : m_pMonitor (&rMonitor)
{
m_pMonitor->acquireReader();
}
/** Construction. Acquire monitor read access.
*/
inline ReaderGuard (monitor_type * pMonitor) : m_pMonitor (pMonitor)
{
OSL_PRECOND(m_pMonitor, "ReaderGuard::ReaderGuard(): No Monitor");
m_pMonitor->acquireReader();
}
/** Destruction. Release monitor read access.
*/
inline ~ReaderGuard()
{
if (m_pMonitor)
m_pMonitor->releaseReader();
}
/** Release monitor read access.
*/
inline void clear()
{
if (m_pMonitor)
{
m_pMonitor->releaseReader();
m_pMonitor = 0;
}
}
};
//----------------------------------------------------------------------------
typedef ReaderGuard<QueuedReaderWriterMonitor> QueuedReaderGuard;
//----------------------------------------------------------------------------
template<class monitor_type>
class WriterGuard
{
/** Representation.
*/
monitor_type *m_pMonitor;
/** Not implemented.
*/
SALHELPER_COPYCTOR_API(WriterGuard<monitor_type>);
public:
/** Construction. Acquire monitor write access.
*/
inline WriterGuard (monitor_type & rMonitor) : m_pMonitor (&rMonitor)
{
m_pMonitor->acquireWriter();
}
/** Construction. Acquire monitor write access.
*/
inline WriterGuard (monitor_type * pMonitor) : m_pMonitor (pMonitor)
{
OSL_PRECOND(m_pMonitor, "WriterGuard::WriterGuard(): No Monitor");
m_pMonitor->acquireWriter();
}
/** Destruction. Release monitor write access.
*/
inline ~WriterGuard()
{
if (m_pMonitor)
m_pMonitor->releaseWriter();
}
/** Release monitor write access.
*/
inline void clear()
{
if (m_pMonitor)
{
m_pMonitor->releaseWriter();
m_pMonitor = 0;
}
}
};
//----------------------------------------------------------------------------
typedef WriterGuard<QueuedReaderWriterMonitor> QueuedWriterGuard;
//----------------------------------------------------------------------------
} // namespace salhelper
#endif /* !_SALHELPER_MONITOR_HXX_ */