Commit a0cb4555 authored by Sebastian Eichelbaum's avatar Sebastian Eichelbaum
Browse files

[ADD] - added new way for access control in WSharedObjects

parent b155dfd9
......@@ -234,9 +234,14 @@ public:
typedef WSharedAssociativeContainer< ConstraintContainerType > ConstraintSharedContainerType;
/**
* Alias for the proper access object
* Alias for proper accessing the object. Read ticket.
*/
typedef typename ConstraintSharedContainerType::WSharedAccess ConstraintAccess;
typedef typename ConstraintSharedContainerType::ReadTicket ReadTicket;
/**
* Alias for proper accessing the object. Write ticket.
*/
typedef typename ConstraintSharedContainerType::WriteTicket WriteTicket;
/**
* Alias for min constraints. It is an alias for convenience.
......@@ -261,7 +266,7 @@ public:
*
* \return the constraint access object
*/
ConstraintAccess getConstraints();
ConstraintSharedContainerType getConstraints();
/**
* Gets the condition, which gets notified whenever the list of constraints changes. It is notified AFTER the write lock has been released so
......@@ -413,11 +418,11 @@ protected:
* Cleans m_constraints from all existing constrains of the specified type.
*
* \param type the type to remove.
* \param useLock true if a lock should be used and if m_constraintsChanged should be notified. Set this to false to use remove lock from inside
* another operation already using the lock and notifying.
*
* \param ticket the write ticket if already existent.
*/
void removeConstraints( PROPERTYCONSTRAINT_TYPE type, bool useLock = true );
void removeConstraints( PROPERTYCONSTRAINT_TYPE type,
typename WPropertyVariable< T >::ConstraintSharedContainerType::WriteTicket ticket
= ConstraintSharedContainerType::WriteTicket() );
/**
* This method gets called by WFlag whenever the value of the property changes. It re-emits the signal with a this pointer
......@@ -435,11 +440,6 @@ protected:
*/
ConstraintSharedContainerType m_constraints;
/**
* The access object of this constrains list.
*/
ConstraintAccess m_constraintsAccess;
private:
};
......@@ -448,8 +448,7 @@ WPropertyVariable< T >::WPropertyVariable( std::string name, std::string descrip
WFlag< T >( new WCondition(), initial ),
WPropertyBase( name, description ),
m_constraintsChanged( new WCondition() ),
m_constraints(),
m_constraintsAccess( m_constraints.getAccessObject() )
m_constraints()
{
updateType();
......@@ -463,8 +462,7 @@ WPropertyVariable< T >::WPropertyVariable( std::string name, std::string descrip
WFlag< T >( condition, initial ),
WPropertyBase( name, description ),
m_constraintsChanged( new WCondition() ),
m_constraints(),
m_constraintsAccess( m_constraints.getAccessObject() )
m_constraints()
{
updateType();
......@@ -479,8 +477,7 @@ WPropertyVariable< T >::WPropertyVariable( std::string name, std::string descrip
WFlag< T >( new WCondition(), initial ),
WPropertyBase( name, description ),
m_constraintsChanged( new WCondition() ),
m_constraints(),
m_constraintsAccess( m_constraints.getAccessObject() )
m_constraints()
{
updateType();
......@@ -499,8 +496,7 @@ WPropertyVariable< T >::WPropertyVariable( std::string name, std::string descrip
WFlag< T >( condition, initial ),
WPropertyBase( name, description ),
m_constraintsChanged( new WCondition() ),
m_constraints(),
m_constraintsAccess( m_constraints.getAccessObject() )
m_constraints()
{
updateType();
......@@ -518,18 +514,20 @@ WPropertyVariable< T >::WPropertyVariable( const WPropertyVariable< T >& from ):
WFlag< T >( from ),
WPropertyBase( from ),
m_constraintsChanged( new WCondition() ),
m_constraints(),
m_constraintsAccess( m_constraints.getAccessObject() )
m_constraints()
{
// copy the constraints
from.m_constraintsAccess->beginRead();
// lock, unlocked if l looses focus
typename WPropertyVariable< T >::ConstraintSharedContainerType::ReadTicket l =
const_cast< WPropertyVariable< T >& >( from ).m_constraints.getReadTicket();
// we need to make a deep copy here.
for ( ConstraintContainerIteratorType iter = from.m_constraintsAccess->get().begin(); iter != from.m_constraintsAccess->get().end(); ++iter )
for ( ConstraintContainerIteratorType iter = l->get().begin(); iter != l->get().end(); ++iter )
{
// clone them to keep dynamic type
m_constraintsAccess->get().insert( ( *iter )->clone() );
l->get().insert( ( *iter )->clone() );
}
from.m_constraintsAccess->endRead();
}
template < typename T >
......@@ -540,9 +538,10 @@ WPropertyVariable< T >::~WPropertyVariable()
m_updateCondition->remove( WFlag< T >::getValueChangeCondition() );
m_notifierConnection.disconnect();
m_constraintsAccess->beginWrite();
m_constraintsAccess->get().clear();
m_constraintsAccess->endWrite();
// lock, unlocked if l looses focus
typename WPropertyVariable< T >::ConstraintSharedContainerType::WriteTicket l = m_constraints.getWriteTicket();
l->get().clear();
}
template < typename T >
......@@ -561,15 +560,15 @@ void WPropertyVariable< T >::propertyChangeNotifier()
template < typename T >
bool WPropertyVariable< T >::accept( T newValue )
{
m_constraintsAccess->beginRead();
// lock, lock vanishes if l looses focus
typename WPropertyVariable< T >::ConstraintSharedContainerType::ReadTicket l = m_constraints.getReadTicket();
// iterate through the set
bool acceptable = WFlag< T >::accept( newValue );
for ( ConstraintContainerConstIteratorType it = m_constraintsAccess->get().begin(); it != m_constraintsAccess->get().end(); ++it )
for ( ConstraintContainerConstIteratorType it = l->get().begin(); it != l->get().end(); ++it )
{
acceptable &= ( *it )->accept( boost::shared_static_cast< WPropertyVariable< T > >( shared_from_this() ), newValue );
}
m_constraintsAccess->endRead();
return acceptable;
}
......@@ -638,9 +637,12 @@ bool WPropertyVariable< T >::ensureValidity( T newValidValue, bool suppressNotif
template < typename T >
void WPropertyVariable< T >::addConstraint( boost::shared_ptr< PropertyConstraint > constraint )
{
m_constraintsAccess->beginWrite();
m_constraintsAccess->get().insert( constraint );
m_constraintsAccess->endWrite();
// lock, unlocked if l looses focus
typename WPropertyVariable< T >::ConstraintSharedContainerType::WriteTicket l = m_constraints.getWriteTicket();
l->get().insert( constraint );
// unlock by hand
l.reset();
m_constraintsChanged->notify();
}
......@@ -689,10 +691,15 @@ boost::shared_ptr< WPropertyConstraintMax< T > > WPropertyVariable< T >::setMax(
template < typename T >
void WPropertyVariable< T >::replaceConstraint( boost::shared_ptr< PropertyConstraint > constraint, PROPERTYCONSTRAINT_TYPE type )
{
m_constraintsAccess->beginWrite();
removeConstraints( type, false );
m_constraintsAccess->get().insert( constraint );
m_constraintsAccess->endWrite();
// lock, unlocked if l looses focus
typename WPropertyVariable< T >::ConstraintSharedContainerType::WriteTicket l = m_constraints.getWriteTicket();
removeConstraints( type, l );
l->get().insert( constraint );
// unlock by hand
l.reset();
m_constraintsChanged->notify();
}
......@@ -709,19 +716,17 @@ template < typename T >
boost::shared_ptr< typename WPropertyVariable< T >::PropertyConstraint >
WPropertyVariable< T >::getFirstConstraint( PROPERTYCONSTRAINT_TYPE type )
{
// lock
m_constraintsAccess->beginRead();
// lock, unlocked if l looses focus
typename WPropertyVariable< T >::ConstraintSharedContainerType::ReadTicket l = m_constraints.getReadTicket();
// search first appearance of a constraint of the specified type
for ( ConstraintContainerConstIteratorType it = m_constraintsAccess->get().begin(); it != m_constraintsAccess->get().end(); ++it )
for ( ConstraintContainerConstIteratorType it = l->get().begin(); it != l->get().end(); ++it )
{
if ( ( *it )->getType() == type )
{
m_constraintsAccess->endRead();
return ( *it );
}
}
m_constraintsAccess->endRead();
return boost::shared_ptr< PropertyConstraint >();
}
......@@ -729,19 +734,18 @@ WPropertyVariable< T >::getFirstConstraint( PROPERTYCONSTRAINT_TYPE type )
template < typename T >
int WPropertyVariable< T >::countConstraint( PROPERTYCONSTRAINT_TYPE type )
{
// lock
m_constraintsAccess->beginRead();
// lock, unlocked if l looses focus
typename WPropertyVariable< T >::ConstraintSharedContainerType::ReadTicket l = m_constraints.getReadTicket();
int i = 0;
// search first appearance of a constraint of the specified type
for ( ConstraintContainerConstIteratorType it = m_constraintsAccess->get().begin(); it != m_constraintsAccess->get().end(); ++it )
for ( ConstraintContainerConstIteratorType it = l->get().begin(); it != l->get().end(); ++it )
{
if ( ( *it )->getType() == type )
{
i++;
}
}
m_constraintsAccess->endRead();
return i;
}
......@@ -777,25 +781,31 @@ boost::shared_ptr< WPropertyConstraintMax< T > > WPropertyVariable< T >::getMax(
}
template< typename T >
typename WPropertyVariable<T>::ConstraintAccess WPropertyVariable<T>::getConstraints()
typename WPropertyVariable<T>::ConstraintSharedContainerType WPropertyVariable<T>::getConstraints()
{
return m_constraintsAccess;
return m_constraints;
}
template < typename T >
void WPropertyVariable< T >::removeConstraints( PROPERTYCONSTRAINT_TYPE type, bool useLock )
void WPropertyVariable< T >::removeConstraints( PROPERTYCONSTRAINT_TYPE type,
typename WPropertyVariable< T >::ConstraintSharedContainerType::WriteTicket ticket )
{
typename WPropertyVariable< T >::ConstraintSharedContainerType::WriteTicket l = ticket;
bool useLock = !ticket;
// lock the constraints set
if ( useLock )
{
m_constraintsAccess->beginWrite();
// lock, unlocked if l looses focus
l = m_constraints.getWriteTicket();
}
for ( ConstraintContainerConstIteratorType it = m_constraintsAccess->get().begin(); it != m_constraintsAccess->get().end(); )
for ( ConstraintContainerConstIteratorType it = l->get().begin(); it != l->get().end(); )
{
if ( ( *it )->getType() == type )
{
m_constraintsAccess->get().erase( it++ );
l->get().erase( it++ );
}
else
{
......@@ -806,7 +816,9 @@ void WPropertyVariable< T >::removeConstraints( PROPERTYCONSTRAINT_TYPE type, bo
// only notify and unlock if locked earlier.
if ( useLock )
{
m_constraintsAccess->endWrite();
// unlock by hand
l.reset();
m_constraintsChanged->notify();
}
}
......
......@@ -28,6 +28,7 @@
#include <boost/thread.hpp>
#include "WCondition.h"
#include "WSharedObjectTicket.h"
/**
* Wrapper around an object/type for thread safe sharing of objects among multiple threads. The advantage of this class over WFlag
......@@ -151,6 +152,32 @@ public:
*/
WSharedAccess getAccessObject();
/**
* Type for read tickets.
*/
typedef boost::shared_ptr< WSharedObjectTicketRead< T > > ReadTicket;
/**
* Type for write tickets.
*/
typedef boost::shared_ptr< WSharedObjectTicketWrite< T > > WriteTicket;
/**
* Returns a ticket to get read access to the contained data. After the ticket is freed, the read lock vanishes.
*
* \return the read ticket
*/
ReadTicket getReadTicket();
/**
* Returns a ticket to get write access to the contained data. After the ticket is freed, the write lock vanishes.
*
* \param suppressNotify true if no notification should be send after unlocking.
*
* \return the ticket
*/
WriteTicket getWriteTicket( bool suppressNotify = false );
/**
* This condition fires whenever the encapsulated object changed. This is fired automatically by endWrite().
*
......@@ -265,5 +292,30 @@ boost::shared_ptr< WCondition > WSharedObject< T >::getChangeCondition()
return m_changeCondition;
}
template < typename T >
typename WSharedObject< T >::ReadTicket WSharedObject< T >::getReadTicket()
{
return boost::shared_ptr< WSharedObjectTicketRead< T > >(
new WSharedObjectTicketRead< T >( m_object, m_lock, boost::shared_ptr< WCondition >() )
);
}
template < typename T >
typename WSharedObject< T >::WriteTicket WSharedObject< T >::getWriteTicket( bool suppressNotify )
{
if ( suppressNotify )
{
return boost::shared_ptr< WSharedObjectTicketWrite< T > >(
new WSharedObjectTicketWrite< T >( m_object, m_lock, boost::shared_ptr< WCondition >() )
);
}
else
{
return boost::shared_ptr< WSharedObjectTicketWrite< T > >(
new WSharedObjectTicketWrite< T >( m_object, m_lock, m_changeCondition )
);
}
}
#endif // WSHAREDOBJECT_H
//---------------------------------------------------------------------------
//
// Project: OpenWalnut ( http://www.openwalnut.org )
//
// Copyright 2009 OpenWalnut Community, BSV@Uni-Leipzig and CNCF@MPI-CBS
// For more information see http://www.openwalnut.org/copying
//
// This file is part of OpenWalnut.
//
// OpenWalnut is free software: you can redistribute it and/or modify
// it under the terms of the GNU Lesser General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// OpenWalnut 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 for more details.
//
// You should have received a copy of the GNU Lesser General Public License
// along with OpenWalnut. If not, see <http://www.gnu.org/licenses/>.
//
//---------------------------------------------------------------------------
#include "WSharedObject.h"
#include "WSharedObjectTicket.h"
//---------------------------------------------------------------------------
//
// Project: OpenWalnut ( http://www.openwalnut.org )
//
// Copyright 2009 OpenWalnut Community, BSV@Uni-Leipzig and CNCF@MPI-CBS
// For more information see http://www.openwalnut.org/copying
//
// This file is part of OpenWalnut.
//
// OpenWalnut is free software: you can redistribute it and/or modify
// it under the terms of the GNU Lesser General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// OpenWalnut 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 for more details.
//
// You should have received a copy of the GNU Lesser General Public License
// along with OpenWalnut. If not, see <http://www.gnu.org/licenses/>.
//
//---------------------------------------------------------------------------
#ifndef WSHAREDOBJECTTICKET_H
#define WSHAREDOBJECTTICKET_H
#include <iostream>
#include <boost/shared_ptr.hpp>
#include "WCondition.h"
#include "WSharedObjectTicket.h"
// The shared object class
template < typename T >
class WSharedObject;
/**
* Class which represents granted access to a locked object. It contains a reference to the object and a lock. The lock is freed after the ticket
* has been destroyed.
*/
template < typename Data >
class WSharedObjectTicket
{
// the shared object class needs protected access to create new instances
friend class WSharedObject< Data >;
public:
/**
* Destroys the ticket and releases the lock.
*/
virtual ~WSharedObjectTicket()
{
// NOTE: the derived destructor already unlocks.
if ( m_condition )
{
m_condition->notify();
}
};
/**
* Returns the protected data. As long as you own the ticket, you are allowed to use it.
*
* \return the data
*/
Data& get() const
{
return m_data;
};
protected:
/**
* Create a new instance. It is protected to avoid someone to create them. It locks the mutex.
*
* \param data the data to protect
* \param mutex the mutex used to lock
* \param condition a condition that should be fired upon unlock. Can be NULL.
*/
WSharedObjectTicket( Data& data, boost::shared_ptr< boost::shared_mutex > mutex, boost::shared_ptr< WCondition > condition ): // NOLINT
m_data( data ),
m_mutex( mutex ),
m_condition( condition )
{
};
/**
* The data to which access is allowed by the ticket
*/
Data& m_data;
/**
* The mutex used for locking.
*/
boost::shared_ptr< boost::shared_mutex > m_mutex;
/**
* A condition which gets notified after unlocking. Especially useful to notify waiting threads about a change in the object.
*/
boost::shared_ptr< WCondition > m_condition;
/**
* Unlocks the mutex.
*/
virtual void unlock() = 0;
private:
};
/**
* Class which represents granted access to a locked object. It contains a reference to the object and a lock. The lock is freed after the ticket
* has been destroyed. This class especially implements the shared (read) lock.
*/
template < typename Data >
class WSharedObjectTicketRead: public WSharedObjectTicket< Data >
{
// the shared object class needs protected access to create new instances
friend class WSharedObject< Data >;
public:
/**
* Destroys the ticket and releases the lock.
*/
virtual ~WSharedObjectTicketRead()
{
unlock();
};
protected:
/**
* Create a new instance. It is protected to avoid someone to create them. It locks the mutex for read.
*
* \param data the data to protect
* \param mutex the mutex used to lock
* \param condition a condition that should be fired upon unlock. Can be NULL.
*/
WSharedObjectTicketRead( Data& data, boost::shared_ptr< boost::shared_mutex > mutex, boost::shared_ptr< WCondition > condition ): // NOLINT
WSharedObjectTicket< Data >( data, mutex, condition ),
m_lock( boost::shared_lock< boost::shared_mutex >( *mutex ) )
{
};
/**
* The lock.
*/
boost::shared_lock< boost::shared_mutex > m_lock;
/**
* Unlocks the mutex.
*/
virtual void unlock()
{
m_lock.unlock();
}
private:
};
/**
* Class which represents granted access to a locked object. It contains a reference to the object and a lock. The lock is freed after the ticket
* has been destroyed. This class especially implements the exclusive (write) lock.
*/
template < typename Data >
class WSharedObjectTicketWrite: public WSharedObjectTicket< Data >
{
// the shared object class needs protected access to create new instances
friend class WSharedObject< Data >;
public:
/**
* Destroys the ticket and releases the lock.
*/
virtual ~WSharedObjectTicketWrite()
{
unlock();
};
protected:
/**
* Create a new instance. It is protected to avoid someone to create them. It locks the mutex for write.
*
* \param data the data to protect
* \param mutex the mutex used to lock
* \param condition a condition that should be fired upon unlock. Can be NULL.
*/
WSharedObjectTicketWrite( Data& data, boost::shared_ptr< boost::shared_mutex > mutex, boost::shared_ptr< WCondition > condition ): // NOLINT
WSharedObjectTicket< Data >( data, mutex, condition ),
m_lock( boost::unique_lock< boost::shared_mutex >( *mutex ) )
{
};
/**
* The lock.
*/
boost::unique_lock< boost::shared_mutex > m_lock;
/**
* Unlocks the mutex.
*/
virtual void unlock()
{
m_lock.unlock();
}
private:
};
#endif // WSHAREDOBJECTTICKET_H
......@@ -102,39 +102,34 @@ WSharedSequenceContainer< T, S >::~WSharedSequenceContainer()
template < typename T, typename S >
void WSharedSequenceContainer< T, S >::push_back( const T& x )
{
typename WSharedObject< S >::WSharedAccess a = WSharedObject< S >::getAccessObject();
a->beginWrite();
// Lock, if "a" looses focus -> look is freed
typename WSharedObject< S >::WriteTicket a = WSharedObject< S >::getWriteTicket();
a->get().push_back( x );
a->endWrite();
}
template < typename T, typename S >
void WSharedSequenceContainer< T, S >::pop_back()
{
typename WSharedObject< S >::WSharedAccess a = WSharedObject< S >::getAccessObject();
a->beginWrite();
// Lock, if "a" looses focus -> look is freed
typename WSharedObject< S >::WriteTicket a = WSharedObject< S >::getWriteTicket();
a->get().pop_back();
a->endWrite();
}
template < typename T, typename S >
void WSharedSequenceContainer< T, S >::clear()
{
typename WSharedObject< S >::WSharedAccess a = WSharedObject< S >::getAccessObject();
a->beginWrite();
// Lock, if "a" looses focus -> look is freed
typename WSharedObject< S >::WriteTicket a = WSharedObject< S >::getWriteTicket();
a->get().clear();
a->endWrite();
}