1  /*
   2   * \brief  Utilities for object life-time management
   3   * \author Norman Feske
   4   * \date   2013-03-09
   5   */

   6  
   7  /*
   8   * Copyright (C) 2013 Genode Labs GmbH
   9   *
  10   * This file is part of the Genode OS framework, which is distributed
  11   * under the terms of the GNU General Public License version 2.
  12   */

  13  
  14  #ifndef _INCLUDE__BASE__WEAK_PTR_H_
  15  #define _INCLUDE__BASE__WEAK_PTR_H_
  16  
  17  #include <base/lock.h>
  18  #include <base/printf.h>
  19  #include <util/list.h>
  20  
  21  namespace Genode {
  22     class Weak_object_base;
  23     class Weak_ptr_base;
  24     class Locked_ptr_base;
  25  
  26     template <typename T> struct Weak_object;
  27     template <typename T> struct Weak_ptr;
  28     template <typename T> struct Locked_ptr;
  29  }

  30  
  31  
  32  /**
  33   * Type-agnostic base class of a weak pointer
  34   *
  35   * This class implements the mechanics of the the `Weak_ptr` class template.
  36   * It is not used directly.
  37   */

  38  class Genode::Weak_ptr_base : public Genode::List<Weak_ptr_base>::Element
  39  {
  40     private:
  41  
  42        friend class Weak_object_base;
  43        friend class Locked_ptr_base;
  44  
  45        Lock mutable      _lock;
  46        Weak_object_base *_obj;
  47  
  48        /*
  49         * This lock is used to synchronize destruction of a weak pointer
  50         * and its corresponding weak object that happen simultanously
  51         */

  52        Lock mutable _destruct_lock { Lock::LOCKED };
  53  
  54        inline void _adopt(Weak_object_base *obj);
  55        inline void _disassociate();

  56  
  57     protected:
  58  
  59        explicit inline Weak_ptr_base(Weak_object_base *obj);
  60  
  61     public:
  62  
  63        /**
  64         * Default constructor, produces invalid pointer
  65         */

  66        inline Weak_ptr_base();
  67  
  68        inline ~Weak_ptr_base();
  69  
  70        /**
  71         * Assignment operator
  72         */

  73        inline void operator = (Weak_ptr_base const &other);

  74  
  75        /**
  76         * Test for equality
  77         */

  78        inline bool operator == (Weak_ptr_base const &other) const;

  79  
  80        /**
  81         * Return pointer to object if it exists, or 0 if object vanished
  82         *
  83         * \noapi
  84         */

  85        Weak_object_base *obj() const { return _obj; }

  86  
  87        /**
  88         * Inspection hook for unit test
  89         *
  90         * \noapi
  91         */

  92        void debug_info() const;

  93  }
