1  /*
   2   * \brief  Lock-guarded allocator interface
   3   * \author Norman Feske
   4   * \date   2008-08-05
   5   */

   6  
   7  /*
   8   * Copyright (C) 2008-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__SYNC_ALLOCATOR_H_
  15  #define _INCLUDE__BASE__SYNC_ALLOCATOR_H_
  16  
  17  #include <base/allocator.h>
  18  #include <base/lock.h>
  19  
  20  namespace Genode {
  21     
  22     template <typename> class Synchronized_allocator;
  23     template <typename> class Synchronized_range_allocator;
  24  }

  25  
  26  
  27  /**
  28   * Lock-guarded allocator
  29   *
  30   * This class wraps the complete `Allocator` interface while
  31   * preventing concurrent calls to the wrapped allocator implementation.
  32   *
  33   * \param ALLOCATOR_IMPL  class implementing the `Allocator`
  34   *                        interface
  35   */

  36  template <typename ALLOCATOR_IMPL>
  37  class Genode::Synchronized_allocator : public Allocator
  38  {
  39     private:
  40  
  41        Lock            _default_lock;
  42        Lock           *_lock;
  43        ALLOCATOR_IMPL _alloc;

  44  
  45     public:
  46  
  47        /**
  48         * Constructor
  49         *
  50         * This constructor uses an embedded lock for synchronizing the
  51         * access to the allocator.
  52         */

  53        Synchronized_allocator()
  54        : _lock(&_default_lock) { }

  55  
  56        /**
  57         * Constructor
  58         *
  59         * This constructor uses an embedded lock for synchronizing the
  60         * access to the allocator.
  61         */

  62        explicit Synchronized_allocator(Allocator *metadata_alloc)
  63        : _lock(&_default_lock), _alloc(metadata_alloc) { }

  64  
  65        /**
  66         * Return reference to wrapped (non-thread-safe) allocator
  67         *
  68         * This is needed, for example, if the wrapped allocator implements
  69         * methods in addition to the Range_allocator interface.
  70         */

  71        ALLOCATOR_IMPL *raw() { return &_alloc; }

  72  
  73        /*************************
  74         ** Allocator interface **
  75         *************************/

  76  
  77        bool alloc(size_t size, void **out_addr) override
  78        {
  79           Lock::Guard lock_guard(*_lock);
  80           return _alloc.alloc(size, out_addr);
  81        }

  82  
  83        void free(void *addr, size_t size) override
  84        {
  85           Lock::Guard lock_guard(*_lock);
  86           _alloc.free(addr, size);
  87        }

  88  
  89        size_t consumed() const override
  90        {
  91           Lock::Guard lock_guard(*_lock);
  92           return _alloc.consumed();
  93        }

  94  
  95        size_t overhead(size_t size) const override
  96        {
  97           Lock::Guard lock_guard(*_lock);
  98           return _alloc.overhead(size);
  99        }

 100  
 101        bool need_size_for_free() const override
 102        {
 103           Lock::Guard lock_guard(*_lock);
 104           return _alloc.need_size_for_free();
 105        }

 106  }
