#ifndef lib_blk_h #define lib_blk_h /* Cesar project {{{ * * Copyright (C) 2007 Spidcom * * <<>> * * }}} */ /** * \file lib/blk.h * \brief 512 byte memory blocks. * \ingroup lib * * Block allocator * =============== * * This entity provide 512 byte memory blocks allocation and reference * counting. Each block counts the number of reference pointing to it. The * user is responsible for managing this counter using addref and release * functions. When the number of references of a block reach zero, the block * is freed. * * Each block is associated with a descriptor. This descriptor is 16 byte * long. The first 8 bytes are reserved for the blk_t type and the rest could * be used for anything the user wants. The type blk_t provide a chaining and * a pointer to data member. This is the basis for hardware blocks chaining. * * The API is available in two flavors. The first one works with descriptors. * The user can request one or more chained blocks and will be given pointers * to descriptors. The second one works directly with data, hiding the * descriptor to the user. In the second flavor, only one block can be * requested at a time, and performances can be lower as usage should be rare. * * An extra feature is provided for block allocated without a descriptor: * automatic destruction. In this case, the descriptor is used to store the * destructor function pointer. * * The reference counter associated with the descriptor. It is modified * atomically but once it reach zero reference, the block is freed * immediately. */ #include "lib/blame.h" /** A block is 512 bytes. */ #define BLK_SIZE 512 /** A block descriptor is 16 bytes, that is greater than \c blk_t. */ #define BLK_DESC_SIZE 16 /** Memory block descriptor. * This structure stores information about a 512 byte memory block. This * representation is shared between hardware and software. */ struct blk_t { /** Pointer to next descriptor. */ struct blk_t *next; /** Pointer to data. */ u8 *data; }; typedef struct blk_t blk_t; /** * Block destructor called just before the block memory is released. * \param data pointer to block data * * Destructor feature can only be used with block returned without a * descriptor as it is then used internally to store the destructor pointer. */ typedef void (*blk_destructor_t) (void *data); BEGIN_DECLS /** * Initialise the block allocator. */ void blk_init (void); /** * Return a newly allocated 512 byte block with its descriptor. * \return the descriptor pointer * * The \c next pointer in the block descriptor is undefined. */ blk_t * blk_alloc_desc_ (void_FL); #define blk_alloc_desc() blk_alloc_desc_ (_fL) /** * Return a number of newly allocated 512 byte blocks with their descriptors. * \param n number of block * \param last where to write the last block descriptor pointer * \return the first block descriptor * * The returned blocks descriptors are chained, the \c next pointer in the * last block descriptor is undefined. */ blk_t * blk_alloc_desc_range_ (uint n, blk_t **last __FL); #define blk_alloc_desc_range(n, last) blk_alloc_desc_range_ ((n), (last) __fL) /** * Add a reference to a block. * \param blk the block to reference */ void blk_addref_desc_ (blk_t *blk __FL); #define blk_addref_desc(blk) blk_addref_desc_ ((blk) __fL) /** * Add a reference to a list of blocks. * \param first first block to reference * \param last last block to reference */ void blk_addref_desc_range_ (blk_t *first, blk_t *last __FL); #define blk_addref_desc_range(first, last) \ blk_addref_desc_range_ ((first), (last) __fL) /** * Add a reference to a list of blocks, by number of blocks. * \param first first block to reference * \param n number of block */ void blk_addref_desc_range_nb_ (blk_t *first, uint n __FL); #define blk_addref_desc_range_nb(first, n) \ blk_addref_desc_range_nb_ ((first), (n) __fL) /** * Release a block reference. * \param blk the block to release */ void blk_release_desc_ (blk_t *blk __FL); #define blk_release_desc(blk) blk_release_desc_ ((blk) __fL) /** * Release references for a list of blocks. * \param first first block to release * \param last last block to release */ void blk_release_desc_range_ (blk_t *first, blk_t *last __FL); #define blk_release_desc_range(first, last) \ blk_release_desc_range_ ((first), (last) __fL) /** * Release references for a list of blocks, by number of blocks. * \param first first block to release * \param n number of block */ void blk_release_desc_range_nb_ (blk_t *first, uint n __FL); #define blk_release_desc_range_nb(first, n) \ blk_release_desc_range_nb_ ((first), (n) __fL) /** * Allocate a 512 byte block, without descriptor. * \return the newly allocated block */ void * blk_alloc_ (void_FL); #define blk_alloc() blk_alloc_ (_fL) /** * Allocate a zero'ed 512 byte block, without descriptor. * \return the newly allocated block */ void * blk_alloc_zero_ (void_FL); #define blk_alloc_zero() blk_alloc_zero_ (_fL) /** * Allocate a 512 byte block, and save the destructor. * \param destructor destructor function pointer * \return the newly allocated block */ void * blk_new_ (blk_destructor_t destructor __FL); #define blk_new(destructor) blk_new_ ((destructor) __fL) /** * Add a reference to a block without descriptor. * \param data pointer to block data */ void blk_addref_ (void *data __FL); #define blk_addref(data) blk_addref_ ((data) __fL) /** * Release a block reference and call the optional destructor if the block is * freed. * \param data pointer to block data */ void blk_release_ (void *data __FL); #define blk_release(data) blk_release_ ((data) __fL) /** * Check if all the blocks previously allocated are now free. * \return true if all blocks are free * * Check if the number of blocks freed is equals to the number of blocks * allocated and if the number of blocks released is equals to the number of * blocks referenced. */ bool blk_check_memory (void); /** * Print memory blocks informations. * * Print the number of blocks allocated, freed, referenced, and released. */ void blk_print_memory (void); /** * Querry blk when a huge number of blocks are needed. * \return true if possible, false otherwise. * * Each time a numerous quantity of blocks are needed to handle a stuff, this * function should be called. When the number of blocks reach a critical level * (not enough) this function will return false, the client should delay the * allocation request. Otherwise, the client can allocate the quantity of * blocks needed. * * The slack level is configurable with a CONFIG_BLK_SLACK = X in the Config * file. X is the minimum number of blocks under the one, the memory level * is considered as critical. */ bool blk_slack (void); END_DECLS #endif /* lib_blk_h */