genode/repos/base/include/base/weak_ptr.h

387 lines
7.6 KiB
C++

/*
* \brief Utilities for object life-time management
* \author Norman Feske
* \date 2013-03-09
*/
/*
* Copyright (C) 2013 Genode Labs GmbH
*
* This file is part of the Genode OS framework, which is distributed
* under the terms of the GNU General Public License version 2.
*/
#ifndef _INCLUDE__BASE__WEAK_PTR_H_
#define _INCLUDE__BASE__WEAK_PTR_H_
#include <base/lock.h>
#include <util/list.h>
namespace Genode {
class Weak_object_base;
class Weak_ptr_base;
class Locked_ptr_base;
template <typename T> struct Weak_object;
template <typename T> struct Weak_ptr;
template <typename T> struct Locked_ptr;
}
/**
* Type-agnostic base class of a weak pointer
*
* This class implements the mechanics of the the 'Weak_ptr' class template.
* It is not used directly.
*/
class Genode::Weak_ptr_base : public Genode::List<Weak_ptr_base>::Element
{
private:
friend class Weak_object_base;
friend class Locked_ptr_base;
Lock mutable _lock;
Weak_object_base *_obj;
bool _valid; /* true if '_obj' points to an
existing object */
inline void _adopt(Weak_object_base *obj);
inline void _disassociate();
protected:
/**
* Return pointer to object if it exists, or 0 if object vanished
*
* \noapi
*/
Weak_object_base *obj() const { return _valid ? _obj: 0; }
explicit inline Weak_ptr_base(Weak_object_base *obj);
public:
/**
* Default constructor, produces invalid pointer
*/
inline Weak_ptr_base();
inline ~Weak_ptr_base();
/**
* Assignment operator
*/
inline void operator = (Weak_ptr_base const &other);
/**
* Test for equality
*/
inline bool operator == (Weak_ptr_base const &other) const;
/**
* Inspection hook for unit test
*
* \noapi
*/
void debug_info() const;
};
/**
* Type-agnostic base class of a weak object
*/
class Genode::Weak_object_base
{
private:
friend class Weak_ptr_base;
friend class Locked_ptr_base;
/**
* List of weak pointers currently pointing to the object
*/
Lock _list_lock;
List<Weak_ptr_base> _list;
/**
* Lock used to defer the destruction of an object derived from
* 'Weak_object_base'
*/
Lock _destruct_lock;
protected:
/**
* Destructor
*
* \noapi
*/
inline ~Weak_object_base();
/**
* To be called from 'Weak_object<T>' only
*
* \noapi
*/
template <typename T>
Weak_ptr<T> _weak_ptr();
public:
/**
* Mark object as safe to be destructed
*
* This method must be called by the destructor of a weak object to
* defer the destruction until no 'Locked_ptr' is held to the object.
*/
void lock_for_destruction() { _destruct_lock.lock(); }
/**
* Inspection hook for unit test
*
* \noapi
*/
void debug_info() const;
};
class Genode::Locked_ptr_base
{
protected:
Weak_object_base *curr;
/**
* Constructor
*
* \noapi
*/
inline Locked_ptr_base(Weak_ptr_base &weak_ptr);
/**
* Destructor
*
* \noapi
*/
inline ~Locked_ptr_base();
};
/**
* Weak pointer to a given type
*
* A weak pointer can be obtained from a weak object (an object that inherits
* the 'Weak_object' class template) and safely survives the lifetime of the
* associated weak object. If the weak object disappears, all
* weak pointers referring to the object are automatically invalidated.
* To avoid race conditions between the destruction and use of a weak object,
* a weak pointer cannot be de-reference directly. To access the object, a
* weak pointer must be turned into a locked pointer ('Locked_ptr').
*/
template <typename T>
struct Genode::Weak_ptr : Genode::Weak_ptr_base
{
/**
* Default constructor creates invalid pointer
*/
Weak_ptr() { }
/**
* Copy constructor
*/
Weak_ptr(Weak_ptr<T> const &other) : Weak_ptr_base(other.obj()) { }
/**
* Assignment operator
*/
inline void operator = (Weak_ptr<T> const &other)
{
*static_cast<Weak_ptr_base *>(this) = other;
}
};
/**
* Weak object
*
* This class template must be inherited in order to equip an object with
* the weak-pointer mechanism.
*
* \param T type of the derived class
*/
template <typename T>
struct Genode::Weak_object : Genode::Weak_object_base
{
/**
* Obtain a weak pointer referring to the weak object
*/
Weak_ptr<T> weak_ptr() { return _weak_ptr<T>(); }
};
/**
* Locked pointer
*
* A locked pointer is constructed from a weak pointer. After construction,
* its validity can (and should) be checked by calling the 'is_valid'
* method. If the locked pointer is valid, the pointed-to object is known to
* be locked until the locked pointer is destroyed. During this time, the
* locked pointer can safely be de-referenced.
*
* The typical pattern of using a locked pointer is to declare it as a
* local variable. Once the execution leaves the scope of the variable, the
* locked pointer is destructed, which unlocks the pointed-to weak object.
* It effectively serves as a lock guard.
*/
template <typename T>
struct Genode::Locked_ptr : Genode::Locked_ptr_base
{
Locked_ptr(Weak_ptr<T> &weak_ptr) : Locked_ptr_base(weak_ptr) { }
T *operator -> () { return static_cast<T *>(curr); }
T &operator * () { return *static_cast<T *>(curr); }
/**
* Returns true if the locked pointer is valid
*
* Only if valid, the locked pointer can be de-referenced. Otherwise,
* the attempt will result in a null-pointer access.
*/
bool is_valid() const { return curr != 0; }
};
/********************
** Implementation **
********************/
void Genode::Weak_ptr_base::_adopt(Genode::Weak_object_base *obj)
{
if (!obj)
return;
_obj = obj;
_valid = true;
Lock::Guard guard(_obj->_list_lock);
_obj->_list.insert(this);
}
void Genode::Weak_ptr_base::_disassociate()
{
/* defer destruction of object */
{
Lock::Guard guard(_lock);
if (!_valid)
return;
_obj->_destruct_lock.lock();
}
/*
* Disassociate reference from object
*
* Because we hold the '_destruct_lock', we are safe to do
* the list operation. However, after we have released the
* 'Weak_ptr_base::_lock', the object may have invalidated
* the reference. So we must check for validity again.
*/
{
Lock::Guard guard(_obj->_list_lock);
if (_valid)
_obj->_list.remove(this);
}
/* release object */
_obj->_destruct_lock.unlock();
}
Genode::Weak_ptr_base::Weak_ptr_base(Genode::Weak_object_base *obj)
{
_adopt(obj);
}
Genode::Weak_ptr_base::Weak_ptr_base() : _obj(0), _valid(false) { }
void Genode::Weak_ptr_base::operator = (Weak_ptr_base const &other)
{
/* self assignment */
if (&other == this)
return;
Weak_object_base *obj = other.obj();
_disassociate();
_adopt(obj);
}
bool Genode::Weak_ptr_base::operator == (Weak_ptr_base const &other) const
{
if (&other == this)
return true;
Lock::Guard guard_this(_lock), guard_other(other._lock);
return (!_valid && !other._valid)
|| (_valid && other._valid && _obj == other._obj);
}
Genode::Weak_ptr_base::~Weak_ptr_base()
{
_disassociate();
}
template <typename T>
Genode::Weak_ptr<T> Genode::Weak_object_base::_weak_ptr()
{
Weak_ptr_base result(this);
return *static_cast<Weak_ptr<T> *>(&result);
}
Genode::Weak_object_base::~Weak_object_base()
{
{
Lock::Guard guard(_list_lock);
Weak_ptr_base *curr = 0;
while ((curr = _list.first())) {
Lock::Guard guard(curr->_lock);
curr->_valid = false;
_list.remove(curr);
}
}
}
Genode::Locked_ptr_base::Locked_ptr_base(Weak_ptr_base &weak_ptr)
: curr(0)
{
Lock::Guard guard(weak_ptr._lock);
if (!weak_ptr._valid)
return;
curr = weak_ptr._obj;
curr->_destruct_lock.lock();
}
Genode::Locked_ptr_base::~Locked_ptr_base()
{
if (curr)
curr->_destruct_lock.unlock();
}
#endif /* _INCLUDE__BASE__WEAK_PTR_H_ */