;

  94  
  95  
  96  /**
  97   * Type-agnostic base class of a weak object
  98   */

  99  class Genode::Weak_object_base
 100  {
 101     private:
 102  
 103        friend class Weak_ptr_base;
 104        friend class Locked_ptr_base;
 105  
 106        /**
 107         * List of weak pointers currently pointing to the object
 108         */

 109        Lock                _list_lock;
 110        List<Weak_ptr_base> _list;
 111  
 112        /**
 113         * Buffers dequeued weak pointer that get invalidated currently
 114         */

 115        Weak_ptr_base *_ptr_in_destruction = nullptr;
 116  
 117        /**
 118         * Lock to synchronize access to object
 119         */

 120        Lock _lock;

 121  
 122     protected:
 123  
 124        /**
 125         * To be called from `Weak_object<T>` only
 126         *
 127         * \noapi
 128         */

 129        template <typename T>
 130        Weak_ptr<T> _weak_ptr();

 131  
 132     public:
 133  
 134        /**
 135         * This exception signals a weak pointer that the object
 136         * is in destruction progress
 137         */

 138        class In_destruction : Exception {};

 139  
 140        ~Weak_object_base()
 141        {
 142           if (_list.first())
 143              PERR("Weak object %p not destructed properly "
 144                   "there are still dangling pointers to it", this)
;

 145        }

 146  
 147        void disassociate(Weak_ptr_base *ptr)
 148        {
 149           if (!ptr) return;
 150  
 151           {
 152              Lock::Guard guard(_list_lock);
 153  
 154              /*
 155               * If the weak pointer that tries to disassociate is currently
 156               * removed to invalidate it by the weak object`s destructor,
 157               * signal that fact to the pointer, so it can free it`s lock,
 158               * and block until invalidation is finished.
 159               */

 160              if (_ptr_in_destruction == ptr)
 161                 throw In_destruction();

 162  
 163              _list.remove(ptr);

 164           }

 165        }

 166  
 167        /**
 168         * Mark object as safe to be destructed
 169         *
 170         * This method must be called by the destructor of a weak object to
 171         * defer the destruction until no `Locked_ptr` is held to the object.
 172         */

 173        void lock_for_destruction()
 174        {
 175           /*
 176            * Loop through the list of weak pointers and invalidate them
 177            */

 178           while (true) {
 179  
 180              /*
 181               * To prevent dead-locks we always have to hold
 182               * the order of lock access, therefore we first
 183               * dequeue one weak pointer and free the list lock again
 184               */

 185              {
 186                 Lock::Guard guard(_list_lock);
 187                 _ptr_in_destruction = _list.first();
 188  
 189                 /* if the list is empty we`re done */
 190                 if (!_ptr_in_destruction) break;
 191                 _list.remove(_ptr_in_destruction);

 192              }

 193  
 194              {
 195                 Lock::Guard guard(_ptr_in_destruction->_lock);
 196                 _ptr_in_destruction->_obj = nullptr;
 197  
 198                 /*
 199                  * unblock a weak pointer that tried to disassociate
 200                  * in the meantime
 201                  */

 202                 _ptr_in_destruction->_destruct_lock.unlock();

 203              }

 204           }

 205  
 206           /*
 207            * synchronize with locked pointers that already aquired
 208            * the lock before the corresponding weak pointer got invalidated
 209            */

 210           _lock.lock();

 211        }

 212  
 213        /**
 214         * Inspection hook for unit test
 215         *
 216         * \noapi
 217         */

 218        void debug_info() const;

 219  }
;

 220  
 221  
 222  class Genode::Locked_ptr_base
 223  {
 224     protected:
 225  
 226        Weak_object_base *curr;
 227  
 228        /**
 229         * Constructor
 230         *
 231         * \noapi
 232         */

 233        inline Locked_ptr_base(Weak_ptr_base &weak_ptr);
 234  
 235        /**
 236         * Destructor
 237         *
 238         * \noapi
 239         */

 240        inline ~Locked_ptr_base();

 241  }
;

 242  
 243  
 244  /**
 245   * Weak pointer to a given type
 246   *
 247   * A weak pointer can be obtained from a weak object (an object that inherits
 248   * the `Weak_object` class template) and safely survives the lifetime of the
 249   * associated weak object. If the weak object disappears, all
 250   * weak pointers referring to the object are automatically invalidated.
 251   * To avoid race conditions between the destruction and use of a weak object,
 252   * a weak pointer cannot be de-reference directly. To access the object, a
 253   * weak pointer must be turned into a locked pointer (`Locked_ptr`).
 254   */

 255  template <typename T>
 256  struct Genode::Weak_ptr : Genode::Weak_ptr_base
 257  {
 258     /**
 259      * Default constructor creates invalid pointer
 260      */

 261     Weak_ptr() { }

 262  
 263     /**
 264      * Copy constructor
 265      */

 266     Weak_ptr(Weak_ptr<T> const &other) : Weak_ptr_base(other.obj()) { }

 267  
 268     /**
 269      * Assignment operator
 270      */

 271     inline void operator = (Weak_ptr<T> const &other)
 272     {
 273        *static_cast<Weak_ptr_base *>(this) = other;
 274     }

 275  }
;

 276  
 277  
 278  /**
 279   * Weak object
 280   *
 281   * This class template must be inherited in order to equip an object with
 282   * the weak-pointer mechanism.
 283   *
 284   * \param T  type of the derived class
 285   */

 286  template <typename T>
 287  struct Genode::Weak_object : Genode::Weak_object_base
 288  {
 289     /**
 290      * Obtain a weak pointer referring to the weak object
 291      */

 292     Weak_ptr<T> weak_ptr() { return _weak_ptr<T>(); }

 293  
 294     /**
 295      * Const version of `weak_ptr`
 296      *
 297      * This function is useful in cases where the returned weak pointer is
 298      * merely used for comparison operations.
 299      */

 300     Weak_ptr<const> const weak_ptr_const() const
 301     {
 302        /*
 303         * We strip off the constness of `this` to reuse the internal non-const
 304         * code of the weak object. The executed operations are known to not
 305         * alter the state of the weak object.
 306         */

 307        return const_cast<Weak_object *>(this)->_weak_ptr<const>();

 308     }

 309  }
