1  /*
   2   * \brief  Slab allocator
   3   * \author Norman Feske
   4   * \date   2006-04-18
   5   */

   6  
   7  /*
   8   * Copyright (C) 2006-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__SLAB_H_
  15  #define _INCLUDE__BASE__SLAB_H_
  16  
  17  #include <base/allocator.h>
  18  #include <base/stdint.h>
  19  
  20  namespace Genode {
  21  
  22     class Slab;
  23     class Slab_block;
  24     class Slab_entry;
  25  }

  26  
  27  
  28  /**
  29   * A slab block holds an array of slab entries.
  30   */

  31  class Genode::Slab_block
  32  {
  33     public:
  34  
  35        Slab_block *next;  /* next block     */
  36        Slab_block *prev;  /* previous block */

  37  
  38     private:
  39  
  40        enum { FREE, USED };
  41  
  42        Slab    *_slab;    /* back reference to slab allocator */
  43        size_t   _avail;   /* free entries of this block       */
  44  
  45        /*
  46         * Each slab block consists of three areas, a fixed-size header
  47         * that contains the member variables declared above, a byte array
  48         * called state table that holds the allocation state for each slab
  49         * entry, and an area holding the actual slab entries. The number
  50         * of state-table elements corresponds to the maximum number of slab
  51         * entries per slab block (the `_num_elem` member variable of the
  52         * Slab allocator).
  53         */

  54  
  55        char _data[];  /* dynamic data (state table and slab entries) */
  56  
  57        /*
  58         * Caution! no member variables allowed below this line!
  59         */

  60  
  61        /**
  62         * Return the allocation state of a slab entry
  63         */

  64        inline bool state(int idx) { return _data[idx]; }

  65  
  66        /**
  67         * Set the allocation state of a slab entry
  68         */

  69        inline void state(int idx, bool state) { _data[idx] = state; }

  70  
  71        /**
  72         * Request address of slab entry by its index
  73         */

  74        Slab_entry *slab_entry(int idx);

  75  
  76        /**
  77         * Determine block index of specified slab entry
  78         */

  79        int slab_entry_idx(Slab_entry *e);

  80  
  81     public:
  82  
  83        /**
  84         * Constructor
  85         *
  86         * Normally, Slab_blocks are constructed by a Slab allocator
  87         * that specifies itself as constructor argument.
  88         */

  89        explicit Slab_block(Slab *= 0) { if (s) slab(s); }

  90  
  91        /**
  92         * Configure block to be managed by the specified slab allocator
  93         */

  94        void slab(Slab *slab);

  95  
  96        /**
  97         * Request number of available entries in block
  98         */

  99        unsigned avail() const { return _avail; }

 100  
 101        /**
 102         * Allocate slab entry from block
 103         */

 104        void *alloc();

 105  
 106        /**
 107         * Return a used slab block entry
 108         */

 109        Slab_entry *first_used_entry();

 110  
 111        /**
 112         * These functions are called by Slab_entry.
 113         */

 114        void inc_avail(Slab_entry *e);

 115        void dec_avail();
 116  
 117        /**
 118         * Debug and test hooks
 119         */

 120        void dump();

 121        int check_bounds();

 122  }
;

 123  
 124  
 125  class Genode::Slab_entry
 126  {
 127     private:
 128  
 129        Slab_block *_sb;
 130        char        _data[];
 131  
 132        /*
 133         * Caution! no member variables allowed below this line!
 134         */

 135  
 136     public:
 137  
 138        void init() { _sb = 0; }
 139  
 140        void occupy(Slab_block *sb)
 141        {
 142           _sb = sb;
 143           _sb->dec_avail();

 144        }

 145  
 146        void free()
 147        {
 148           _sb->inc_avail(this);
 149           _sb = 0;

 150        }

 151  
 152        void *addr() { return _data; }
 153  
 154        /**
 155         * Lookup Slab_entry by given address
 156         *
 157         * The specified address is supposed to point to _data[0].
 158         */

 159        static Slab_entry *slab_entry(void *addr) {
 160           return (Slab_entry *)((addr_t)addr - sizeof(Slab_entry)); }

 161  }
;

 162  
 163  
 164  /**
 165   * Slab allocator
 166   */

 167  class Genode::Slab : public Allocator
 168  {
 169     private:
 170  
 171        size_t      _slab_size;     /* size of one slab entry               */
 172        size_t      _block_size;    /* size of slab block                   */
 173        size_t      _num_elem;      /* number of slab entries per block     */
 174        Slab_block *_first_sb;      /* first slab block                     */
 175        Slab_block *_initial_sb;    /* initial (static) slab block          */
 176        bool        _alloc_state;   /* indicator for `currently in service` */
 177  
 178        Allocator *_backing_store;
 179  
 180        /**
 181         * Allocate and initialize new slab block
 182         */

 183        Slab_block *_new_slab_block();

 184  
 185     public:
 186  
 187        inline size_t slab_size()  const { return _slab_size;  }
 188        inline size_t block_size() const { return _block_size; }
 189        inline size_t num_elem()   const { return _num_elem;   }
 190        inline size_t entry_size() const { return sizeof(Slab_entry) + _slab_size; }
 191  
 192        /**
 193         * Constructor
 194         *
 195         * At construction time, there exists one initial slab
 196         * block that is used for the first couple of allocations,
 197         * especially for the allocation of the second slab
 198         * block.
 199         */

 200        Slab(size_t slab_size, size_t block_size, Slab_block *initial_sb,
 201             Allocator *backing_store = 0)
;

 202  
 203        /**
 204         * Destructor
 205         */

 206        ~Slab();

 207  
 208        /**
 209         * Debug function for dumping the current slab block list
 210         *
 211         * \noapi
 212         */

 213        void dump_sb_list();

 214  
 215        /**
 216         * Remove block from slab block list
 217         *
 218         * \noapi
 219         */

 220        void remove_sb(Slab_block *sb);

 221  
 222        /**
 223         * Insert block into slab block list
 224         *
 225         * \noapi
 226         */

 227        void insert_sb(Slab_block *sb, Slab_block *at = 0);

 228  
 229        /**
 230         * Free slab entry
 231         */

 232        static void free(void *addr);

 233  
 234        /**
 235         * Return a used slab element
 236         */

 237        void *first_used_elem();

 238  
 239        /**
 240         * Return true if number of free slab entries is higher than n
 241         */

 242        bool num_free_entries_higher_than(int n);

 243  
 244        /**
 245         * Define/request backing-store allocator
 246         *
 247         * \noapi
 248         */

 249        void backing_store(Allocator *bs) { _backing_store = bs; }

 250  
 251        /**
 252         * Request backing-store allocator
 253         *
 254         * \noapi
 255         */

 256        Allocator *backing_store() { return _backing_store; }

 257  
 258        /*************************
 259         ** Allocator interface **
 260         *************************/

 261  
 262        /**
 263         * Allocate slab entry
 264         *
 265         * The `size` parameter is ignored as only slab entries with
 266         * preconfigured slab-entry size are allocated.
 267         */

 268        bool   alloc(size_t size, void **addr) override;

 269        void   free(void *addr, size_t) override { free(addr); }
 270        size_t consumed() const override;
 271        size_t overhead(size_t) const override { return _block_size/_num_elem; }
 272        bool   need_size_for_free() const override { return false; }

 273  }
;

 274  
 275  #endif /* _INCLUDE__BASE__SLAB_H_ */