;

 107  
 108  
 109  /**
 110   * Lock-guarded range allocator
 111   *
 112   * This class wraps the complete `Range_allocator` interface while
 113   * preventing concurrent calls to the wrapped allocator implementation.
 114   *
 115   * \param ALLOCATOR_IMPL  class implementing the `Range_allocator`
 116   *                        interface
 117   */

 118  template <typename ALLOCATOR_IMPL>
 119  class Genode::Synchronized_range_allocator : public Range_allocator
 120  {
 121     private:
 122  
 123        Lock           _default_lock;
 124        Lock          *_lock;
 125        ALLOCATOR_IMPL _alloc;

 126  
 127     public:
 128  
 129        /**
 130         * Constructor
 131         *
 132         * This constructor uses an embedded lock for synchronizing the
 133         * access to the allocator.
 134         */

 135        Synchronized_range_allocator()
 136        : _lock(&_default_lock) { }

 137  
 138        /**
 139         * Constructor
 140         *
 141         * This constructor uses an embedded lock for synchronizing the
 142         * access to the allocator.
 143         */

 144        explicit Synchronized_range_allocator(Allocator *metadata_alloc)
 145        : _lock(&_default_lock), _alloc(metadata_alloc) { }

 146  
 147        /**
 148         * Constructor
 149         *
 150         * \param lock  use specified lock rather then an embedded lock for
 151         *              synchronization
 152         *
 153         * This constructor is useful if multiple allocators must be
 154         * synchronized with each other. In such as case, the shared
 155         * lock can be passed to each `Synchronized_range_allocator`
 156         * instance.
 157         */

 158        Synchronized_range_allocator(Lock *lock, Allocator *metadata_alloc)
 159        : _lock(lock), _alloc(metadata_alloc) { }

 160  
 161        /**
 162         * Return reference to wrapped (non-thread-safe) allocator
 163         *
 164         * This is needed, for example, if the wrapped allocator implements
 165         * methods in addition to the Range_allocator interface.
 166         *
 167         * NOTE: Synchronize accesses to the raw allocator by facilitating
 168         * the lock() method.
 169         */

 170        ALLOCATOR_IMPL *raw() { return &_alloc; }

 171  
 172        /**
 173         * Return reference to synchronization lock
 174         */

 175        Lock *lock() { return _lock; }

 176  
 177  
 178        /*************************
 179         ** Allocator interface **
 180         *************************/

 181  
 182        bool alloc(size_t size, void **out_addr) override
 183        {
 184           Lock::Guard lock_guard(*_lock);
 185           return _alloc.alloc(size, out_addr);
 186        }

 187  
 188        void free(void *addr, size_t size) override
 189        {
 190           Lock::Guard lock_guard(*_lock);
 191           _alloc.free(addr, size);
 192        }

 193  
 194        size_t consumed() const override
 195        {
 196           Lock::Guard lock_guard(*_lock);
 197           return _alloc.consumed();
 198        }

 199  
 200        size_t overhead(size_t size) const override
 201        {
 202           Lock::Guard lock_guard(*_lock);
 203           return _alloc.overhead(size);
 204        }

 205  
 206        bool need_size_for_free() const override
 207        {
 208           Lock::Guard lock_guard(*_lock);
 209           return _alloc.need_size_for_free();
 210        }

 211  
 212  
 213        /*******************************
 214         ** Range-allocator interface **
 215         *******************************/

 216  
 217        int add_range(addr_t base, size_t size) override
 218        {
 219           Lock::Guard lock_guard(*_lock);
 220           return _alloc.add_range(base, size);
 221        }

 222  
 223        int remove_range(addr_t base, size_t size) override
 224        {
 225           Lock::Guard lock_guard(*_lock);
 226           return _alloc.remove_range(base, size);
 227        }

 228  
 229        Alloc_return alloc_aligned(size_t size, void **out_addr, int align = 0,
 230                                   addr_t from = 0, addr_t to = ~0UL)
 override
 231        {
 232           Lock::Guard lock_guard(*_lock);
 233           return _alloc.alloc_aligned(size, out_addr, align, from, to);
 234        }

 235  
 236        Alloc_return alloc_addr(size_t size, addr_t addr) override
 237        {
 238           Lock::Guard lock_guard(*_lock);
 239           return _alloc.alloc_addr(size, addr);
 240        }

 241  
 242        void free(void *addr) override
 243        {
 244           Lock::Guard lock_guard(*_lock);
 245           _alloc.free(addr);
 246        }

 247  
 248        size_t avail() const override
 249        {
 250           Lock::Guard lock_guard(*_lock);
 251           return _alloc.avail();
 252        }

 253  
 254        bool valid_addr(addr_t addr) const override
 255        {
 256           Lock::Guard lock_guard(*_lock);
 257           return _alloc.valid_addr(addr);
 258        }

 259  }
;

 260  
 261  #endif /* _INCLUDE__BASE__SYNC_ALLOCATOR_H_ */