Skip to content
Snippets Groups Projects
Unverified Commit 747b11d9 authored by Gaëtan Harter's avatar Gaëtan Harter Committed by GitHub
Browse files

Merge pull request #7651 from tobhe/memarray

Generic memory block allocator
parents 644576d9 62ca3d36
No related branches found
No related tags found
No related merge requests found
/*
* Copyright (C) 2018 Tobias Heider <heidert@nm.ifi.lmu.de>
*
* This file is subject to the terms and conditions of the GNU Lesser
* General Public License v2.1. See the file LICENSE in the top level
* directory for more details.
*/
/**
* @defgroup sys_memarray memory array allocator
* @ingroup sys
* @brief memory array allocator
* @{
*
* @brief pseudo dynamic allocation in static memory arrays
* @author Tobias Heider <heidert@nm.ifi.lmu.de>
*/
#ifndef MEMARRAY_H
#define MEMARRAY_H
#include <stdint.h>
#include <stdlib.h>
#ifdef __cplusplus
extern "C" {
#endif
/**
* @brief Memory pool
*/
typedef struct {
void *free_data; /**< memory pool data / head of the free list */
size_t size; /**< size of single list element */
size_t num; /**< max number of elements in list */
} memarray_t;
/**
* @brief Initialize memarray pool with free list
*
* @pre `mem != NULL`
* @pre `data != NULL`
* @pre `size >= sizeof(void*)`
* @pre `num != 0`
*
* @param[in,out] mem memarray pool to initialize
* @param[in] data pointer to user-allocated data
* @param[in] size size of a single element in data
* @param[in] num number of elements in data
*/
void memarray_init(memarray_t *mem, void *data, size_t size, size_t num);
/**
* @brief Allocate memory chunk in memarray pool
*
* @pre `mem != NULL`
*
* @param[in,out] mem memarray pool to allocate block in
*
* @return pointer to allocated structure, if enough memory was available
* @return NULL, on failure
*/
void *memarray_alloc(memarray_t *mem);
/**
* @brief Free memory chunk in memarray pool
*
* @pre `mem != NULL`
* @pre `ptr != NULL`
*
* @param[in,out] mem memarray pool to free block in
* @param[in] ptr pointer to memarray chunk
*/
void memarray_free(memarray_t *mem, void *ptr);
#ifdef __cplusplus
}
#endif
#endif /* MEMARRAY_H */
/**
* @}
*/
include $(RIOTBASE)/Makefile.base
/*
* Copyright (C) 2018 Tobias Heider <heidert@nm.ifi.lmu.de>
*
* This file is subject to the terms and conditions of the GNU Lesser
* General Public License v2.1. See the file LICENSE in the top level
* directory for more details.
*/
#include <string.h>
#include "memarray.h"
#define ENABLE_DEBUG (0)
#include "debug.h"
void memarray_init(memarray_t *mem, void *data, size_t size, size_t num)
{
assert((mem != NULL) && (data != NULL) && (size >= sizeof(void *)) &&
(num != 0));
DEBUG("memarray: Initialize memarray of %u times %u Bytes at %p\n",
(unsigned)num, (unsigned)size, data);
mem->free_data = data;
mem->size = size;
mem->num = num;
for (size_t i = 0; i < (mem->num - 1); i++) {
void *next = ((char *)mem->free_data) + ((i + 1) * mem->size);
memcpy(((char *)mem->free_data) + (i * mem->size), &next, sizeof(void *));
}
}
void *memarray_alloc(memarray_t *mem)
{
assert(mem != NULL);
if (mem->free_data == NULL) {
return NULL;
}
void *free = mem->free_data;
mem->free_data = *((void **)mem->free_data);
DEBUG("memarray: Allocate %u Bytes at %p\n", (unsigned)mem->size, free);
return free;
}
void memarray_free(memarray_t *mem, void *ptr)
{
assert((mem != NULL) && (ptr != NULL));
memcpy(ptr, &mem->free_data, sizeof(void *));
mem->free_data = ptr;
DEBUG("memarray: Free %u Bytes at %p\n", (unsigned)mem->size, ptr);
}
include ../Makefile.tests_common
USEMODULE += memarray
# Used for invoking _ps_handler
USEMODULE += shell_commands
USEMODULE += ps
include $(RIOTBASE)/Makefile.include
Expected result
===============
This application should run a number of tests equal to NUMBER_OF_TESTS (Default 12).
At the beginning of the tests memory usage of each thread is printed.
At the end of the tests, the threads memory usage is printed once more time.
This test is passed if the memory used by the main thread remains static.
Background
==========
The module `memarray` is the fixed-size block allocator for RIOT-OS.
This test application is therefore specialized for only testing the use of the module.
This is also inspired by `test/malloc`.
/*
* Copyright (C) 2018 Inria
*
* This file is subject to the terms and conditions of the GNU Lesser
* General Public License v2.1. See the file LICENSE in the top level
* directory for more details.
*/
/**
* @ingroup tests
* @{
*
* @file
* @brief Simple memarray module tests
*
* @author Tobias Heider <heidert@nm.ifi.lmu.de>
* @author Raul Fuentes <raul.fuentes-samaniego@inria.fr>
*
* @}
*/
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "memarray.h"
#define MAX_NUMBER_BLOCKS (10)
#define MESSAGE_SIZE (8U)
#define NUMBER_OF_TESTS (12)
extern int _ps_handler(int argc, char **argv);
struct block_t {
struct node *next;
int number;
/* static size for the components */
unsigned char message[MESSAGE_SIZE];
};
struct block_t block_storage_data[MAX_NUMBER_BLOCKS];
memarray_t block_storage;
int total = 0;
static void memory_block_init(void)
{
memarray_init(&block_storage, block_storage_data, sizeof(struct block_t), MAX_NUMBER_BLOCKS);
}
void fill_memory(struct block_t *head)
{
int aux = 0;
while ((aux < MAX_NUMBER_BLOCKS) && (head)) {
memset(head->message, '@', MESSAGE_SIZE - 1);
head->message[MESSAGE_SIZE - 1] = 0;
head->number = aux;
printf("\t(%i, %s) Allocated %u Bytes at %p, total %d\n",
head->number, head->message, (unsigned)sizeof(struct block_t),
(void *)head, total);
/* NOTE: If there is not space, memarray_alloc returns zero */
head->next = memarray_alloc(&block_storage);
head = (struct block_t *)head->next;
total += sizeof(struct block_t);
aux++;
}
}
void free_memory(struct block_t *head)
{
struct block_t *old;
while (head) {
total -= sizeof(struct block_t);
printf("\tFree (%i) %u Bytes at %p, total %d\n", \
head->number, (unsigned)sizeof(struct block_t),
(void *)head, total);
if (head->next) {
old = head;
head = (struct block_t *) head->next;
memarray_free(&block_storage, old);
}
else {
memarray_free(&block_storage, head);
head = 0;
}
}
}
int main(void)
{
memory_block_init();
int count = 0;
printf("Starting (%d, %u)\n", MAX_NUMBER_BLOCKS, MESSAGE_SIZE);
_ps_handler(0, NULL);
while (count < NUMBER_OF_TESTS) {
struct block_t *head = (struct block_t *) memarray_alloc(&block_storage);
printf("TEST #%i:\n", count + 1 );
fill_memory(head);
free_memory(head);
count++;
}
printf("Finishing\n");
_ps_handler(0, NULL);
return 0;
}
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Please register or to comment