;

 310  
 311  
 312  /**
 313   * Locked pointer
 314   *
 315   * A locked pointer is constructed from a weak pointer. After construction,
 316   * its validity can (and should) be checked by calling the `is_valid`
 317   * method. If the locked pointer is valid, the pointed-to object is known to
 318   * be locked until the locked pointer is destroyed. During this time, the
 319   * locked pointer can safely be de-referenced.
 320   *
 321   * The typical pattern of using a locked pointer is to declare it as a
 322   * local variable. Once the execution leaves the scope of the variable, the
 323   * locked pointer is destructed, which unlocks the pointed-to weak object.
 324   * It effectively serves as a lock guard.
 325   */

 326  template <typename T>
 327  struct Genode::Locked_ptr : Genode::Locked_ptr_base
 328  {
 329     Locked_ptr(Weak_ptr<T> &weak_ptr) : Locked_ptr_base(weak_ptr) { }
 330  
 331     *operator -> () { return static_cast<*>(curr); }
 332  
 333     &operator * () { return *static_cast<*>(curr); }
 334  
 335     /**
 336      * Returns true if the locked pointer is valid
 337      *
 338      * Only if valid, the locked pointer can be de-referenced. Otherwise,
 339      * the attempt will result in a null-pointer access.
 340      */

 341     bool is_valid() const { return curr != nullptr; }

 342  }
;

 343  
 344  
 345  /********************
 346   ** Implementation **
 347   ********************/

 348  
 349  void Genode::Weak_ptr_base::_adopt(Genode::Weak_object_base *obj)
 350  {
 351     if (!obj)
 352        return;

 353  
 354     _obj = obj;
 355  
 356     {
 357        Lock::Guard guard(_obj->_list_lock);
 358        _obj->_list.insert(this);
 359     }

 360  }

 361  
 362  
 363  void Genode::Weak_ptr_base::_disassociate()
 364  {
 365     /* defer destruction of object */
 366     try {
 367        Lock::Guard guard(_lock);
 368  
 369        if (_obj) _obj->disassociate(this);
 370     }
 catch(Weak_object_base::In_destruction&) {
 371        _destruct_lock.lock();
 372     }

 373  }

 374  
 375  
 376  Genode::Weak_ptr_base::Weak_ptr_base(Genode::Weak_object_base *obj)
 377  {
 378     _adopt(obj);
 379  }

 380  
 381  
 382  Genode::Weak_ptr_base::Weak_ptr_base() : _obj(nullptr) { }
 383  
 384  
 385  void Genode::Weak_ptr_base::operator = (Weak_ptr_base const &other)
 386  {
 387     /* self assignment */
 388     if (&other == this)
 389        return;

 390  
 391     _disassociate();
 392     {
 393        Lock::Guard guard(other._lock);
 394        _adopt(other._obj);
 395     }

 396  }

 397  
 398  
 399  bool Genode::Weak_ptr_base::operator == (Weak_ptr_base const &other) const
 400  {
 401     if (&other == this)
 402        return true;

 403  
 404     Lock::Guard guard_this(_lock), guard_other(other._lock);
 405  
 406     return (_obj == other._obj);

 407  }

 408  
 409  
 410  Genode::Weak_ptr_base::~Weak_ptr_base()
 411  {
 412     _disassociate();
 413  }

 414  
 415  
 416  template <typename T>
 417  Genode::Weak_ptr<T> Genode::Weak_object_base::_weak_ptr()
 418  {
 419     Weak_ptr_base result(this);
 420     return *static_cast<Weak_ptr<T> *>(&result);
 421  }

 422  
 423  
 424  Genode::Locked_ptr_base::Locked_ptr_base(Weak_ptr_base &weak_ptr)
 425  : curr(nullptr)
 426  {
 427     Lock::Guard guard(weak_ptr._lock);
 428  
 429     if (!weak_ptr.obj()) return;
 430  
 431     curr = weak_ptr.obj();
 432     curr->_lock.lock();

 433  }

 434  
 435  
 436  Genode::Locked_ptr_base::~Locked_ptr_base()
 437  {
 438     if (curr)
 439        curr->_lock.unlock();

 440  }

 441  
 442  #endif /* _INCLUDE__BASE__WEAK_PTR_H_ */