1  /*
   2   * \brief  A guard for arbitrary allocators to limit memory exhaustion
   3   * \author Stefan Kalkowski
   4   * \date   2010-08-20
   5   */

   6  
   7  /*
   8   * Copyright (C) 2010-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__ALLOCATOR_GUARD_H_
  15  #define _INCLUDE__BASE__ALLOCATOR_GUARD_H_
  16  
  17  #include <base/allocator.h>
  18  #include <base/printf.h>
  19  #include <base/stdint.h>
  20  
  21  namespace Genode { class Allocator_guard; }
  22  
  23  
  24  /**
  25   * This class acts as guard for arbitrary allocators to limit
  26   * memory exhaustion
  27   */

  28  class Genode::Allocator_guard : public Allocator
  29  {
  30     private:
  31  
  32        Allocator *_allocator;  /* allocator to guard */
  33        size_t     _amount;     /* total amount */
  34        size_t     _consumed;   /* already consumed bytes */

  35  
  36     public:
  37  
  38        Allocator_guard(Allocator *allocator, size_t amount)
  39        : _allocator(allocator), _amount(amount), _consumed(0) { }

  40  
  41        /**
  42         * Extend allocation limit
  43         */

  44        void upgrade(size_t additional_amount) {
  45           _amount += additional_amount; }

  46  
  47        /**
  48         * Consume bytes without actually allocating them
  49         */

  50        bool withdraw(size_t size)
  51        {
  52           if ((_amount - _consumed) < size)
  53              return false;

  54  
  55           _consumed += size;
  56           return true;

  57        }

  58  
  59        /*************************
  60         ** Allocator interface **
  61         *************************/

  62  
  63        /**
  64         * Allocate block
  65         *
  66         * \param size      block size to allocate
  67         * \param out_addr  resulting pointer to the new block,
  68         *                  undefined in the error case
  69         * \return          true on success
  70         */

  71        bool alloc(size_t size, void **out_addr) override
  72        {
  73           if ((_amount - _consumed) < (size + _allocator->overhead(size))) {
  74              PWRN("Quota exceeded! amount=%zu, size=%zu, consumed=%zu",
  75                   _amount, (size + _allocator->overhead(size)), _consumed)
;

  76              return false;

  77           }

  78           bool b = _allocator->alloc(size, out_addr);
  79           if (b)
  80              _consumed += size + _allocator->overhead(size);

  81           return b;

  82        }

  83  
  84        /**
  85         * Free block a previously allocated block
  86         */

  87        void free(void *addr, size_t size) override
  88        {
  89           _allocator->free(addr, size);
  90           _consumed -= size + _allocator->overhead(size);

  91        }

  92  
  93        /**
  94         * Return amount of backing store consumed by the allocator
  95         */

  96        size_t consumed() const override { return _consumed; }

  97  
  98        /**
  99         * Return allocation limit
 100         */

 101        size_t quota() const { return _amount; }

 102  
 103        /**
 104         * Return meta-data overhead per block
 105         */

 106        size_t overhead(size_t size) const override { return _allocator->overhead(size); }

 107  
 108        bool need_size_for_free() const override {
 109           return _allocator->need_size_for_free(); }

 110  }
;

 111  
 112  #endif /* _INCLUDE__BASE__ALLOCATOR_GUARD_H_ */