MemoryPool implemented
This commit is contained in:
parent
1d80cebbce
commit
4f13160f52
139
memory_pool.c
139
memory_pool.c
@ -2,4 +2,143 @@
|
||||
// Created by epagris on 2022.10.20..
|
||||
//
|
||||
|
||||
#include <stdbool.h>
|
||||
#include "memory_pool.h"
|
||||
#include "utils.h"
|
||||
|
||||
MP *mp_init(uint8_t *p, uint32_t size) {
|
||||
ASSERT_BAD_ALIGN(p); // check for alignment
|
||||
MP *pool = (MP *) p; // fill in properties
|
||||
pool->p = p + sizeof(MP); // compute beginning of the allocatable area
|
||||
pool->poolSize = size; // save total pool size
|
||||
pool->blockRegistry = (MPAllocRecord *) ALIGN((p + size - sizeof(MPAllocRecord)), uint32_t); // determine block registry address
|
||||
pool->freeSpace = ((uint8_t *) pool->blockRegistry) - pool->p - sizeof(MPAllocRecord); // calculate free space size
|
||||
|
||||
// place sentry element
|
||||
pool->blockRegistry[-1].addrStart = 0;
|
||||
pool->blockRegistry[-1].size = 0;
|
||||
pool->blockRegistry[-1].type = MPRT_SENTRY;
|
||||
|
||||
// place element record holding info on the single, undivided, unallocated block
|
||||
pool->blockRegistry[0].addrStart = pool->p;
|
||||
pool->blockRegistry[0].size = pool->freeSpace;
|
||||
pool->blockRegistry[0].type = MPRT_FREE;
|
||||
|
||||
pool->blockRecCnt = 2; // sentry and free block
|
||||
|
||||
return pool;
|
||||
}
|
||||
|
||||
uint8_t *mp_alloc(MP *mp, uint32_t size) {
|
||||
// make the allocation from the beginning of the smallest suitable (large enough)
|
||||
// contiguous block
|
||||
|
||||
// round size to make it divisible by 4
|
||||
size = ALIGN(size, uint32_t);
|
||||
|
||||
// badness = area left free on the candidate free block after allocating the requested block
|
||||
MPAllocRecord *bestBlock = NULL;
|
||||
uint32_t leastBadness = ~0;
|
||||
MPAllocRecord *recIter = mp->blockRegistry; // allocation record
|
||||
while (recIter->type != MPRT_SENTRY && leastBadness > 0) { // at badness = 0 just break, since it's a perfectly fitting block
|
||||
// look for suitable free block
|
||||
if (recIter->type == MPRT_FREE && recIter->size > size) {
|
||||
uint32_t iterBadness = recIter->size - size;
|
||||
if (iterBadness < leastBadness) { // calculate badness
|
||||
bestBlock = recIter;
|
||||
leastBadness = recIter->size - size;
|
||||
}
|
||||
}
|
||||
recIter--; // step to next block
|
||||
}
|
||||
|
||||
// allocate block
|
||||
uint8_t * ptr = NULL;
|
||||
if (leastBadness == 0) { // just change block registry type if block perfectly fits
|
||||
bestBlock->type = MPRT_ALLOCATED;
|
||||
ptr = bestBlock->addrStart;
|
||||
} else { // if there are some bytes left between allocated blocks
|
||||
// shift the registry below best block
|
||||
MPAllocRecord *rec = mp->blockRegistry - (mp->blockRecCnt + 1); // bottom of the registry
|
||||
while (rec != bestBlock) {
|
||||
*(rec) = *(rec + 1);
|
||||
rec++;
|
||||
}
|
||||
|
||||
// store information on allocated block
|
||||
MPAllocRecord *allocated = bestBlock - 1;
|
||||
allocated->type = MPRT_ALLOCATED;
|
||||
allocated->size = size;
|
||||
allocated->addrStart = bestBlock->addrStart;
|
||||
ptr = allocated->addrStart;
|
||||
|
||||
// shrink the remaining free block size
|
||||
bestBlock->size -= size;
|
||||
bestBlock->addrStart += size;
|
||||
|
||||
// decrease free size with the increase in the registry size
|
||||
mp->freeSpace -= sizeof(MPAllocRecord);
|
||||
|
||||
// increase record count
|
||||
mp->blockRecCnt++;
|
||||
}
|
||||
|
||||
// decrease free space size with the allocated block size
|
||||
mp->freeSpace -= size;
|
||||
|
||||
return ptr;
|
||||
}
|
||||
|
||||
// join adjacent free blocks
|
||||
static void mp_join_free_blocks(MP *mp) {
|
||||
MPAllocRecord *recIter = mp->blockRegistry;
|
||||
while (recIter->type != MPRT_SENTRY) {
|
||||
if (recIter->type == MPRT_FREE && (recIter - 1)->type == MPRT_FREE) { // if two adjacent free blocks have been found...
|
||||
// join the blocks
|
||||
recIter->size += (recIter - 1)->size;
|
||||
recIter->addrStart = (recIter - 1)->addrStart;
|
||||
|
||||
// shift block below joined blocks one upper
|
||||
MPAllocRecord *joinIter = (recIter - 1);
|
||||
while (joinIter->type != MPRT_SENTRY) {
|
||||
*joinIter = *(joinIter - 1);
|
||||
joinIter--;
|
||||
}
|
||||
mp->freeSpace += sizeof(MPAllocRecord);
|
||||
} else {
|
||||
recIter--;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void mp_free(MP *mp, const uint8_t *p) {
|
||||
// look for registry record
|
||||
bool success = false;
|
||||
MPAllocRecord *recIter = mp->blockRegistry;
|
||||
while (recIter->type != MPRT_SENTRY) {
|
||||
if ((recIter->type == MPRT_ALLOCATED) &&
|
||||
((recIter->addrStart <= p) && ((recIter->addrStart + recIter->size) > p))) { // ...block found
|
||||
recIter->type = MPRT_FREE;
|
||||
success = true;
|
||||
break;
|
||||
}
|
||||
recIter--;
|
||||
}
|
||||
|
||||
if (success) {
|
||||
mp_join_free_blocks(mp);
|
||||
}
|
||||
}
|
||||
|
||||
void mp_report(MP *mp) {
|
||||
INFO("# TYPE BEGIN SIZE\n");
|
||||
MPAllocRecord *recIter = mp->blockRegistry;
|
||||
uint32_t bi = 0;
|
||||
while (recIter->type != MPRT_SENTRY) {
|
||||
INFO("%05u %s %p %u\n", bi, recIter->type == MPRT_ALLOCATED ? "ALLOC " : "FREE ",
|
||||
recIter->addrStart, recIter->size);
|
||||
recIter--;
|
||||
bi++;
|
||||
}
|
||||
INFO("\n");
|
||||
}
|
@ -5,56 +5,75 @@
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
/**
|
||||
* Record type
|
||||
*/
|
||||
typedef enum {
|
||||
MPRT_FREE = 0,
|
||||
MPRT_ALLOCATED = 1,
|
||||
MPRT_SENTRY = ~0
|
||||
} MPRecordtype;
|
||||
|
||||
/**
|
||||
* Record in the allocation registry.
|
||||
*/
|
||||
typedef struct {
|
||||
uint8_t * addrStart; ///< Starting address of allocated memory block.
|
||||
uint32_t size; ///< Size of allocated block.
|
||||
MPRecordtype type; ///< Type of block
|
||||
} MPAllocRecord;
|
||||
|
||||
/**
|
||||
* Memory pool state structure.
|
||||
*/
|
||||
typedef struct {
|
||||
uint8_t * p; ///< Pointer to contiguous memory block the pool operates on.
|
||||
uint32_t totalSize; ///< Total size of the memory pool.
|
||||
uint32_t blockSize; ///< Single block size.
|
||||
uint8_t * blockRegistry; ///< Bitfield array in which block allocations are maintained.
|
||||
uint32_t totalBlocks; ///< Total number of blocks.
|
||||
uint32_t freeBlocks; ///< Number of free blocks.
|
||||
} MemoryPool;
|
||||
uint32_t poolSize; ///< Total size of the memory pool.
|
||||
MPAllocRecord * blockRegistry; ///< Array in which block allocations are maintained.
|
||||
uint32_t blockRecCnt; ///< Number of block records (including sentry!)
|
||||
uint32_t freeSpace; ///< Free memory size.
|
||||
} MP;
|
||||
|
||||
/**
|
||||
* Header inserted at the beginning of each block when allocated. Blocks can
|
||||
* be forward-chained with this structure used as singly-linked list elements.
|
||||
*/
|
||||
typedef struct MemoryPoolBlockHeader_ {
|
||||
struct MemoryPoolBlockHeader_ * next; ///< Next block in the chain. Zero if chain's last block.
|
||||
uint8_t * block; ///< Pointer to the data block.
|
||||
} MemoryPoolBlockHeader;
|
||||
|
||||
/**
|
||||
* Block chain header placed after the first memory block's header.
|
||||
* Contains fast-accessable information about the full chain.
|
||||
*/
|
||||
typedef struct MemoryPoolBlockChainHead_ {
|
||||
uint32_t totalChainSize; ///< Total memory size allocated in the full chain.
|
||||
uint16_t chainCntr; ///< Number of chain elements linked together.
|
||||
uint16_t _spaceholder;
|
||||
} MemoryPoolBlockChainHead;
|
||||
|
||||
/**
|
||||
* Initialize a new memory pool. MemoryPool object is allocated at the beginning of the given
|
||||
* Initialize a new memory pool. MP object is allocated at the beginning of the given
|
||||
* area (p).
|
||||
*
|
||||
* Memory structure:
|
||||
*
|
||||
* p -> -------------
|
||||
* MP object
|
||||
* ------------------
|
||||
* allocatable area
|
||||
* ------------------
|
||||
* block registry
|
||||
* p + size -> ------
|
||||
*
|
||||
* @param p memory block the pool is based on
|
||||
* @param blockSize allocation block size
|
||||
* @param blockCnt number of available blocks
|
||||
* @return Pointer to the MemoryPool object handling the newly allocated memory pool, or NULL
|
||||
* @param size pool size
|
||||
* @return Pointer to the MP object handling the newly allocated memory pool, or NULL
|
||||
* on failure.
|
||||
*/
|
||||
MemoryPool * mp_init(uint8_t * p, uint32_t blockSize, uint32_t blockCnt);
|
||||
MP * mp_init(uint8_t * p, uint32_t size);
|
||||
|
||||
/**
|
||||
* Allocate a memory block chain from memory pool.
|
||||
* @param mp memory pool the allocation is made from
|
||||
* @param size requested memory size
|
||||
* @return pointer to head of allocated memory block chain or NULL on failure
|
||||
* @return beginning of the allocated area or NULL on failure
|
||||
*/
|
||||
MemoryPoolBlockHeader * mp_alloc(MemoryPool * mp, uint32_t size);
|
||||
uint8_t * mp_alloc(MP * mp, uint32_t size);
|
||||
|
||||
void mp_free(MemoryPool * mp, MemoryPoolBlockHeader )
|
||||
/**
|
||||
* Release a chain of memory blocks.
|
||||
* @param mp Memory block on which the allocation happened earlier.
|
||||
* @param mpbh Beginning of allocated memory block to free.
|
||||
*/
|
||||
void mp_free(MP * mp, const uint8_t * p);
|
||||
|
||||
/**
|
||||
* Create report on memory allocations.
|
||||
* @param mp Memory pool
|
||||
*/
|
||||
void mp_report(MP * mp);
|
||||
|
||||
#endif //ETHERLIB_MEMORY_POOL_H
|
||||
|
@ -1,6 +1,6 @@
|
||||
#ifndef ETHERLIB_PACKET_INPUT_H
|
||||
#define ETHERLIB_PACKET_INPUT_H
|
||||
|
||||
void input_packet()
|
||||
void input_packet();
|
||||
|
||||
#endif //ETHERLIB_PACKET_INPUT_H
|
||||
|
@ -40,12 +40,15 @@ typedef int (*PcktProcFn)(const uint8_t *pHdr, uint32_t size, uint8_t *pProps);
|
||||
* @struct PcktTypeDesc
|
||||
* Pckt type descriptor. Pckt parsers can be registered
|
||||
* using PcktTypeDesc assignments.
|
||||
*
|
||||
*/
|
||||
typedef struct {
|
||||
uint16_t type; ///< Type identification the packet (unique!)
|
||||
uint16_t type; ///< Type identification of the packet 'class' (unique!)
|
||||
uint16_t containerType; ///< Type of container packet packet (e.g.: IPv4 in case of UDP)
|
||||
PcktProcFn procFun; ///< Pckt processing function
|
||||
} PcktTypeDesc;
|
||||
|
||||
// ---------------------
|
||||
|
||||
|
||||
|
||||
#endif //ETHERLIB_PACKET_REGISTRY_H
|
5
utils.c
Normal file
5
utils.c
Normal file
@ -0,0 +1,5 @@
|
||||
//
|
||||
// Created by epagris on 2022.10.31..
|
||||
//
|
||||
|
||||
#include "utils.h"
|
16
utils.h
Normal file
16
utils.h
Normal file
@ -0,0 +1,16 @@
|
||||
//
|
||||
// Created by epagris on 2022.10.31..
|
||||
//
|
||||
|
||||
#ifndef ETHERLIB_UTILS_H
|
||||
#define ETHERLIB_UTILS_H
|
||||
|
||||
#include <stdio.h>
|
||||
|
||||
#define ERROR(...) printf(__VA_ARGS__)
|
||||
#define INFO(...) printf(__VA_ARGS__)
|
||||
|
||||
#define ASSERT_BAD_ALIGN(p) if ((size_t)(p) & 0b11) ERROR("Bad memory alignment in function '%s' in file '%s' on line %d!\n", __func__, __FILE__, __LINE__)
|
||||
#define ALIGN(p,t) (((size_t)(p) + (sizeof(t) - 1)) & ~(sizeof(t) - 1))
|
||||
|
||||
#endif //ETHERLIB_UTILS_H
|
Loading…
x
Reference in New Issue
Block a user