mirror of
https://github.com/MaJerle/lwmem.git
synced 2025-01-26 06:02:54 +08:00
Merge branch 'develop'
This commit is contained in:
commit
0f79742628
@ -16,14 +16,14 @@ AlignConsecutiveBitFields:
|
||||
AlignConsecutiveDeclarations: None
|
||||
AlignEscapedNewlines: Right
|
||||
AlignOperands: Align
|
||||
SortIncludes: false
|
||||
SortIncludes: true
|
||||
InsertBraces: true # Control statements must have curly brackets
|
||||
AlignTrailingComments: true
|
||||
AllowAllArgumentsOnNextLine: true
|
||||
AllowAllParametersOfDeclarationOnNextLine: true
|
||||
AllowShortEnumsOnASingleLine: true
|
||||
AllowShortBlocksOnASingleLine: Empty
|
||||
AllowShortCaseLabelsOnASingleLine: false
|
||||
AllowShortCaseLabelsOnASingleLine: true
|
||||
AllowShortFunctionsOnASingleLine: All
|
||||
AllowShortLambdasOnASingleLine: All
|
||||
AllowShortIfStatementsOnASingleLine: Never
|
||||
|
19
.clang-tidy
Normal file
19
.clang-tidy
Normal file
@ -0,0 +1,19 @@
|
||||
---
|
||||
Checks: "*,
|
||||
-abseil-*,
|
||||
-altera-*,
|
||||
-android-*,
|
||||
-fuchsia-*,
|
||||
-google-*,
|
||||
-llvm*,
|
||||
-modernize-use-trailing-return-type,
|
||||
-zircon-*,
|
||||
-readability-else-after-return,
|
||||
-readability-static-accessed-through-instance,
|
||||
-readability-avoid-const-params-in-decls,
|
||||
-cppcoreguidelines-non-private-member-variables-in-classes,
|
||||
-misc-non-private-member-variables-in-classes,
|
||||
"
|
||||
WarningsAsErrors: ''
|
||||
HeaderFilterRegex: ''
|
||||
FormatStyle: none
|
18
.readthedocs.yaml
Normal file
18
.readthedocs.yaml
Normal file
@ -0,0 +1,18 @@
|
||||
version: 2
|
||||
build:
|
||||
os: ubuntu-22.04
|
||||
tools:
|
||||
python: "3.11"
|
||||
|
||||
# Build documentation in the docs/ directory with Sphinx
|
||||
sphinx:
|
||||
configuration: docs/conf.py
|
||||
|
||||
# Python configuration
|
||||
python:
|
||||
install:
|
||||
- requirements: docs/requirements.txt
|
||||
|
||||
formats:
|
||||
- pdf
|
||||
- epub
|
9
.vscode/settings.json
vendored
9
.vscode/settings.json
vendored
@ -4,7 +4,14 @@
|
||||
"lwevt_type.h": "c",
|
||||
"lwevt.h": "c",
|
||||
"string.h": "c",
|
||||
"lwevt_opt.h": "c"
|
||||
"lwevt_opt.h": "c",
|
||||
"streambuf": "c",
|
||||
"lwmem.h": "c",
|
||||
"lwmem_opt.h": "c",
|
||||
"array": "c",
|
||||
"string_view": "c",
|
||||
"initializer_list": "c",
|
||||
"limits.h": "c"
|
||||
},
|
||||
"esbonio.sphinx.confDir": ""
|
||||
}
|
2
.vscode/tasks.json
vendored
2
.vscode/tasks.json
vendored
@ -1,5 +1,5 @@
|
||||
{
|
||||
"version": "2.1.0",
|
||||
"version": "2.0.0",
|
||||
"tasks": [
|
||||
{
|
||||
"type": "cppbuild",
|
||||
|
4
AUTHORS
Normal file
4
AUTHORS
Normal file
@ -0,0 +1,4 @@
|
||||
Tilen Majerle <tilen.majerle@gmail.com>
|
||||
upbeat27 <upbeat27@gmail.com>
|
||||
Tilen Majerle <tilen@majerle.eu>
|
||||
Y <469960757@qq.com>
|
@ -2,6 +2,12 @@
|
||||
|
||||
## Develop
|
||||
|
||||
## v2.2.0
|
||||
|
||||
- Rework library CMake with removed INTERFACE type
|
||||
- Add `LWMEM_CFG_FULL` to allow control build configuration of the library
|
||||
- Implement support for simple (no realloc, no free, grow-only malloc) allocation mechanism
|
||||
|
||||
## v2.1.0
|
||||
|
||||
- Split CMakeLists.txt files between library and executable
|
||||
|
@ -6,41 +6,26 @@ project(LwLibPROJECT)
|
||||
if(NOT PROJECT_IS_TOP_LEVEL)
|
||||
add_subdirectory(lwmem)
|
||||
else()
|
||||
# Set as executable
|
||||
add_executable(${PROJECT_NAME})
|
||||
|
||||
# Add key executable block
|
||||
target_sources(${PROJECT_NAME} PUBLIC
|
||||
${CMAKE_CURRENT_LIST_DIR}/dev/main.cpp
|
||||
${CMAKE_CURRENT_LIST_DIR}/tests/lwmem_test.c
|
||||
${CMAKE_CURRENT_LIST_DIR}/tests/lwmem_test_simple.c
|
||||
|
||||
# win32 port
|
||||
${CMAKE_CURRENT_LIST_DIR}/lwmem/src/system/lwmem_sys_win32.c
|
||||
)
|
||||
|
||||
# Add key include paths
|
||||
target_include_directories(${PROJECT_NAME} PUBLIC
|
||||
${CMAKE_CURRENT_LIST_DIR}
|
||||
${CMAKE_CURRENT_LIST_DIR}/dev
|
||||
)
|
||||
|
||||
# Compilation definition information
|
||||
target_compile_definitions(${PROJECT_NAME} PUBLIC
|
||||
WIN32
|
||||
_DEBUG
|
||||
CONSOLE
|
||||
LWMEM_DEV
|
||||
)
|
||||
|
||||
# Compiler options
|
||||
target_compile_options(${PROJECT_NAME} PRIVATE
|
||||
-Wall
|
||||
-Wextra
|
||||
-Wpedantic
|
||||
)
|
||||
|
||||
# Add subdir with lwmem and link to the project
|
||||
set(LWMEM_OPTS_FILE ${CMAKE_CURRENT_LIST_DIR}/dev/lwmem_opts.h)
|
||||
add_subdirectory(lwmem)
|
||||
target_link_libraries(${PROJECT_NAME} lwmem)
|
||||
target_link_libraries(${PROJECT_NAME} lwmem_cpp)
|
||||
target_link_libraries(${PROJECT_NAME} PUBLIC lwmem_cpp)
|
||||
|
||||
# Add compile options to the library, which will propagate options to executable through public link
|
||||
target_compile_definitions(lwmem PUBLIC WIN32 _DEBUG CONSOLE LWMEM_DEV)
|
||||
target_compile_options(lwmem PUBLIC -Wall -Wextra -Wpedantic)
|
||||
endif()
|
||||
|
2
LICENSE
2
LICENSE
@ -1,6 +1,6 @@
|
||||
MIT License
|
||||
|
||||
Copyright (c) 2023 Tilen MAJERLE
|
||||
Copyright (c) 2024 Tilen MAJERLE
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
|
@ -4,7 +4,7 @@
|
||||
|
||||
## Features
|
||||
|
||||
* Written in ANSI C99, compatible with ``size_t`` for size data types
|
||||
* Written in C (C11), compatible with ``size_t`` for size data types
|
||||
* Implements standard C library functions for memory allocation, malloc, calloc, realloc and free
|
||||
* Uses *first-fit* algorithm to search for free block
|
||||
* Supports multiple allocation instances to split between memories and/or CPU cores
|
||||
@ -13,16 +13,17 @@
|
||||
* Supports embedded applications with fragmented memories
|
||||
* Supports automotive applications
|
||||
* Supports advanced free/realloc algorithms to optimize memory usage
|
||||
* **Since v2.2.0** Supports light implementation with allocation only
|
||||
* Operating system ready, thread-safe API
|
||||
* C++ wrapper functions
|
||||
* User friendly MIT license
|
||||
|
||||
## Contribute
|
||||
|
||||
Fresh contributions are always welcome. Simple instructions to proceed::
|
||||
Fresh contributions are always welcome. Simple instructions to proceed:
|
||||
|
||||
1. Fork Github repository
|
||||
2. Respect [C style & coding rules](https://github.com/MaJerle/c-code-style) used by the library
|
||||
2. Follow [C style & coding rules](https://github.com/MaJerle/c-code-style) already used in the project
|
||||
3. Create a pull request to develop branch with new features or bug fixes
|
||||
|
||||
Alternatively you may:
|
||||
|
@ -4,7 +4,7 @@
|
||||
*/
|
||||
|
||||
/*
|
||||
* Copyright (c) 2023 Tilen MAJERLE
|
||||
* Copyright (c) 2024 Tilen MAJERLE
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person
|
||||
* obtaining a copy of this software and associated documentation
|
||||
@ -45,5 +45,6 @@
|
||||
#define LWMEM_CFG_OS_MUTEX_HANDLE HANDLE
|
||||
#define LWMEM_CFG_ENABLE_STATS 0
|
||||
#define LWMEM_CFG_CLEAN_MEMORY 1
|
||||
#define LWMEM_CFG_FULL 0
|
||||
|
||||
#endif /* LWMEM_HDR_OPTS_H */
|
||||
|
15
dev/main.cpp
15
dev/main.cpp
@ -1,24 +1,33 @@
|
||||
#include "lwmem/lwmem.h"
|
||||
#include "lwmem/lwmem.hpp"
|
||||
#include <iostream>
|
||||
#include <stdint.h>
|
||||
#include <string.h>
|
||||
#include "lwmem/lwmem.h"
|
||||
#include "lwmem/lwmem.hpp"
|
||||
|
||||
extern "C" void lwmem_test_run(void);
|
||||
extern "C" void lwmem_test_simple_run(void);
|
||||
extern "C" void lwmem_test_memory_structure(void);
|
||||
|
||||
/* Setup manager */
|
||||
Lwmem::LwmemLight<1024> manager;
|
||||
static Lwmem::LwmemLight<1024> manager;
|
||||
|
||||
int
|
||||
main(void) {
|
||||
#if LWMEM_CFG_FULL
|
||||
lwmem_test_memory_structure();
|
||||
//lwmem_test_run();
|
||||
#else
|
||||
lwmem_test_simple_run();
|
||||
#endif
|
||||
|
||||
#if 1
|
||||
/* Test C++ code */
|
||||
void* ret = manager.malloc(123);
|
||||
std::cout << ret << std::endl;
|
||||
#if LWMEM_CFG_FULL
|
||||
manager.free(ret);
|
||||
#endif /* LWMEM_CFG_FULL */
|
||||
#endif
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
8
docs/authors/index.rst
Normal file
8
docs/authors/index.rst
Normal file
@ -0,0 +1,8 @@
|
||||
.. _authors:
|
||||
|
||||
Authors
|
||||
=======
|
||||
|
||||
List of authors and contributors to the library
|
||||
|
||||
.. literalinclude:: ../../AUTHORS
|
@ -23,7 +23,7 @@ subprocess.call('doxygen doxyfile.doxy', shell=True)
|
||||
# -- Project information -----------------------------------------------------
|
||||
|
||||
project = 'LwMEM'
|
||||
copyright = '2022, Tilen MAJERLE'
|
||||
copyright = '2023, Tilen MAJERLE'
|
||||
author = 'Tilen MAJERLE'
|
||||
|
||||
# Try to get branch at which this is running
|
||||
|
@ -1,4 +1,5 @@
|
||||
#define ASSERT(x) do { \
|
||||
#define ASSERT(x) \
|
||||
do { \
|
||||
if (!(x)) { \
|
||||
printf("Assert failed with condition (" #x ")\r\n"); \
|
||||
} else { \
|
||||
@ -53,7 +54,7 @@ main(void) {
|
||||
printf("State 3b\r\n");
|
||||
rptr2 = lwmem_realloc(ptr2, 20);
|
||||
lwmem_debug_print(1, 1);
|
||||
ASSERT(rptr2 == ptr2);
|
||||
ASSERT(rptr2 == ptr1);
|
||||
|
||||
/* Create 3c case */
|
||||
printf("\r\n------------------------------------------------------------------------\r\n");
|
||||
|
@ -52,7 +52,7 @@ State 3b
|
||||
| 4 | 0034A548 | 1 | 56 | 48 |Free block |
|
||||
| 5 | 0034A580 | 0 | 0 | 0 |End of region |
|
||||
|-------|----------|--------|------|------------------|----------------|
|
||||
Assert failed with condition (rptr2 == ptr2)
|
||||
Assert passed with condition (rptr2 == ptr1)
|
||||
|
||||
------------------------------------------------------------------------
|
||||
-- > State restored to last saved!
|
||||
|
@ -57,8 +57,18 @@ Update cloned to latest version
|
||||
Add library to project
|
||||
^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
||||
At this point it is assumed that you have successfully download library, either cloned it or from releases page.
|
||||
Next step is to add the library to the project, by means of source files to compiler inputs and header files in search path
|
||||
At this point it is assumed that you have successfully download library, either with ``git clone`` command or with manual download from the library releases page.
|
||||
Next step is to add the library to the project, by means of source files to compiler inputs and header files in search path.
|
||||
|
||||
*CMake* is the main supported build system. Package comes with the ``CMakeLists.txt`` and ``library.cmake`` files, both located in the ``lwmem`` directory:
|
||||
|
||||
* ``library.cmake``: It is a fully configured set of variables and with library definition. User can include this file to the project file with ``include(path/to/library.cmake)`` and then manually use the variables provided by the file, such as list of source files, include paths or necessary compiler definitions. It is up to the user to properly use the this file on its own.
|
||||
* ``CMakeLists.txt``: It is a wrapper-only file and includes ``library.cmake`` file. It is used for when user wants to include the library to the main project by simply calling *CMake* ``add_subdirectory`` command, followed by ``target_link_libraries`` to link external library to the final project.
|
||||
|
||||
.. tip::
|
||||
Open ``library.cmake`` and analyze the provided information. Among variables, you can also find list of all possible exposed libraries for the user.
|
||||
|
||||
If you do not use the *CMake*, you can do the following:
|
||||
|
||||
* Copy ``lwmem`` folder to your project, it contains library files
|
||||
* Add ``lwmem/src/include`` folder to `include path` of your toolchain. This is where `C/C++` compiler can find the files during compilation process. Usually using ``-I`` flag
|
||||
@ -70,7 +80,7 @@ Configuration file
|
||||
^^^^^^^^^^^^^^^^^^
|
||||
|
||||
Configuration file is used to overwrite default settings defined for the essential use case.
|
||||
Library comes with template config file, which can be modified according to needs.
|
||||
Library comes with template config file, which can be modified according to the application needs.
|
||||
and it should be copied (or simply renamed in-place) and named ``lwmem_opts.h``
|
||||
|
||||
.. note::
|
||||
@ -78,7 +88,11 @@ and it should be copied (or simply renamed in-place) and named ``lwmem_opts.h``
|
||||
File must be renamed to ``lwmem_opts.h`` first and then copied to the project directory where compiler
|
||||
include paths have access to it by using ``#include "lwmem_opts.h"``.
|
||||
|
||||
List of configuration options are available in the :ref:`api_lwmem_opt` section.
|
||||
.. tip::
|
||||
If you are using *CMake* build system, define the variable ``LWMEM_OPTS_FILE`` before adding library's directory to the *CMake* project.
|
||||
Variable must contain the path to the user options file. If not provided and to avoid build error, one will be generated in the build directory.
|
||||
|
||||
Configuration options list is available available in the :ref:`api_lwmem_opt` section.
|
||||
If any option is about to be modified, it should be done in configuration file
|
||||
|
||||
.. literalinclude:: ../../lwmem/src/include/lwmem/lwmem_opts_template.h
|
||||
|
@ -16,7 +16,7 @@ LwMEM is lightweight dynamic memory manager optimized for embedded systems.
|
||||
Features
|
||||
^^^^^^^^
|
||||
|
||||
* Written in ANSI C99, compatible with ``size_t`` for size data types
|
||||
* Written in C (C11), compatible with ``size_t`` for size data types
|
||||
* Implements standard C library functions for memory allocation, malloc, calloc, realloc and free
|
||||
* Uses *first-fit* algorithm to search for free block
|
||||
* Supports multiple allocation instances to split between memories and/or CPU cores
|
||||
@ -25,6 +25,7 @@ Features
|
||||
* Supports embedded applications with fragmented memories
|
||||
* Supports automotive applications
|
||||
* Supports advanced free/realloc algorithms to optimize memory usage
|
||||
* **Since v2.2.0** Supports light implementation with allocation only
|
||||
* Operating system ready, thread-safe API
|
||||
* C++ wrapper functions
|
||||
* User friendly MIT license
|
||||
@ -67,6 +68,7 @@ Table of contents
|
||||
api-reference/index
|
||||
examples/index
|
||||
changelog/index
|
||||
authors/index
|
||||
|
||||
.. toctree::
|
||||
:maxdepth: 2
|
||||
@ -78,7 +80,7 @@ Table of contents
|
||||
LwESP - ESP-AT library <https://github.com/MaJerle/lwesp>
|
||||
LwEVT - Event manager <https://github.com/MaJerle/lwevt>
|
||||
LwGPS - GPS NMEA parser <https://github.com/MaJerle/lwgps>
|
||||
LwGSM - GSM-AT library <https://github.com/MaJerle/lwgsm>
|
||||
LwCELL - Cellular modem host AT library <https://github.com/MaJerle/lwcell>
|
||||
LwJSON - JSON parser <https://github.com/MaJerle/lwjson>
|
||||
LwMEM - Memory manager <https://github.com/MaJerle/lwmem>
|
||||
LwOW - OneWire with UART <https://github.com/MaJerle/lwow>
|
||||
@ -87,3 +89,4 @@ Table of contents
|
||||
LwRB - Ring buffer <https://github.com/MaJerle/lwrb>
|
||||
LwSHELL - Shell <https://github.com/MaJerle/lwshell>
|
||||
LwUTIL - Utility functions <https://github.com/MaJerle/lwutil>
|
||||
LwWDG - RTOS task watchdog <https://github.com/MaJerle/lwwdg>
|
||||
|
@ -1,7 +1,8 @@
|
||||
breathe>=4.9.1
|
||||
colorama
|
||||
docutils==0.16
|
||||
sphinx>=3.5.1
|
||||
breathe>=4.9.1
|
||||
urllib3==1.26.18
|
||||
docutils==0.16
|
||||
colorama
|
||||
sphinx_rtd_theme>=1.0.0
|
||||
sphinx-tabs
|
||||
sphinxcontrib-svg2pdfconverter
|
||||
|
BIN
docs/static/images/logo_tm.png
vendored
BIN
docs/static/images/logo_tm.png
vendored
Binary file not shown.
Before Width: | Height: | Size: 3.3 KiB After Width: | Height: | Size: 19 KiB |
BIN
docs/static/images/logo_tm_full.png
vendored
BIN
docs/static/images/logo_tm_full.png
vendored
Binary file not shown.
Before Width: | Height: | Size: 17 KiB After Width: | Height: | Size: 23 KiB |
@ -9,4 +9,5 @@ User manual
|
||||
how-it-works
|
||||
instances
|
||||
realloc-algorithm
|
||||
light-version
|
||||
thread-safety
|
19
docs/user-manual/light-version.rst
Normal file
19
docs/user-manual/light-version.rst
Normal file
@ -0,0 +1,19 @@
|
||||
.. _light_version:
|
||||
|
||||
LwMEM light implementation
|
||||
==========================
|
||||
|
||||
When system is super memory constrained or when system only requires memory allocation at initialization stage,
|
||||
it is possible to put the library into *light* mode by controlling the :c:macro:`LWMEM_CFG_FULL` user configuration option
|
||||
|
||||
When *full* mode is disabled, user must be aware of some contraints:
|
||||
|
||||
* It is only possible to allocate memory (no free, no realloc)
|
||||
* It is only possible to use one (``1``) memory region. When assigning the memory with more than one region, function will return an error.
|
||||
|
||||
.. tip::
|
||||
Light mode is useful for opaque types that are returned to user and must be allocated on the heap.
|
||||
These are typically allocated at initialization stage and never freed during program execution.
|
||||
|
||||
.. toctree::
|
||||
:maxdepth: 2
|
@ -1,5 +1,5 @@
|
||||
{
|
||||
"version": "2.1.0",
|
||||
"version": "2.0.0",
|
||||
"tasks": [
|
||||
{
|
||||
"type": "cppbuild",
|
||||
|
@ -1,7 +1,5 @@
|
||||
cmake_minimum_required(VERSION 3.22)
|
||||
|
||||
message("Entering ${CMAKE_CURRENT_LIST_DIR}/CMakeLists.txt")
|
||||
|
||||
#
|
||||
# Core project settings
|
||||
#
|
||||
@ -223,5 +221,3 @@ add_custom_command(TARGET ${EXECUTABLE} POST_BUILD
|
||||
add_custom_command(TARGET ${EXECUTABLE} POST_BUILD
|
||||
COMMAND ${CMAKE_OBJCOPY} -O binary $<TARGET_FILE:${EXECUTABLE}> ${EXECUTABLE}.bin
|
||||
)
|
||||
|
||||
message("Exiting ${CMAKE_CURRENT_LIST_DIR}/CMakeLists.txt")
|
||||
|
@ -4,12 +4,15 @@ set(CMAKE_SYSTEM_PROCESSOR arm)
|
||||
# Some default GCC settings
|
||||
# arm-none-eabi- must be part of path environment
|
||||
set(TOOLCHAIN_PREFIX arm-none-eabi-)
|
||||
set(FLAGS "-fdata-sections -ffunction-sections --specs=nano.specs -Wl,--gc-sections")
|
||||
set(CPP_FLAGS "-fno-rtti -fno-exceptions -fno-threadsafe-statics")
|
||||
set(FLAGS "-fdata-sections -ffunction-sections -Wl,--gc-sections")
|
||||
set(CPP_FLAGS "${FLAGS} -fno-rtti -fno-exceptions -fno-threadsafe-statics")
|
||||
|
||||
set(CMAKE_C_COMPILER ${TOOLCHAIN_PREFIX}gcc ${FLAGS})
|
||||
set(CMAKE_C_FLAGS ${FLAGS})
|
||||
set(CMAKE_CXX_FLAGS ${CPP_FLAGS})
|
||||
|
||||
set(CMAKE_C_COMPILER ${TOOLCHAIN_PREFIX}gcc)
|
||||
set(CMAKE_ASM_COMPILER ${CMAKE_C_COMPILER})
|
||||
set(CMAKE_CXX_COMPILER ${TOOLCHAIN_PREFIX}g++ ${FLAGS} ${CPP_FLAGS})
|
||||
set(CMAKE_CXX_COMPILER ${TOOLCHAIN_PREFIX}g++)
|
||||
set(CMAKE_OBJCOPY ${TOOLCHAIN_PREFIX}objcopy)
|
||||
set(CMAKE_SIZE ${TOOLCHAIN_PREFIX}size)
|
||||
|
||||
|
@ -4,7 +4,7 @@
|
||||
*/
|
||||
|
||||
/*
|
||||
* Copyright (c) 2023 Tilen MAJERLE
|
||||
* Copyright (c) 2024 Tilen MAJERLE
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person
|
||||
* obtaining a copy of this software and associated documentation
|
||||
|
@ -4,7 +4,7 @@
|
||||
*/
|
||||
|
||||
/*
|
||||
* Copyright (c) 2023 Tilen MAJERLE
|
||||
* Copyright (c) 2024 Tilen MAJERLE
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person
|
||||
* obtaining a copy of this software and associated documentation
|
||||
|
@ -4,7 +4,7 @@
|
||||
*/
|
||||
|
||||
/*
|
||||
* Copyright (c) 2023 Tilen MAJERLE
|
||||
* Copyright (c) 2024 Tilen MAJERLE
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person
|
||||
* obtaining a copy of this software and associated documentation
|
||||
|
@ -1,5 +1,5 @@
|
||||
{
|
||||
"version": "2.1.0",
|
||||
"version": "2.0.0",
|
||||
"tasks": [
|
||||
{
|
||||
"type": "cppbuild",
|
||||
|
@ -1,7 +1,5 @@
|
||||
cmake_minimum_required(VERSION 3.22)
|
||||
|
||||
message("Entering ${CMAKE_CURRENT_LIST_DIR}/CMakeLists.txt")
|
||||
|
||||
#
|
||||
# Core project settings
|
||||
#
|
||||
@ -207,5 +205,3 @@ add_custom_command(TARGET ${EXECUTABLE} POST_BUILD
|
||||
add_custom_command(TARGET ${EXECUTABLE} POST_BUILD
|
||||
COMMAND ${CMAKE_OBJCOPY} -O binary $<TARGET_FILE:${EXECUTABLE}> ${EXECUTABLE}.bin
|
||||
)
|
||||
|
||||
message("Exiting ${CMAKE_CURRENT_LIST_DIR}/CMakeLists.txt")
|
||||
|
@ -4,12 +4,15 @@ set(CMAKE_SYSTEM_PROCESSOR arm)
|
||||
# Some default GCC settings
|
||||
# arm-none-eabi- must be part of path environment
|
||||
set(TOOLCHAIN_PREFIX arm-none-eabi-)
|
||||
set(FLAGS "-fdata-sections -ffunction-sections --specs=nano.specs -Wl,--gc-sections")
|
||||
set(CPP_FLAGS "-fno-rtti -fno-exceptions -fno-threadsafe-statics")
|
||||
set(FLAGS "-fdata-sections -ffunction-sections -Wl,--gc-sections")
|
||||
set(CPP_FLAGS "${FLAGS} -fno-rtti -fno-exceptions -fno-threadsafe-statics")
|
||||
|
||||
set(CMAKE_C_COMPILER ${TOOLCHAIN_PREFIX}gcc ${FLAGS})
|
||||
set(CMAKE_C_FLAGS ${FLAGS})
|
||||
set(CMAKE_CXX_FLAGS ${CPP_FLAGS})
|
||||
|
||||
set(CMAKE_C_COMPILER ${TOOLCHAIN_PREFIX}gcc)
|
||||
set(CMAKE_ASM_COMPILER ${CMAKE_C_COMPILER})
|
||||
set(CMAKE_CXX_COMPILER ${TOOLCHAIN_PREFIX}g++ ${FLAGS} ${CPP_FLAGS})
|
||||
set(CMAKE_CXX_COMPILER ${TOOLCHAIN_PREFIX}g++)
|
||||
set(CMAKE_OBJCOPY ${TOOLCHAIN_PREFIX}objcopy)
|
||||
set(CMAKE_SIZE ${TOOLCHAIN_PREFIX}size)
|
||||
|
||||
|
@ -4,7 +4,7 @@
|
||||
*/
|
||||
|
||||
/*
|
||||
* Copyright (c) 2023 Tilen MAJERLE
|
||||
* Copyright (c) 2024 Tilen MAJERLE
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person
|
||||
* obtaining a copy of this software and associated documentation
|
||||
|
@ -4,7 +4,7 @@
|
||||
*/
|
||||
|
||||
/*
|
||||
* Copyright (c) 2023 Tilen MAJERLE
|
||||
* Copyright (c) 2024 Tilen MAJERLE
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person
|
||||
* obtaining a copy of this software and associated documentation
|
||||
|
@ -4,7 +4,7 @@
|
||||
*/
|
||||
|
||||
/*
|
||||
* Copyright (c) 2023 Tilen MAJERLE
|
||||
* Copyright (c) 2024 Tilen MAJERLE
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person
|
||||
* obtaining a copy of this software and associated documentation
|
||||
|
2
examples/win32/.vscode/tasks.json
vendored
2
examples/win32/.vscode/tasks.json
vendored
@ -1,5 +1,5 @@
|
||||
{
|
||||
"version": "2.1.0",
|
||||
"version": "2.0.0",
|
||||
"tasks": [
|
||||
{
|
||||
"type": "cppbuild",
|
||||
|
@ -4,7 +4,7 @@
|
||||
*/
|
||||
|
||||
/*
|
||||
* Copyright (c) 2023 Tilen MAJERLE
|
||||
* Copyright (c) 2024 Tilen MAJERLE
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person
|
||||
* obtaining a copy of this software and associated documentation
|
||||
|
@ -4,7 +4,7 @@
|
||||
*/
|
||||
|
||||
/*
|
||||
* Copyright (c) 2023 Tilen MAJERLE
|
||||
* Copyright (c) 2024 Tilen MAJERLE
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person
|
||||
* obtaining a copy of this software and associated documentation
|
||||
|
@ -4,7 +4,7 @@
|
||||
*/
|
||||
|
||||
/*
|
||||
* Copyright (c) 2023 Tilen MAJERLE
|
||||
* Copyright (c) 2024 Tilen MAJERLE
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person
|
||||
* obtaining a copy of this software and associated documentation
|
||||
|
@ -4,7 +4,7 @@
|
||||
*/
|
||||
|
||||
/*
|
||||
* Copyright (c) 2023 Tilen MAJERLE
|
||||
* Copyright (c) 2024 Tilen MAJERLE
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person
|
||||
* obtaining a copy of this software and associated documentation
|
||||
|
@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "LwMEM",
|
||||
"version": "2.1.0",
|
||||
"version": "2.2.0",
|
||||
"description": "Lightweight dynamic memory manager optimized for embedded systems",
|
||||
"keywords": "lwmem, memory, dynamic, heap, malloc, calloc, realloc, free, lightweight, manager, embedded, stm32, win32",
|
||||
"repository": {
|
||||
@ -29,5 +29,8 @@
|
||||
"build",
|
||||
"**/build"
|
||||
]
|
||||
},
|
||||
"build": {
|
||||
"includeDir": "lwmem/src/include"
|
||||
}
|
||||
}
|
@ -1,23 +1,3 @@
|
||||
cmake_minimum_required(VERSION 3.22)
|
||||
|
||||
# Debug message
|
||||
message("Entering ${CMAKE_CURRENT_LIST_DIR}/CMakeLists.txt")
|
||||
|
||||
# Register core library
|
||||
add_library(lwmem INTERFACE)
|
||||
target_sources(lwmem PUBLIC ${CMAKE_CURRENT_LIST_DIR}/src/lwmem/lwmem.c)
|
||||
target_include_directories(lwmem INTERFACE ${CMAKE_CURRENT_LIST_DIR}/src/include)
|
||||
|
||||
if (DEFINED LWMEM_SYS_PORT)
|
||||
target_sources(lwmem PUBLIC ${CMAKE_CURRENT_LIST_DIR}/src/system/lwmem_sys_${LWMEM_SYS_PORT}.c)
|
||||
endif()
|
||||
|
||||
# Register core library with C++ extensions
|
||||
add_library(lwmem_cpp INTERFACE)
|
||||
target_sources(lwmem_cpp PUBLIC ${CMAKE_CURRENT_LIST_DIR}/src/lwmem/lwmem.cpp)
|
||||
target_include_directories(lwmem_cpp INTERFACE ${CMAKE_CURRENT_LIST_DIR}/src/include)
|
||||
|
||||
# Register other modules
|
||||
|
||||
# Debug message
|
||||
message("Exiting ${CMAKE_CURRENT_LIST_DIR}/CMakeLists.txt")
|
||||
include(${CMAKE_CURRENT_LIST_DIR}/library.cmake)
|
64
lwmem/library.cmake
Normal file
64
lwmem/library.cmake
Normal file
@ -0,0 +1,64 @@
|
||||
#
|
||||
# LIB_PREFIX: LWMEM
|
||||
#
|
||||
# This file provides set of variables for end user
|
||||
# and also generates one (or more) libraries, that can be added to the project using target_link_libraries(...)
|
||||
#
|
||||
# Before this file is included to the root CMakeLists file (using include() function), user can set some variables:
|
||||
#
|
||||
# LWMEM_SYS_PORT: If defined, it will include port source file from the library.
|
||||
# LWMEM_OPTS_FILE: If defined, it is the path to the user options file. If not defined, one will be generated for you automatically
|
||||
# LWMEM_COMPILE_OPTIONS: If defined, it provide compiler options for generated library.
|
||||
# LWMEM_COMPILE_DEFINITIONS: If defined, it provides "-D" definitions to the library build
|
||||
#
|
||||
|
||||
# Custom include directory
|
||||
set(LWMEM_CUSTOM_INC_DIR ${CMAKE_CURRENT_BINARY_DIR}/lib_inc)
|
||||
|
||||
# Library core sources
|
||||
set(lwmem_core_SRCS
|
||||
${CMAKE_CURRENT_LIST_DIR}/src/lwmem/lwmem.c
|
||||
)
|
||||
|
||||
# C++ extension
|
||||
set(lwmem_core_cpp_SRCS
|
||||
${CMAKE_CURRENT_LIST_DIR}/src/lwmem/lwmem.cpp
|
||||
)
|
||||
|
||||
# Setup include directories
|
||||
set(lwmem_include_DIRS
|
||||
${CMAKE_CURRENT_LIST_DIR}/src/include
|
||||
${LWMEM_CUSTOM_INC_DIR}
|
||||
)
|
||||
|
||||
# Add system port
|
||||
if(DEFINED LWMEM_SYS_PORT)
|
||||
set(lwmem_core_SRCS ${lwmem_core_SRCS}
|
||||
${CMAKE_CURRENT_LIST_DIR}/src/system/lwmem_sys_${LWMEM_SYS_PORT}.c
|
||||
)
|
||||
endif()
|
||||
|
||||
# Register core library
|
||||
add_library(lwmem)
|
||||
target_sources(lwmem PRIVATE ${lwmem_core_SRCS})
|
||||
target_include_directories(lwmem PUBLIC ${lwmem_include_DIRS})
|
||||
target_compile_options(lwmem PRIVATE ${LWMEM_COMPILE_OPTIONS})
|
||||
target_compile_definitions(lwmem PRIVATE ${LWMEM_COMPILE_DEFINITIONS})
|
||||
|
||||
# Register core library with C++ extensions
|
||||
add_library(lwmem_cpp)
|
||||
target_sources(lwmem_cpp PRIVATE ${lwmem_core_SRCS})
|
||||
target_include_directories(lwmem_cpp PUBLIC ${lwmem_include_DIRS})
|
||||
target_compile_options(lwmem_cpp PRIVATE ${LWMEM_COMPILE_OPTIONS})
|
||||
target_compile_definitions(lwmem_cpp PRIVATE ${LWMEM_COMPILE_DEFINITIONS})
|
||||
target_link_libraries(lwmem_cpp PUBLIC lwmem)
|
||||
|
||||
# Create config file if user didn't provide one info himself
|
||||
if(NOT LWMEM_OPTS_FILE)
|
||||
message(STATUS "Using default lwmem_opts.h file")
|
||||
set(LWMEM_OPTS_FILE ${CMAKE_CURRENT_LIST_DIR}/src/include/lwmem/lwmem_opts_template.h)
|
||||
else()
|
||||
message(STATUS "Using custom lwmem_opts.h file from ${LWMEM_OPTS_FILE}")
|
||||
endif()
|
||||
|
||||
configure_file(${LWMEM_OPTS_FILE} ${LWMEM_CUSTOM_INC_DIR}/lwmem_opts.h COPYONLY)
|
@ -4,7 +4,7 @@
|
||||
*/
|
||||
|
||||
/*
|
||||
* Copyright (c) 2023 Tilen MAJERLE
|
||||
* Copyright (c) 2024 Tilen MAJERLE
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person
|
||||
* obtaining a copy of this software and associated documentation
|
||||
@ -29,12 +29,13 @@
|
||||
* This file is part of LwMEM - Lightweight dynamic memory manager library.
|
||||
*
|
||||
* Author: Tilen MAJERLE <tilen@majerle.eu>
|
||||
* Version: v2.1.0
|
||||
* Version: v2.2.0
|
||||
*/
|
||||
#ifndef LWMEM_HDR_H
|
||||
#define LWMEM_HDR_H
|
||||
|
||||
#include <limits.h>
|
||||
#include <stddef.h>
|
||||
#include <stdint.h>
|
||||
#include "lwmem/lwmem_opt.h"
|
||||
|
||||
@ -59,8 +60,8 @@ extern "C" {
|
||||
* \brief Memory block structure
|
||||
*/
|
||||
typedef struct lwmem_block {
|
||||
struct lwmem_block*
|
||||
next; /*!< Next free memory block on linked list. Set to \ref LWMEM_BLOCK_ALLOC_MARK when block is allocated and in use */
|
||||
struct lwmem_block* next; /*!< Next free memory block on linked list.
|
||||
Set to \ref LWMEM_BLOCK_ALLOC_MARK when block is allocated and in use */
|
||||
size_t size; /*!< Size of block, including metadata part.
|
||||
MSB bit is set to `1` when block is allocated and in use,
|
||||
or `0` when block is considered free */
|
||||
@ -72,8 +73,8 @@ typedef struct lwmem_block {
|
||||
typedef struct {
|
||||
uint32_t mem_size_bytes; /*!< Total memory size of all regions combined */
|
||||
uint32_t mem_available_bytes; /*!< Free memory available for allocation */
|
||||
uint32_t
|
||||
minimum_ever_mem_available_bytes; /*!< Minimum amount of total free memory there has been in the heap since the system booted. */
|
||||
uint32_t minimum_ever_mem_available_bytes; /*!< Minimum amount of total free memory there has been
|
||||
in the heap since the system booted. */
|
||||
uint32_t nr_alloc; /*!< Number of all allocated blocks in single instance */
|
||||
uint32_t nr_free; /*!< Number of frees in the LwMEM instance */
|
||||
} lwmem_stats_t;
|
||||
@ -82,10 +83,16 @@ typedef struct {
|
||||
* \brief LwMEM main structure
|
||||
*/
|
||||
typedef struct lwmem {
|
||||
size_t mem_available_bytes; /*!< Memory size available for allocation */
|
||||
#if LWMEM_CFG_FULL
|
||||
lwmem_block_t start_block; /*!< Holds beginning of memory allocation regions */
|
||||
lwmem_block_t* end_block; /*!< Pointer to the last memory location in regions linked list */
|
||||
size_t mem_available_bytes; /*!< Memory size available for allocation */
|
||||
size_t mem_regions_count; /*!< Number of regions used for allocation */
|
||||
#else
|
||||
uint8_t* mem_next_available_ptr; /*!< Pointer for next allocation */
|
||||
uint8_t is_initialized; /*!< Set to `1` when initialized */
|
||||
#endif
|
||||
|
||||
#if LWMEM_CFG_OS || __DOXYGEN__
|
||||
LWMEM_CFG_OS_MUTEX_HANDLE mutex; /*!< System mutex for OS */
|
||||
#endif /* LWMEM_CFG_OS || __DOXYGEN__ */
|
||||
@ -109,107 +116,29 @@ typedef struct {
|
||||
size_t lwmem_assignmem_ex(lwmem_t* lwobj, const lwmem_region_t* regions);
|
||||
void* lwmem_malloc_ex(lwmem_t* lwobj, const lwmem_region_t* region, const size_t size);
|
||||
void* lwmem_calloc_ex(lwmem_t* lwobj, const lwmem_region_t* region, const size_t nitems, const size_t size);
|
||||
#if LWMEM_CFG_FULL || __DOXYGEN__
|
||||
void* lwmem_realloc_ex(lwmem_t* lwobj, const lwmem_region_t* region, void* const ptr, const size_t size);
|
||||
uint8_t lwmem_realloc_s_ex(lwmem_t* lwobj, const lwmem_region_t* region, void** const ptr, const size_t size);
|
||||
int lwmem_realloc_s_ex(lwmem_t* lwobj, const lwmem_region_t* region, void** const ptr, const size_t size);
|
||||
void lwmem_free_ex(lwmem_t* lwobj, void* const ptr);
|
||||
void lwmem_free_s_ex(lwmem_t* lwobj, void** const ptr);
|
||||
size_t lwmem_get_size_ex(lwmem_t* lwobj, void* ptr);
|
||||
#endif /* LWMEM_CFG_FULL || __DOXYGEN__ */
|
||||
#if LWMEM_CFG_ENABLE_STATS || __DOXYGEN__
|
||||
void lwmem_get_stats_ex(lwmem_t* lwobj, lwmem_stats_t* stats);
|
||||
void lwmem_get_size(lwmem_stats_t* stats);
|
||||
#endif /* LWMEM_CFG_ENABLE_STATS || __DOXYGEN__ */
|
||||
|
||||
/**
|
||||
* \note This is a wrapper for \ref lwmem_assignmem_ex function.
|
||||
* It operates in default LwMEM instance and uses first available region for memory operations
|
||||
* \param[in] regions: Pointer to array of regions with address and respective size.
|
||||
* Regions must be in increasing order (start address) and must not overlap in-between.
|
||||
* Last region entry must have address `NULL` and size set to `0`
|
||||
* \code{.c}
|
||||
//Example definition
|
||||
lwmem_region_t regions[] = {
|
||||
{ (void *)0x10000000, 0x1000 }, //Region starts at address 0x10000000 and is 0x1000 bytes long
|
||||
{ (void *)0x20000000, 0x2000 }, //Region starts at address 0x20000000 and is 0x2000 bytes long
|
||||
{ (void *)0x30000000, 0x3000 }, //Region starts at address 0x30000000 and is 0x3000 bytes long
|
||||
{ NULL, 0 } //Array termination indicator
|
||||
}
|
||||
\endcode
|
||||
* \return `0` on failure, number of final regions used for memory manager on success
|
||||
*/
|
||||
#define lwmem_assignmem(regions) lwmem_assignmem_ex(NULL, (regions))
|
||||
size_t lwmem_assignmem(const lwmem_region_t* regions);
|
||||
void* lwmem_malloc(size_t size);
|
||||
void* lwmem_calloc(size_t nitems, size_t size);
|
||||
|
||||
/**
|
||||
* \note This is a wrapper for \ref lwmem_malloc_ex function.
|
||||
* It operates in default LwMEM instance and uses first available region for memory operations
|
||||
* \param[in] size: Size to allocate in units of bytes
|
||||
* \return Pointer to allocated memory on success, `NULL` otherwise
|
||||
* \note This function is thread safe when \ref LWMEM_CFG_OS is enabled
|
||||
*/
|
||||
#define lwmem_malloc(size) lwmem_malloc_ex(NULL, NULL, (size))
|
||||
|
||||
/**
|
||||
* \note This is a wrapper for \ref lwmem_calloc_ex function.
|
||||
* It operates in default LwMEM instance and uses first available region for memory operations
|
||||
* \param[in] nitems: Number of elements to be allocated
|
||||
* \param[in] size: Size of each element, in units of bytes
|
||||
* \return Pointer to allocated memory on success, `NULL` otherwise
|
||||
* \note This function is thread safe when \ref LWMEM_CFG_OS is enabled
|
||||
*/
|
||||
#define lwmem_calloc(nitems, size) lwmem_calloc_ex(NULL, NULL, (nitems), (size))
|
||||
|
||||
/**
|
||||
* \note This is a wrapper for \ref lwmem_realloc_ex function.
|
||||
* It operates in default LwMEM instance and uses first available region for memory operations
|
||||
* \param[in] ptr: Memory block previously allocated with one of allocation functions.
|
||||
* It may be set to `NULL` to create new clean allocation
|
||||
* \param[in] size: Size of new memory to reallocate
|
||||
* \return Pointer to allocated memory on success, `NULL` otherwise
|
||||
* \note This function is thread safe when \ref LWMEM_CFG_OS is enabled
|
||||
*/
|
||||
#define lwmem_realloc(ptr, size) lwmem_realloc_ex(NULL, NULL, (ptr), (size))
|
||||
|
||||
/**
|
||||
* \note This is a wrapper for \ref lwmem_realloc_s_ex function.
|
||||
* It operates in default LwMEM instance and uses first available region for memory operations
|
||||
* \param[in] ptrptr: Pointer to pointer to allocated memory. Must not be set to `NULL`.
|
||||
* If reallocation is successful, it modifies pointer's pointing address,
|
||||
* or sets it to `NULL` in case of `free` operation
|
||||
* \param[in] size: New requested size in bytes
|
||||
* \return `1` if successfully reallocated, `0` otherwise
|
||||
* \note This function is thread safe when \ref LWMEM_CFG_OS is enabled
|
||||
*/
|
||||
#define lwmem_realloc_s(ptrptr, size) lwmem_realloc_s_ex(NULL, NULL, (ptrptr), (size))
|
||||
|
||||
/**
|
||||
* \note This is a wrapper for \ref lwmem_free_ex function.
|
||||
* It operates in default LwMEM instance and uses first available region for memory operations
|
||||
* \param[in] ptr: Memory to free. `NULL` pointer is valid input
|
||||
* \note This function is thread safe when \ref LWMEM_CFG_OS is enabled
|
||||
*/
|
||||
#define lwmem_free(ptr) lwmem_free_ex(NULL, (ptr))
|
||||
|
||||
/**
|
||||
* \note This is a wrapper for \ref lwmem_free_s_ex function.
|
||||
* It operates in default LwMEM instance and uses first available region for memory operations
|
||||
* \param[in] ptrptr: Pointer to pointer to allocated memory.
|
||||
* When set to non `NULL`, pointer is freed and set to `NULL`
|
||||
* \note This function is thread safe when \ref LWMEM_CFG_OS is enabled
|
||||
*/
|
||||
#define lwmem_free_s(ptrptr) lwmem_free_s_ex(NULL, (ptrptr))
|
||||
|
||||
/**
|
||||
* \note This is a wrapper for \ref lwmem_get_size_ex function.
|
||||
* It operates in default LwMEM instance and uses first available region for memory operations
|
||||
* \param[in] ptr: Pointer to allocated memory
|
||||
* \return Block size for user in units of bytes
|
||||
*/
|
||||
#define lwmem_get_size(ptr) lwmem_get_size_ex(NULL, (ptr))
|
||||
|
||||
/**
|
||||
* \note This is a wrapper for \ref lwmem_get_stats_ex function.
|
||||
* It operates in default LwMEM instance
|
||||
* \param[in] ptr: Pointer to lwmem_stats_t to store result
|
||||
*/
|
||||
#define lwmem_get_stats(stats) lwmem_get_stats_ex(NULL, (stats))
|
||||
#if LWMEM_CFG_FULL || __DOXYGEN__
|
||||
void* lwmem_realloc(void* ptr, size_t size);
|
||||
int lwmem_realloc_s(void** ptr2ptr, size_t size);
|
||||
void lwmem_free(void* ptr);
|
||||
void lwmem_free_s(void** ptr2ptr);
|
||||
size_t lwmem_get_size(void* ptr);
|
||||
#endif /* LWMEM_CFG_FULL || __DOXYGEN__ */
|
||||
|
||||
#if defined(LWMEM_DEV) && !__DOXYGEN__
|
||||
unsigned char lwmem_debug_create_regions(lwmem_region_t** regs_out, size_t count, size_t size);
|
||||
|
@ -29,7 +29,7 @@
|
||||
* This file is part of LwMEM - Lightweight dynamic memory manager library.
|
||||
*
|
||||
* Author: Tilen MAJERLE <tilen@majerle.eu>
|
||||
* Version: v2.1.0
|
||||
* Version: v2.2.0
|
||||
*/
|
||||
#ifndef LWMEM_HDR_HPP
|
||||
#define LWMEM_HDR_HPP
|
||||
@ -93,6 +93,7 @@ class LwmemLight {
|
||||
return lwmem_calloc_ex(&m_lw, nullptr, nitems, size);
|
||||
}
|
||||
|
||||
#if LWMEM_CFG_FULL || __DOXYGEN__
|
||||
/**
|
||||
* \brief Reallocate block of memory
|
||||
* \param ptr: Pointer to previously allocated memory block
|
||||
@ -114,6 +115,7 @@ class LwmemLight {
|
||||
free(void* ptr) {
|
||||
lwmem_free_ex(&m_lw, ptr);
|
||||
}
|
||||
#endif /* LWMEM_CFG_FULL || __DOXYGEN__ */
|
||||
|
||||
private:
|
||||
/* Delete unused constructors */
|
||||
|
@ -4,7 +4,7 @@
|
||||
*/
|
||||
|
||||
/*
|
||||
* Copyright (c) 2023 Tilen MAJERLE
|
||||
* Copyright (c) 2024 Tilen MAJERLE
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person
|
||||
* obtaining a copy of this software and associated documentation
|
||||
@ -29,7 +29,7 @@
|
||||
* This file is part of LwMEM - Lightweight dynamic memory manager library.
|
||||
*
|
||||
* Author: Tilen MAJERLE <tilen@majerle.eu>
|
||||
* Version: v2.1.0
|
||||
* Version: v2.2.0
|
||||
*/
|
||||
#ifndef LWMEM_OPT_HDR_H
|
||||
#define LWMEM_OPT_HDR_H
|
||||
@ -82,7 +82,27 @@ extern "C" {
|
||||
* Usually alignment of `4` bytes fits to all processors.
|
||||
*/
|
||||
#ifndef LWMEM_CFG_ALIGN_NUM
|
||||
#define LWMEM_CFG_ALIGN_NUM ((size_t)4)
|
||||
#define LWMEM_CFG_ALIGN_NUM 4
|
||||
#endif
|
||||
|
||||
/**
|
||||
* \brief Enables `1` or disables `0` full memory management support.
|
||||
*
|
||||
* When enabled (default config), library supports allocation, reallocation and freeing of the memory.
|
||||
* - Memory [c]allocation
|
||||
* - Memory reallocation
|
||||
* - Memory allocation in user defined memory regions
|
||||
* - Memory freeing
|
||||
*
|
||||
* When disabled, library only supports allocation and does not provide any other service.
|
||||
* - Its purpose is for memory allocation at the start of firmware initialization only
|
||||
*
|
||||
* \note When disabled, statistics functionaltiy is not available
|
||||
* and only one region is supported (for now, may be updated later).
|
||||
* API to allocate memory remains the same as for full configuration.
|
||||
*/
|
||||
#ifndef LWMEM_CFG_FULL
|
||||
#define LWMEM_CFG_FULL 1
|
||||
#endif
|
||||
|
||||
/**
|
||||
@ -103,6 +123,33 @@ extern "C" {
|
||||
#define LWMEM_CFG_ENABLE_STATS 0
|
||||
#endif
|
||||
|
||||
/**
|
||||
* \brief Memory set function
|
||||
*
|
||||
* \note Function footprint is the same as \ref memset
|
||||
*/
|
||||
#ifndef LWMEM_MEMSET
|
||||
#define LWMEM_MEMSET(dst, val, len) memset((dst), (val), (len))
|
||||
#endif
|
||||
|
||||
/**
|
||||
* \brief Memory copy function
|
||||
*
|
||||
* \note Function footprint is the same as \ref memcpy
|
||||
*/
|
||||
#ifndef LWMEM_MEMCPY
|
||||
#define LWMEM_MEMCPY(dst, src, len) memcpy((dst), (src), (len))
|
||||
#endif
|
||||
|
||||
/**
|
||||
* \brief Memory move function
|
||||
*
|
||||
* \note Function footprint is the same as \ref memmove
|
||||
*/
|
||||
#ifndef LWMEM_MEMMOVE
|
||||
#define LWMEM_MEMMOVE(dst, src, len) memmove((dst), (src), (len))
|
||||
#endif
|
||||
|
||||
/**
|
||||
* \}
|
||||
*/
|
||||
|
@ -4,7 +4,7 @@
|
||||
*/
|
||||
|
||||
/*
|
||||
* Copyright (c) 2023 Tilen MAJERLE
|
||||
* Copyright (c) 2024 Tilen MAJERLE
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person
|
||||
* obtaining a copy of this software and associated documentation
|
||||
@ -29,7 +29,7 @@
|
||||
* This file is part of LwMEM - Lightweight dynamic memory manager library.
|
||||
*
|
||||
* Author: Tilen MAJERLE <tilen@majerle.eu>
|
||||
* Version: v2.1.0
|
||||
* Version: v2.2.0
|
||||
*/
|
||||
#ifndef LWMEM_OPTS_HDR_H
|
||||
#define LWMEM_OPTS_HDR_H
|
||||
|
@ -4,7 +4,7 @@
|
||||
*/
|
||||
|
||||
/*
|
||||
* Copyright (c) 2023 Tilen MAJERLE
|
||||
* Copyright (c) 2024 Tilen MAJERLE
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person
|
||||
* obtaining a copy of this software and associated documentation
|
||||
@ -29,7 +29,7 @@
|
||||
* This file is part of LwMEM - Lightweight dynamic memory manager library.
|
||||
*
|
||||
* Author: Tilen MAJERLE <tilen@majerle.eu>
|
||||
* Version: v2.1.0
|
||||
* Version: v2.2.0
|
||||
*/
|
||||
#ifndef LWMEM_SYS_HDR_H
|
||||
#define LWMEM_SYS_HDR_H
|
||||
|
@ -4,7 +4,7 @@
|
||||
*/
|
||||
|
||||
/*
|
||||
* Copyright (c) 2023 Tilen MAJERLE
|
||||
* Copyright (c) 2024 Tilen MAJERLE
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person
|
||||
* obtaining a copy of this software and associated documentation
|
||||
@ -29,19 +29,54 @@
|
||||
* This file is part of LwMEM - Lightweight dynamic memory manager library.
|
||||
*
|
||||
* Author: Tilen MAJERLE <tilen@majerle.eu>
|
||||
* Version: v2.1.0
|
||||
* Version: v2.2.0
|
||||
*/
|
||||
#include "lwmem/lwmem.h"
|
||||
#include <limits.h>
|
||||
#include <stdint.h>
|
||||
#include <string.h>
|
||||
|
||||
#if LWMEM_CFG_OS
|
||||
#include "system/lwmem_sys.h"
|
||||
#endif /* LWMEM_CFG_OS */
|
||||
|
||||
#define LWMEM_MEMSET memset
|
||||
#define LWMEM_MEMCPY memcpy
|
||||
#define LWMEM_MEMMOVE memmove
|
||||
#if LWMEM_CFG_OS
|
||||
#define LWMEM_PROTECT(lwobj) lwmem_sys_mutex_wait(&((lwobj)->mutex))
|
||||
#define LWMEM_UNPROTECT(lwobj) lwmem_sys_mutex_release(&((lwobj)->mutex))
|
||||
#else /* LWMEM_CFG_OS */
|
||||
#define LWMEM_PROTECT(lwobj)
|
||||
#define LWMEM_UNPROTECT(lwobj)
|
||||
#endif /* !LWMEM_CFG_OS */
|
||||
|
||||
/* Statistics part */
|
||||
#if LWMEM_CFG_ENABLE_STATS
|
||||
#define LWMEM_INC_STATS(field) (++(field))
|
||||
#define LWMEM_UPDATE_MIN_FREE(lwobj) \
|
||||
do { \
|
||||
if ((lwobj)->mem_available_bytes < (lwobj)->stats.minimum_ever_mem_available_bytes) { \
|
||||
(lwobj)->stats.minimum_ever_mem_available_bytes = (lwobj)->mem_available_bytes; \
|
||||
} \
|
||||
} while (0)
|
||||
#else
|
||||
#define LWMEM_INC_STATS(field)
|
||||
#define LWMEM_UPDATE_MIN_FREE(lwobj)
|
||||
#endif /* LWMEM_CFG_ENABLE_STATS */
|
||||
|
||||
/* Verify alignment */
|
||||
#if (LWMEM_CFG_ALIGN_NUM & (LWMEM_CFG_ALIGN_NUM - 1) > 0)
|
||||
#error "LWMEM_ALIGN_BITS must be power of 2"
|
||||
#endif
|
||||
|
||||
/**
|
||||
* \brief LwMEM default structure used by application
|
||||
*/
|
||||
static lwmem_t lwmem_default;
|
||||
|
||||
/**
|
||||
* \brief Get LwMEM instance based on user input
|
||||
* \param[in] in_lwobj: LwMEM instance. Set to `NULL` for default instance
|
||||
*/
|
||||
#define LWMEM_GET_LWOBJ(in_lwobj) ((in_lwobj) != NULL ? (in_lwobj) : (&lwmem_default))
|
||||
|
||||
/**
|
||||
* \brief Transform alignment number (power of `2`) to bits
|
||||
@ -65,17 +100,19 @@
|
||||
*/
|
||||
#define LWMEM_ALIGN(x) (((x) + (LWMEM_ALIGN_BITS)) & ~(LWMEM_ALIGN_BITS))
|
||||
|
||||
/**
|
||||
* \brief Size of metadata header for block information
|
||||
*/
|
||||
#define LWMEM_BLOCK_META_SIZE LWMEM_ALIGN(sizeof(lwmem_block_t))
|
||||
|
||||
/**
|
||||
* \brief Cast input pointer to byte
|
||||
* \param[in] p: Input pointer to cast to byte pointer
|
||||
*/
|
||||
#define LWMEM_TO_BYTE_PTR(p) ((uint8_t*)(p))
|
||||
|
||||
#if LWMEM_CFG_FULL
|
||||
|
||||
/**
|
||||
* \brief Size of metadata header for block information
|
||||
*/
|
||||
#define LWMEM_BLOCK_META_SIZE LWMEM_ALIGN(sizeof(lwmem_block_t))
|
||||
|
||||
/**
|
||||
* \brief Bit indicating memory block is allocated
|
||||
*/
|
||||
@ -86,18 +123,6 @@
|
||||
*/
|
||||
#define LWMEM_BLOCK_ALLOC_MARK (0xDEADBEEF)
|
||||
|
||||
/**
|
||||
* \brief Set block as allocated
|
||||
* \param[in] block: Block to set as allocated
|
||||
*/
|
||||
#define LWMEM_BLOCK_SET_ALLOC(block) \
|
||||
do { \
|
||||
if ((block) != NULL) { \
|
||||
(block)->size |= LWMEM_ALLOC_BIT; \
|
||||
(block)->next = (void*)(LWMEM_TO_BYTE_PTR(0) + LWMEM_BLOCK_ALLOC_MARK); \
|
||||
} \
|
||||
} while (0)
|
||||
|
||||
/**
|
||||
* \brief Check if input block is properly allocated and valid
|
||||
* \param[in] block: Block to check if properly set as allocated
|
||||
@ -126,69 +151,59 @@
|
||||
*/
|
||||
#define LWMEM_BLOCK_MIN_SIZE (LWMEM_BLOCK_META_SIZE)
|
||||
|
||||
/**
|
||||
* \brief Get LwMEM instance based on user input
|
||||
* \param[in] in_lwobj: LwMEM instance. Set to `NULL` for default instance
|
||||
*/
|
||||
#define LWMEM_GET_LWOBJ(in_lwobj) ((in_lwobj) != NULL ? (in_lwobj) : (&lwmem_default))
|
||||
|
||||
/**
|
||||
* \brief Gets block before input block (marked as prev) and its previous free block
|
||||
* \param[in] in_lwobj: LwMEM instance. Set to `NULL` to use default instance
|
||||
* \param[in] in_b: Input block to find previous and its previous
|
||||
* \param[in] in_pp: Previous previous of input block
|
||||
* \param[in] in_p: Previous of input block
|
||||
* \param[in] in_pp: Previous previous of input block. Finding will be stored here
|
||||
* \param[in] in_p: Previous of input block. Finding will be stored here
|
||||
*/
|
||||
#define LWMEM_GET_PREV_CURR_OF_BLOCK(in_lwobj, in_b, in_pp, in_p) \
|
||||
do { \
|
||||
for ((in_pp) = NULL, (in_p) = &((in_lwobj)->start_block); (in_p) != NULL && (in_p)->next < (in_b); \
|
||||
(in_pp) = (in_p), (in_p) = (in_p)->next) {} \
|
||||
} while (0)
|
||||
|
||||
#if LWMEM_CFG_OS
|
||||
#define LWMEM_PROTECT(lwobj) lwmem_sys_mutex_wait(&((lwobj)->mutex))
|
||||
#define LWMEM_UNPROTECT(lwobj) lwmem_sys_mutex_release(&((lwobj)->mutex))
|
||||
#else /* LWMEM_CFG_OS */
|
||||
#define LWMEM_PROTECT(lwobj)
|
||||
#define LWMEM_UNPROTECT(lwobj)
|
||||
#endif /* !LWMEM_CFG_OS */
|
||||
|
||||
/* Statistics part */
|
||||
#if LWMEM_CFG_ENABLE_STATS
|
||||
#define LWMEM_INC_STATS(field) (++(field))
|
||||
#define LWMEM_UPDATE_MIN_FREE(lwobj) \
|
||||
do { \
|
||||
if ((lwobj)->mem_available_bytes < (lwobj)->stats.minimum_ever_mem_available_bytes) { \
|
||||
(lwobj)->stats.minimum_ever_mem_available_bytes = (lwobj)->mem_available_bytes; \
|
||||
} \
|
||||
} while (0)
|
||||
#else
|
||||
#define LWMEM_INC_STATS(field)
|
||||
#define LWMEM_UPDATE_MIN_FREE(lwobj)
|
||||
#endif /* LWMEM_CFG_ENABLE_STATS */
|
||||
static void
|
||||
prv_get_prev_curr_of_block(lwmem_t* in_lwobj, const lwmem_block_t* in_b, lwmem_block_t** in_pp, lwmem_block_t** in_p) {
|
||||
for (*in_pp = NULL, *in_p = &((in_lwobj)->start_block); *in_p != NULL && (*in_p)->next < in_b;
|
||||
*in_pp = (*in_p), *in_p = (*in_p)->next) {}
|
||||
}
|
||||
|
||||
/**
|
||||
* \brief LwMEM default structure used by application
|
||||
* \brief Set block as allocated
|
||||
* \param[in] block: Block to set as allocated
|
||||
*/
|
||||
static lwmem_t lwmem_default;
|
||||
static void
|
||||
prv_block_set_alloc(lwmem_block_t* block) {
|
||||
if (block != NULL) {
|
||||
block->size |= LWMEM_ALLOC_BIT;
|
||||
block->next = (void*)(LWMEM_TO_BYTE_PTR(0) + LWMEM_BLOCK_ALLOC_MARK);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* \brief Get region aligned start address and aligned size
|
||||
* \param[in] region: Region to check for size and address
|
||||
* \param[out] msa: Memory start address output variable
|
||||
* \param[out] ms: Memory size output variable
|
||||
* \param[out] msz: Memory size output variable
|
||||
* \return `1` if region valid, `0` otherwise
|
||||
*/
|
||||
static uint8_t
|
||||
prv_get_region_addr_size(const lwmem_region_t* region, uint8_t** msa, size_t* ms) {
|
||||
size_t mem_size;
|
||||
uint8_t* mem_start_addr;
|
||||
prv_get_region_addr_size(const lwmem_region_t* region, uint8_t** msa, size_t* msz) {
|
||||
size_t mem_size = 0;
|
||||
uint8_t* mem_start_addr = NULL;
|
||||
|
||||
if (region == NULL || msa == NULL || ms == NULL) {
|
||||
if (region == NULL || msa == NULL || msz == NULL) {
|
||||
return 0;
|
||||
}
|
||||
*msa = NULL;
|
||||
*ms = 0;
|
||||
*msz = 0;
|
||||
|
||||
/*
|
||||
* Start address must be aligned to configuration
|
||||
* Increase start address and decrease effective region size
|
||||
*/
|
||||
mem_start_addr = region->start_addr;
|
||||
mem_size = region->size;
|
||||
if (((size_t)mem_start_addr) & LWMEM_ALIGN_BITS) { /* Check alignment boundary */
|
||||
mem_start_addr += ((size_t)LWMEM_CFG_ALIGN_NUM) - ((size_t)mem_start_addr & LWMEM_ALIGN_BITS);
|
||||
mem_size -= (size_t)(mem_start_addr - LWMEM_TO_BYTE_PTR(region->start_addr));
|
||||
}
|
||||
|
||||
/* Check region size and align it to config bits */
|
||||
mem_size = region->size & ~LWMEM_ALIGN_BITS; /* Size does not include lower bits */
|
||||
@ -196,20 +211,10 @@ prv_get_region_addr_size(const lwmem_region_t* region, uint8_t** msa, size_t* ms
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* Start address must be aligned to configuration
|
||||
* Increase start address and decrease effective region size
|
||||
*/
|
||||
mem_start_addr = region->start_addr;
|
||||
if (((size_t)mem_start_addr) & LWMEM_ALIGN_BITS) { /* Check alignment boundary */
|
||||
mem_start_addr += ((size_t)LWMEM_CFG_ALIGN_NUM) - ((size_t)mem_start_addr & LWMEM_ALIGN_BITS);
|
||||
mem_size -= (size_t)(mem_start_addr - LWMEM_TO_BYTE_PTR(region->start_addr));
|
||||
}
|
||||
|
||||
/* Check final memory size */
|
||||
if (mem_size >= (2 * LWMEM_BLOCK_MIN_SIZE)) {
|
||||
*msa = mem_start_addr;
|
||||
*ms = mem_size;
|
||||
*msz = mem_size;
|
||||
|
||||
return 1;
|
||||
}
|
||||
@ -219,14 +224,14 @@ prv_get_region_addr_size(const lwmem_region_t* region, uint8_t** msa, size_t* ms
|
||||
/**
|
||||
* \brief Insert free block to linked list of free blocks
|
||||
* \param[in] lwobj: LwMEM instance. Set to `NULL` to use default instance
|
||||
* \param[in] nb: New free block to insert into linked list
|
||||
* \param[in] nblk: New free block to insert into linked list
|
||||
*/
|
||||
static void
|
||||
prv_insert_free_block(lwmem_t* const lwobj, lwmem_block_t* nb) {
|
||||
prv_insert_free_block(lwmem_t* const lwobj, lwmem_block_t* nblk) {
|
||||
lwmem_block_t* prev;
|
||||
|
||||
/* Check valid inputs */
|
||||
if (nb == NULL) {
|
||||
if (nblk == NULL) {
|
||||
return;
|
||||
}
|
||||
|
||||
@ -234,7 +239,7 @@ prv_insert_free_block(lwmem_t* const lwobj, lwmem_block_t* nb) {
|
||||
* Try to find position to put new block in-between
|
||||
* Search until all free block addresses are lower than entry block
|
||||
*/
|
||||
for (prev = &(lwobj->start_block); prev != NULL && prev->next < nb; prev = prev->next) {}
|
||||
for (prev = &(lwobj->start_block); prev != NULL && prev->next < nblk; prev = prev->next) {}
|
||||
|
||||
/* This is hard error with wrong memory usage */
|
||||
if (prev == NULL) {
|
||||
@ -254,10 +259,10 @@ prv_insert_free_block(lwmem_t* const lwobj, lwmem_block_t* nb) {
|
||||
* By doing this, we protect data left by app
|
||||
* and we make sure new allocations cannot see old information
|
||||
*/
|
||||
if (nb != NULL) {
|
||||
void* p = LWMEM_GET_PTR_FROM_BLOCK(nb);
|
||||
if (p != NULL) {
|
||||
LWMEM_MEMSET(p, 0x00, nb->size - LWMEM_BLOCK_META_SIZE);
|
||||
if (nblk != NULL) {
|
||||
void* ptr = LWMEM_GET_PTR_FROM_BLOCK(nblk);
|
||||
if (ptr != NULL) {
|
||||
LWMEM_MEMSET(ptr, 0x00, nblk->size - LWMEM_BLOCK_META_SIZE);
|
||||
}
|
||||
}
|
||||
#endif /* LWMEM_CFG_RESET_MEMORY */
|
||||
@ -266,9 +271,9 @@ prv_insert_free_block(lwmem_t* const lwobj, lwmem_block_t* nb) {
|
||||
* Check if previous block and input block together create one big contiguous block
|
||||
* If this is the case, merge blocks together and increase previous block by input block size
|
||||
*/
|
||||
if ((LWMEM_TO_BYTE_PTR(prev) + prev->size) == LWMEM_TO_BYTE_PTR(nb)) {
|
||||
prev->size += nb->size; /* Increase current block by size of new block */
|
||||
nb = prev; /* New block and current are now the same thing */
|
||||
if ((LWMEM_TO_BYTE_PTR(prev) + prev->size) == LWMEM_TO_BYTE_PTR(nblk)) {
|
||||
prev->size += nblk->size; /* Increase current block by size of new block */
|
||||
nblk = prev; /* New block and current are now the same thing */
|
||||
/*
|
||||
* It is important to set new block as current one
|
||||
* as this allows merging previous and next blocks together with new block
|
||||
@ -281,25 +286,24 @@ prv_insert_free_block(lwmem_t* const lwobj, lwmem_block_t* nb) {
|
||||
* Do not merge with "end of region" indication (commented part of if statement)
|
||||
*/
|
||||
if (prev->next != NULL && prev->next->size > 0 /* Do not remove "end of region" indicator in each region */
|
||||
&& (LWMEM_TO_BYTE_PTR(nb) + nb->size) == LWMEM_TO_BYTE_PTR(prev->next)) {
|
||||
&& (LWMEM_TO_BYTE_PTR(nblk) + nblk->size) == LWMEM_TO_BYTE_PTR(prev->next)) {
|
||||
if (prev->next == lwobj->end_block) { /* Does it points to the end? */
|
||||
nb->next = lwobj->end_block; /* Set end block pointer */
|
||||
nblk->next = lwobj->end_block; /* Set end block pointer */
|
||||
} else {
|
||||
nb->size +=
|
||||
prev->next
|
||||
->size; /* Expand of current block for size of next free block which is right behind new block */
|
||||
nb->next = prev->next->next; /* Next free is pointed to the next one of previous next */
|
||||
/* Expand of current block for size of next free block which is right behind new block */
|
||||
nblk->size += prev->next->size;
|
||||
nblk->next = prev->next->next; /* Next free is pointed to the next one of previous next */
|
||||
}
|
||||
} else {
|
||||
nb->next = prev->next; /* Set next of input block as next of current one */
|
||||
nblk->next = prev->next; /* Set next of input block as next of current one */
|
||||
}
|
||||
|
||||
/*
|
||||
* If new block has not been set as current (and expanded),
|
||||
* then link them together, otherwise ignore as it would point to itself
|
||||
*/
|
||||
if (prev != nb) {
|
||||
prev->next = nb;
|
||||
if (prev != nblk) {
|
||||
prev->next = nblk;
|
||||
}
|
||||
}
|
||||
|
||||
@ -341,7 +345,7 @@ prv_split_too_big_block(lwmem_t* const lwobj, lwmem_block_t* block, size_t new_b
|
||||
|
||||
/* If allocation bit was set before, set it now again */
|
||||
if (is_alloc_bit) {
|
||||
LWMEM_BLOCK_SET_ALLOC(block);
|
||||
prv_block_set_alloc(block);
|
||||
}
|
||||
return success;
|
||||
}
|
||||
@ -431,7 +435,7 @@ prv_alloc(lwmem_t* const lwobj, const lwmem_region_t* region, const size_t size)
|
||||
|
||||
lwobj->mem_available_bytes -= curr->size; /* Decrease available bytes by allocated block size */
|
||||
prv_split_too_big_block(lwobj, curr, final_size); /* Split block if it is too big */
|
||||
LWMEM_BLOCK_SET_ALLOC(curr); /* Set block as allocated */
|
||||
prv_block_set_alloc(curr); /* Set block as allocated */
|
||||
|
||||
LWMEM_UPDATE_MIN_FREE(lwobj);
|
||||
LWMEM_INC_STATS(lwobj->stats.nr_alloc);
|
||||
@ -477,7 +481,7 @@ prv_free(lwmem_t* const lwobj, void* const ptr) {
|
||||
*/
|
||||
static void*
|
||||
prv_realloc(lwmem_t* const lwobj, const lwmem_region_t* region, void* const ptr, const size_t size) {
|
||||
lwmem_block_t *block, *prevprev, *prev;
|
||||
lwmem_block_t *block = NULL, *prevprev = NULL, *prev = NULL;
|
||||
size_t block_size; /* Holds size of input block (ptr), including metadata size */
|
||||
const size_t final_size =
|
||||
LWMEM_ALIGN(size) + LWMEM_BLOCK_META_SIZE; /* Holds size of new requested block size, including metadata size */
|
||||
@ -501,7 +505,11 @@ prv_realloc(lwmem_t* const lwobj, const lwmem_region_t* region, void* const ptr,
|
||||
|
||||
/* Process existing block */
|
||||
block = LWMEM_GET_BLOCK_FROM_PTR(ptr);
|
||||
if (LWMEM_BLOCK_IS_ALLOC(block)) {
|
||||
if (!LWMEM_BLOCK_IS_ALLOC(block)) {
|
||||
|
||||
/* Hard error. Input pointer is not NULL and block is not considered allocated */
|
||||
return NULL;
|
||||
}
|
||||
block_size = block->size & ~LWMEM_ALLOC_BIT; /* Get actual block size, without memory allocation bit */
|
||||
|
||||
/* Check current block size is the same as new requested size */
|
||||
@ -539,7 +547,7 @@ prv_realloc(lwmem_t* const lwobj, const lwmem_region_t* region, void* const ptr,
|
||||
*/
|
||||
|
||||
/* Find free blocks before input block */
|
||||
LWMEM_GET_PREV_CURR_OF_BLOCK(lwobj, block, prevprev, prev);
|
||||
prv_get_prev_curr_of_block(lwobj, block, &prevprev, &prev);
|
||||
|
||||
/* Check if current block and next free are connected */
|
||||
if ((LWMEM_TO_BYTE_PTR(block) + block_size) == LWMEM_TO_BYTE_PTR(prev->next)
|
||||
@ -552,20 +560,21 @@ prv_realloc(lwmem_t* const lwobj, const lwmem_region_t* region, void* const ptr,
|
||||
prev->next = (void*)(LWMEM_TO_BYTE_PTR(prev->next) - (block_size - final_size));
|
||||
prev->next->size = tmp_size + (block_size - final_size);
|
||||
prev->next->next = tmp_next;
|
||||
lwobj->mem_available_bytes +=
|
||||
block_size - final_size; /* Increase available bytes by increase of free block */
|
||||
|
||||
/* Increase available bytes by increase of free block */
|
||||
lwobj->mem_available_bytes += block_size - final_size;
|
||||
|
||||
block->size = final_size; /* Block size is requested size */
|
||||
}
|
||||
}
|
||||
LWMEM_BLOCK_SET_ALLOC(block); /* Set block as allocated */
|
||||
prv_block_set_alloc(block); /* Set block as allocated */
|
||||
return ptr; /* Return existing pointer */
|
||||
}
|
||||
|
||||
/* New requested size is bigger than current block size is */
|
||||
|
||||
/* Find last free (and its previous) block, located just before input block */
|
||||
LWMEM_GET_PREV_CURR_OF_BLOCK(lwobj, block, prevprev, prev);
|
||||
prv_get_prev_curr_of_block(lwobj, block, &prevprev, &prev);
|
||||
|
||||
/* If entry could not be found, there is a hard error */
|
||||
if (prev == NULL) {
|
||||
@ -577,9 +586,8 @@ prv_realloc(lwmem_t* const lwobj, const lwmem_region_t* region, void* const ptr,
|
||||
/* Input block points to address somewhere between "prev" and "prev->next" pointers */
|
||||
|
||||
/* Check if "block" and next free "prev->next" create contiguous memory with size of at least new requested size */
|
||||
if ((LWMEM_TO_BYTE_PTR(block) + block_size)
|
||||
== LWMEM_TO_BYTE_PTR(prev->next) /* Blocks create contiguous block */
|
||||
&& (block_size + prev->next->size) >= final_size) { /* Size is greater or equal to requested */
|
||||
if ((LWMEM_TO_BYTE_PTR(block) + block_size) == LWMEM_TO_BYTE_PTR(prev->next)
|
||||
&& (block_size + prev->next->size) >= final_size) {
|
||||
|
||||
/*
|
||||
* Merge blocks together by increasing current block with size of next free one
|
||||
@ -588,11 +596,11 @@ prv_realloc(lwmem_t* const lwobj, const lwmem_region_t* region, void* const ptr,
|
||||
lwobj->mem_available_bytes -= prev->next->size; /* For now decrease effective available bytes */
|
||||
LWMEM_UPDATE_MIN_FREE(lwobj);
|
||||
block->size = block_size + prev->next->size; /* Increase effective size of new block */
|
||||
prev->next =
|
||||
prev->next->next; /* Set next to next's next, effectively remove expanded block from free list */
|
||||
prev->next = prev->next->next; /* Set next to next's next,
|
||||
effectively remove expanded block from free list */
|
||||
|
||||
prv_split_too_big_block(lwobj, block, final_size); /* Split block if it is too big */
|
||||
LWMEM_BLOCK_SET_ALLOC(block); /* Set block as allocated */
|
||||
prv_block_set_alloc(block); /* Set block as allocated */
|
||||
return ptr; /* Return existing pointer */
|
||||
}
|
||||
|
||||
@ -601,8 +609,7 @@ prv_realloc(lwmem_t* const lwobj, const lwmem_region_t* region, void* const ptr,
|
||||
*
|
||||
* It is necessary to make a memory move and shift content up as new return pointer is now upper on address space
|
||||
*/
|
||||
if ((LWMEM_TO_BYTE_PTR(prev) + prev->size) == LWMEM_TO_BYTE_PTR(block) /* Blocks create contiguous block */
|
||||
&& (prev->size + block_size) >= final_size) { /* Size is greater or equal to requested */
|
||||
if ((LWMEM_TO_BYTE_PTR(prev) + prev->size) == LWMEM_TO_BYTE_PTR(block) && (prev->size + block_size) >= final_size) {
|
||||
/* Move memory from block to block previous to current */
|
||||
void* const old_data_ptr = LWMEM_GET_PTR_FROM_BLOCK(block);
|
||||
void* const new_data_ptr = LWMEM_GET_PTR_FROM_BLOCK(prev);
|
||||
@ -620,12 +627,12 @@ prv_realloc(lwmem_t* const lwobj, const lwmem_region_t* region, void* const ptr,
|
||||
lwobj->mem_available_bytes -= prev->size; /* For now decrease effective available bytes */
|
||||
LWMEM_UPDATE_MIN_FREE(lwobj);
|
||||
prev->size += block_size; /* Increase size of input block size */
|
||||
prevprev->next =
|
||||
prev->next; /* Remove prev from free list as it is now being used for allocation together with existing block */
|
||||
prevprev->next = prev->next; /* Remove prev from free list as it is now being used
|
||||
for allocation together with existing block */
|
||||
block = prev; /* Move block pointer to previous one */
|
||||
|
||||
prv_split_too_big_block(lwobj, block, final_size); /* Split block if it is too big */
|
||||
LWMEM_BLOCK_SET_ALLOC(block); /* Set block as allocated */
|
||||
prv_block_set_alloc(block); /* Set block as allocated */
|
||||
return new_data_ptr; /* Return new data ptr */
|
||||
}
|
||||
|
||||
@ -637,11 +644,9 @@ prv_realloc(lwmem_t* const lwobj, const lwmem_region_t* region, void* const ptr,
|
||||
* Last option is to check if previous free block "prev", input block "block" and next free block "prev->next" create contiguous block
|
||||
* and size of new block (from 3 contiguous blocks) together is big enough
|
||||
*/
|
||||
if ((LWMEM_TO_BYTE_PTR(prev) + prev->size)
|
||||
== LWMEM_TO_BYTE_PTR(block) /* Input block and free block before create contiguous block */
|
||||
&& (LWMEM_TO_BYTE_PTR(block) + block_size)
|
||||
== LWMEM_TO_BYTE_PTR(prev->next) /* Input block and free block after create contiguous block */
|
||||
&& (prev->size + block_size + prev->next->size) >= final_size) { /* Size is greater or equal to requested */
|
||||
if ((LWMEM_TO_BYTE_PTR(prev) + prev->size) == LWMEM_TO_BYTE_PTR(block)
|
||||
&& (LWMEM_TO_BYTE_PTR(block) + block_size) == LWMEM_TO_BYTE_PTR(prev->next)
|
||||
&& (prev->size + block_size + prev->next->size) >= final_size) {
|
||||
|
||||
/* Move memory from block to block previous to current */
|
||||
void* const old_data_ptr = LWMEM_GET_PTR_FROM_BLOCK(block);
|
||||
@ -655,27 +660,21 @@ prv_realloc(lwmem_t* const lwobj, const lwmem_region_t* region, void* const ptr,
|
||||
*
|
||||
* Metadata of "prev" are not modified during memmove
|
||||
*/
|
||||
LWMEM_MEMMOVE(new_data_ptr, old_data_ptr, block_size); /* Copy old buffer size to new location */
|
||||
LWMEM_MEMMOVE(new_data_ptr, old_data_ptr, block_size);
|
||||
|
||||
lwobj->mem_available_bytes -=
|
||||
prev->size
|
||||
+ prev->next
|
||||
->size; /* Decrease effective available bytes for free blocks before and after input block */
|
||||
/* Decrease effective available bytes for free blocks before and after input block */
|
||||
lwobj->mem_available_bytes -= prev->size + prev->next->size;
|
||||
LWMEM_UPDATE_MIN_FREE(lwobj);
|
||||
prev->size += block_size + prev->next->size; /* Increase size of new block by size of 2 free blocks */
|
||||
prevprev->next =
|
||||
prev->next
|
||||
->next; /* Remove free block before current one and block after current one from linked list (remove 2) */
|
||||
|
||||
/* Remove free block before current one and block after current one from linked list (remove 2) */
|
||||
prevprev->next = prev->next->next;
|
||||
block = prev; /* Previous block is now current */
|
||||
|
||||
prv_split_too_big_block(lwobj, block, final_size); /* Split block if it is too big */
|
||||
LWMEM_BLOCK_SET_ALLOC(block); /* Set block as allocated */
|
||||
prv_block_set_alloc(block); /* Set block as allocated */
|
||||
return new_data_ptr; /* Return new data ptr */
|
||||
}
|
||||
} else {
|
||||
/* Hard error. Input pointer is not NULL and block is not considered allocated */
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/*
|
||||
* If application reaches this point, it means:
|
||||
@ -688,85 +687,29 @@ prv_realloc(lwmem_t* const lwobj, const lwmem_region_t* region, void* const ptr,
|
||||
*/
|
||||
retval = prv_alloc(lwobj, region, size); /* Try to allocate new block */
|
||||
if (retval != NULL) {
|
||||
block_size =
|
||||
(block->size & ~LWMEM_ALLOC_BIT) - LWMEM_BLOCK_META_SIZE; /* Get application size from input pointer */
|
||||
LWMEM_MEMCPY(retval, ptr, size > block_size ? block_size : size); /* Copy content to new allocated block */
|
||||
prv_free(lwobj, ptr); /* Free input pointer */
|
||||
/* Get application size from input pointer, then copy content to new block */
|
||||
block_size = (block->size & ~LWMEM_ALLOC_BIT) - LWMEM_BLOCK_META_SIZE;
|
||||
LWMEM_MEMCPY(retval, ptr, size > block_size ? block_size : size);
|
||||
prv_free(lwobj, ptr); /* Free old block */
|
||||
}
|
||||
return retval;
|
||||
}
|
||||
|
||||
/**
|
||||
* \brief Initializes and assigns user regions for memory used by allocator algorithm
|
||||
* \param[in] lwobj: LwMEM instance. Set to `NULL` to use default instance
|
||||
* \param[in] regions: Pointer to array of regions with address and respective size.
|
||||
* Regions must be in increasing order (start address) and must not overlap in-between.
|
||||
* Last region entry must have address `NULL` and size set to `0`
|
||||
* \code{.c}
|
||||
//Example definition
|
||||
lwmem_region_t regions[] = {
|
||||
{ (void *)0x10000000, 0x1000 }, //Region starts at address 0x10000000 and is 0x1000 bytes long
|
||||
{ (void *)0x20000000, 0x2000 }, //Region starts at address 0x20000000 and is 0x2000 bytes long
|
||||
{ (void *)0x30000000, 0x3000 }, //Region starts at address 0x30000000 and is 0x3000 bytes long
|
||||
{ NULL, 0 } //Array termination indicator
|
||||
}
|
||||
\endcode
|
||||
* \return `0` on failure, number of final regions used for memory manager on success
|
||||
* \note This function is not thread safe when used with operating system.
|
||||
* It must be called only once to setup memory regions
|
||||
*/
|
||||
size_t
|
||||
lwmem_assignmem_ex(lwmem_t* lwobj, const lwmem_region_t* regions) {
|
||||
uint8_t* mem_start_addr;
|
||||
size_t mem_size, len = 0;
|
||||
lwmem_block_t *first_block, *prev_end_block;
|
||||
|
||||
lwobj = LWMEM_GET_LWOBJ(lwobj);
|
||||
/* Check first things first */
|
||||
if (regions == NULL || lwobj->end_block != NULL /* Init function may only be called once per lwmem instance */
|
||||
|| (((size_t)LWMEM_CFG_ALIGN_NUM) & (((size_t)LWMEM_CFG_ALIGN_NUM) - 1)) > 0) { /* Must be power of 2 */
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Check values entered by application */
|
||||
mem_start_addr = (void*)0;
|
||||
mem_size = 0;
|
||||
for (size_t i = 0;; ++i) {
|
||||
/*
|
||||
* Check for valid entry or end of array descriptor
|
||||
* \brief Assign the memory structure for advanced memory allocation system
|
||||
*
|
||||
* Invalid entry is considered as "end-of-region" indicator
|
||||
* \param lwobj
|
||||
* \param regions
|
||||
* \return size_t
|
||||
*/
|
||||
if (regions[i].size == 0 && regions[i].start_addr == NULL) {
|
||||
len = i;
|
||||
if (len == 0) {
|
||||
return 0;
|
||||
}
|
||||
break;
|
||||
}
|
||||
static size_t
|
||||
prv_assignmem(lwmem_t* lwobj, const lwmem_region_t* regions) {
|
||||
uint8_t* mem_start_addr = NULL;
|
||||
size_t mem_size = 0;
|
||||
lwmem_block_t *first_block = NULL, *prev_end_block = NULL;
|
||||
|
||||
/* New region(s) must be higher (in address space) than previous one */
|
||||
if ((mem_start_addr + mem_size) > LWMEM_TO_BYTE_PTR(regions[i].start_addr)) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Save new values for next round */
|
||||
mem_start_addr = regions[i].start_addr;
|
||||
mem_size = regions[i].size;
|
||||
}
|
||||
|
||||
/* Process further checks of valid inputs */
|
||||
if (regions == NULL || len == 0
|
||||
#if LWMEM_CFG_OS
|
||||
|| lwmem_sys_mutex_isvalid(&(lwobj->mutex)) /* Check if mutex valid already = must not be */
|
||||
|| !lwmem_sys_mutex_create(&(lwobj->mutex)) /* Final step = try to create mutex for new instance */
|
||||
#endif /* LWMEM_CFG_OS */
|
||||
) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
for (size_t i = 0; i < len; ++i, ++regions) {
|
||||
/* Get region start address and size */
|
||||
for (size_t idx = 0; regions->size > 0 && regions->start_addr != NULL; ++idx, ++regions) {
|
||||
/* Get region start address and size, stop on failure */
|
||||
if (!prv_get_region_addr_size(regions, &mem_start_addr, &mem_size)) {
|
||||
continue;
|
||||
}
|
||||
@ -827,6 +770,161 @@ lwmem_assignmem_ex(lwmem_t* lwobj, const lwmem_region_t* regions) {
|
||||
return lwobj->mem_regions_count; /* Return number of regions used by manager */
|
||||
}
|
||||
|
||||
#else /* LWMEM_CFG_FULL */
|
||||
|
||||
/**
|
||||
* \brief Assign the regions for simple algorithm
|
||||
*
|
||||
* At this point, regions check has been performed, so we assume
|
||||
* everything is ready to proceed
|
||||
*
|
||||
* \param lwobj: LwMEM object
|
||||
* \param regions: List of regions to assign
|
||||
* \return Number of regions used
|
||||
*/
|
||||
static size_t
|
||||
prv_assignmem_simple(lwmem_t* const lwobj, const lwmem_region_t* regions) {
|
||||
uint8_t* mem_start_addr = regions[0].start_addr;
|
||||
size_t mem_size = regions[0].size;
|
||||
|
||||
/* Adjust alignment data */
|
||||
if (((size_t)mem_start_addr) & LWMEM_ALIGN_BITS) {
|
||||
mem_start_addr += ((size_t)LWMEM_CFG_ALIGN_NUM) - ((size_t)mem_start_addr & LWMEM_ALIGN_BITS);
|
||||
mem_size -= (size_t)(mem_start_addr - LWMEM_TO_BYTE_PTR(regions[0].start_addr));
|
||||
}
|
||||
|
||||
/* Align mem to alignment*/
|
||||
mem_size = mem_size & ~LWMEM_ALIGN_BITS;
|
||||
|
||||
/* Store the available information */
|
||||
lwobj->mem_available_bytes = mem_size;
|
||||
lwobj->mem_next_available_ptr = mem_start_addr;
|
||||
lwobj->is_initialized = 1;
|
||||
return 1; /* One region is being used only for now */
|
||||
}
|
||||
|
||||
/**
|
||||
* \brief Simple allocation algorithm, that can only allocate memory,
|
||||
* but it does not support free.
|
||||
*
|
||||
* It uses simple first-in-first-serve concept,
|
||||
* where memory grows upward gradually, up until it reaches the end
|
||||
* of memory area
|
||||
*
|
||||
* \param lwobj: LwMEM object
|
||||
* \param region: Selected region. Not used in the current revision,
|
||||
* but footprint remains the same if one day library will support it
|
||||
* \param size: Requested allocation size
|
||||
* \return `NULL` on failure, or pointer to allocated memory
|
||||
*/
|
||||
static void*
|
||||
prv_alloc_simple(lwmem_t* const lwobj, const lwmem_region_t* region, const size_t size) {
|
||||
void* retval = NULL;
|
||||
const size_t alloc_size = LWMEM_ALIGN(size);
|
||||
|
||||
if (alloc_size <= lwobj->mem_available_bytes) {
|
||||
retval = lwobj->mem_next_available_ptr;
|
||||
|
||||
/* Get ready for next iteration */
|
||||
lwobj->mem_next_available_ptr += alloc_size;
|
||||
lwobj->mem_available_bytes -= alloc_size;
|
||||
}
|
||||
(void)region;
|
||||
return retval;
|
||||
}
|
||||
|
||||
#endif /* LWMEM_CFG_FULL */
|
||||
|
||||
/**
|
||||
* \brief Initializes and assigns user regions for memory used by allocator algorithm
|
||||
* \param[in] lwobj: LwMEM instance. Set to `NULL` to use default instance
|
||||
* \param[in] regions: Pointer to array of regions with address and respective size.
|
||||
* Regions must be in increasing order (start address) and must not overlap in-between.
|
||||
* Last region entry must have address `NULL` and size set to `0`
|
||||
* \code{.c}
|
||||
//Example definition
|
||||
lwmem_region_t regions[] = {
|
||||
{ (void *)0x10000000, 0x1000 }, //Region starts at address 0x10000000 and is 0x1000 bytes long
|
||||
{ (void *)0x20000000, 0x2000 }, //Region starts at address 0x20000000 and is 0x2000 bytes long
|
||||
{ (void *)0x30000000, 0x3000 }, //Region starts at address 0x30000000 and is 0x3000 bytes long
|
||||
{ NULL, 0 } //Array termination indicator
|
||||
}
|
||||
\endcode
|
||||
* \return `0` on failure, number of final regions used for memory manager on success
|
||||
* \note This function is not thread safe when used with operating system.
|
||||
* It must be called only once to setup memory regions
|
||||
*/
|
||||
size_t
|
||||
lwmem_assignmem_ex(lwmem_t* lwobj, const lwmem_region_t* regions) {
|
||||
uint8_t* mem_start_addr = NULL;
|
||||
size_t mem_size = 0, len = 0;
|
||||
|
||||
lwobj = LWMEM_GET_LWOBJ(lwobj);
|
||||
|
||||
/* Check first things first */
|
||||
if (regions == NULL
|
||||
#if LWMEM_CFG_FULL
|
||||
|| lwobj->end_block != NULL /* Init function may only be called once per lwmem instance */
|
||||
#else
|
||||
|| lwobj->is_initialized /* Already initialized? */
|
||||
#endif /* LWMEM_CFG_FULL */
|
||||
) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Check values entered by application */
|
||||
mem_start_addr = (void*)0;
|
||||
mem_size = 0;
|
||||
for (size_t idx = 0;; ++idx) {
|
||||
/*
|
||||
* Check for valid entry or end of array descriptor
|
||||
* Invalid entry is considered as "end-of-region" indicator
|
||||
*/
|
||||
if (regions[idx].size == 0 && regions[idx].start_addr == NULL) {
|
||||
len = idx;
|
||||
if (len == 0) {
|
||||
return 0;
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
#if !LWMEM_CFG_FULL
|
||||
/*
|
||||
* In case of simple allocation algorithm, we (for now!) only allow one region.
|
||||
* Return zero value if user passed more than one region in a sequence.
|
||||
*/
|
||||
else if (idx > 0) {
|
||||
return 0;
|
||||
}
|
||||
#endif /* LWMEM_CFG_FULL */
|
||||
|
||||
/* New region(s) must be higher (in address space) than previous one */
|
||||
if ((mem_start_addr + mem_size) > LWMEM_TO_BYTE_PTR(regions[idx].start_addr)) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Save new values for next round */
|
||||
mem_start_addr = regions[idx].start_addr;
|
||||
mem_size = regions[idx].size;
|
||||
}
|
||||
|
||||
/* Final init and check before initializing the regions */
|
||||
if (len == 0
|
||||
#if LWMEM_CFG_OS
|
||||
|| lwmem_sys_mutex_isvalid(&(lwobj->mutex)) /* Check if mutex valid already = must not be */
|
||||
|| !lwmem_sys_mutex_create(&(lwobj->mutex)) /* Final step = try to create mutex for new instance */
|
||||
#endif /* LWMEM_CFG_OS */
|
||||
) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
#if LWMEM_CFG_FULL
|
||||
return prv_assignmem(lwobj, regions);
|
||||
#else /* LWMEM_CFG_FULL */
|
||||
return prv_assignmem_simple(lwobj, regions);
|
||||
#endif /* LWMEM_CFG_FULL */
|
||||
}
|
||||
|
||||
/**
|
||||
* \brief Allocate memory of requested size in specific lwmem instance and optional region.
|
||||
* \note This is an extended malloc version function declaration to support advanced features
|
||||
@ -839,10 +937,16 @@ lwmem_assignmem_ex(lwmem_t* lwobj, const lwmem_region_t* regions) {
|
||||
*/
|
||||
void*
|
||||
lwmem_malloc_ex(lwmem_t* lwobj, const lwmem_region_t* region, const size_t size) {
|
||||
void* ptr;
|
||||
void* ptr = NULL;
|
||||
|
||||
lwobj = LWMEM_GET_LWOBJ(lwobj);
|
||||
|
||||
LWMEM_PROTECT(lwobj);
|
||||
#if LWMEM_CFG_FULL
|
||||
ptr = prv_alloc(lwobj, region, size);
|
||||
#else /* LWMEM_CFG_FULL */
|
||||
ptr = prv_alloc_simple(lwobj, region, size);
|
||||
#endif /* LWMEM_CFG_FULL */
|
||||
LWMEM_UNPROTECT(lwobj);
|
||||
return ptr;
|
||||
}
|
||||
@ -852,7 +956,7 @@ lwmem_malloc_ex(lwmem_t* lwobj, const lwmem_region_t* region, const size_t size)
|
||||
* in specific lwmem instance and region.
|
||||
*
|
||||
* It resets allocated block of memory to zero if allocation is successful
|
||||
|
||||
*
|
||||
* \note This is an extended calloc version function declaration to support advanced features
|
||||
* \param[in] lwobj: LwMEM instance. Set to `NULL` to use default instance
|
||||
* \param[in] region: Optional region instance within LwMEM instance to force allocation from.
|
||||
@ -864,18 +968,27 @@ lwmem_malloc_ex(lwmem_t* lwobj, const lwmem_region_t* region, const size_t size)
|
||||
*/
|
||||
void*
|
||||
lwmem_calloc_ex(lwmem_t* lwobj, const lwmem_region_t* region, const size_t nitems, const size_t size) {
|
||||
void* ptr;
|
||||
const size_t s = size * nitems;
|
||||
void* ptr = NULL;
|
||||
const size_t alloc_size = size * nitems;
|
||||
|
||||
lwobj = LWMEM_GET_LWOBJ(lwobj);
|
||||
|
||||
LWMEM_PROTECT(lwobj);
|
||||
if ((ptr = prv_alloc(lwobj, region, s)) != NULL) {
|
||||
LWMEM_MEMSET(ptr, 0x00, s);
|
||||
}
|
||||
#if LWMEM_CFG_FULL
|
||||
ptr = prv_alloc(lwobj, region, alloc_size);
|
||||
#else /* LWMEM_CFG_FULL */
|
||||
ptr = prv_alloc_simple(lwobj, region, alloc_size);
|
||||
#endif /* LWMEM_CFG_FULL */
|
||||
LWMEM_UNPROTECT(lwobj);
|
||||
|
||||
if (ptr != NULL) {
|
||||
LWMEM_MEMSET(ptr, 0x00, alloc_size);
|
||||
}
|
||||
return ptr;
|
||||
}
|
||||
|
||||
#if LWMEM_CFG_FULL || __DOXYGEN__
|
||||
|
||||
/**
|
||||
* \brief Reallocates already allocated memory with new size in specific lwmem instance and region.
|
||||
*
|
||||
@ -936,7 +1049,7 @@ lwmem_realloc_ex(lwmem_t* lwobj, const lwmem_region_t* region, void* const ptr,
|
||||
* \return `1` if successfully reallocated, `0` otherwise
|
||||
* \note This function is thread safe when \ref LWMEM_CFG_OS is enabled
|
||||
*/
|
||||
uint8_t
|
||||
int
|
||||
lwmem_realloc_s_ex(lwmem_t* lwobj, const lwmem_region_t* region, void** const ptr, const size_t size) {
|
||||
void* new_ptr;
|
||||
|
||||
@ -1025,13 +1138,15 @@ lwmem_get_size_ex(lwmem_t* lwobj, void* ptr) {
|
||||
return len;
|
||||
}
|
||||
|
||||
#endif /* LWMEM_CFG_FULL || __DOXYGEN__ */
|
||||
|
||||
#if LWMEM_CFG_ENABLE_STATS || __DOXYGEN__
|
||||
|
||||
/**
|
||||
* \brief Get statistics of a LwMEM instance
|
||||
* \param[in] lwobj: LwMEM instance. Set to `NULL` to use default instance.
|
||||
* Instance must be the same as used during allocation procedure
|
||||
* \param[in] stats: Pointer to \ref lwmem_stats_t to store result
|
||||
* \param[in,out] stats: Pointer to \ref lwmem_stats_t to store result
|
||||
*/
|
||||
void
|
||||
lwmem_get_stats_ex(lwmem_t* lwobj, lwmem_stats_t* stats) {
|
||||
@ -1044,12 +1159,135 @@ lwmem_get_stats_ex(lwmem_t* lwobj, lwmem_stats_t* stats) {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* \brief Get statistics of a default LwMEM instance
|
||||
* \param[in,out] stats: Pointer to \ref lwmem_stats_t to store result
|
||||
*/
|
||||
size_t
|
||||
lwmem_get_size(lwmem_stats_t* stats) {
|
||||
lwmem_get_stats_ex(NULL, stats);
|
||||
}
|
||||
|
||||
#endif /* LWMEM_CFG_ENABLE_STATS || __DOXYGEN__ */
|
||||
|
||||
/**
|
||||
* \note This is a wrapper for \ref lwmem_assignmem_ex function.
|
||||
* It operates in default LwMEM instance and uses first available region for memory operations
|
||||
* \param[in] regions: Pointer to array of regions with address and respective size.
|
||||
* Regions must be in increasing order (start address) and must not overlap in-between.
|
||||
* Last region entry must have address `NULL` and size set to `0`
|
||||
* \code{.c}
|
||||
//Example definition
|
||||
lwmem_region_t regions[] = {
|
||||
{ (void *)0x10000000, 0x1000 }, //Region starts at address 0x10000000 and is 0x1000 bytes long
|
||||
{ (void *)0x20000000, 0x2000 }, //Region starts at address 0x20000000 and is 0x2000 bytes long
|
||||
{ (void *)0x30000000, 0x3000 }, //Region starts at address 0x30000000 and is 0x3000 bytes long
|
||||
{ NULL, 0 } //Array termination indicator
|
||||
}
|
||||
\endcode
|
||||
* \return `0` on failure, number of final regions used for memory manager on success
|
||||
*/
|
||||
size_t
|
||||
lwmem_assignmem(const lwmem_region_t* regions) {
|
||||
return lwmem_assignmem_ex(NULL, regions);
|
||||
}
|
||||
|
||||
/**
|
||||
* \note This is a wrapper for \ref lwmem_malloc_ex function.
|
||||
* It operates in default LwMEM instance and uses first available region for memory operations
|
||||
* \param[in] size: Size to allocate in units of bytes
|
||||
* \return Pointer to allocated memory on success, `NULL` otherwise
|
||||
* \note This function is thread safe when \ref LWMEM_CFG_OS is enabled
|
||||
*/
|
||||
void*
|
||||
lwmem_malloc(size_t size) {
|
||||
return lwmem_malloc_ex(NULL, NULL, size);
|
||||
}
|
||||
|
||||
/**
|
||||
* \note This is a wrapper for \ref lwmem_calloc_ex function.
|
||||
* It operates in default LwMEM instance and uses first available region for memory operations
|
||||
* \param[in] nitems: Number of elements to be allocated
|
||||
* \param[in] size: Size of each element, in units of bytes
|
||||
* \return Pointer to allocated memory on success, `NULL` otherwise
|
||||
* \note This function is thread safe when \ref LWMEM_CFG_OS is enabled
|
||||
*/
|
||||
void*
|
||||
lwmem_calloc(size_t nitems, size_t size) {
|
||||
return lwmem_calloc_ex(NULL, NULL, nitems, size);
|
||||
}
|
||||
|
||||
#if LWMEM_CFG_FULL || __DOXYGEN__
|
||||
|
||||
/**
|
||||
* \note This is a wrapper for \ref lwmem_realloc_ex function.
|
||||
* It operates in default LwMEM instance and uses first available region for memory operations
|
||||
* \param[in] ptr: Memory block previously allocated with one of allocation functions.
|
||||
* It may be set to `NULL` to create new clean allocation
|
||||
* \param[in] size: Size of new memory to reallocate
|
||||
* \return Pointer to allocated memory on success, `NULL` otherwise
|
||||
* \note This function is thread safe when \ref LWMEM_CFG_OS is enabled
|
||||
*/
|
||||
void*
|
||||
lwmem_realloc(void* ptr, size_t size) {
|
||||
return lwmem_realloc_ex(NULL, NULL, ptr, size);
|
||||
}
|
||||
|
||||
/**
|
||||
* \note This is a wrapper for \ref lwmem_realloc_s_ex function.
|
||||
* It operates in default LwMEM instance and uses first available region for memory operations
|
||||
* \param[in] ptr2ptr: Pointer to pointer to allocated memory. Must not be set to `NULL`.
|
||||
* If reallocation is successful, it modifies pointer's pointing address,
|
||||
* or sets it to `NULL` in case of `free` operation
|
||||
* \param[in] size: New requested size in bytes
|
||||
* \return `1` if successfully reallocated, `0` otherwise
|
||||
* \note This function is thread safe when \ref LWMEM_CFG_OS is enabled
|
||||
*/
|
||||
int
|
||||
lwmem_realloc_s(void** ptr2ptr, size_t size) {
|
||||
return lwmem_realloc_s_ex(NULL, NULL, ptr2ptr, size);
|
||||
}
|
||||
|
||||
/**
|
||||
* \note This is a wrapper for \ref lwmem_free_ex function.
|
||||
* It operates in default LwMEM instance and uses first available region for memory operations
|
||||
* \param[in] ptr: Memory to free. `NULL` pointer is valid input
|
||||
* \note This function is thread safe when \ref LWMEM_CFG_OS is enabled
|
||||
*/
|
||||
void
|
||||
lwmem_free(void* ptr) {
|
||||
lwmem_free_ex(NULL, (ptr));
|
||||
}
|
||||
|
||||
/**
|
||||
* \note This is a wrapper for \ref lwmem_free_s_ex function.
|
||||
* It operates in default LwMEM instance and uses first available region for memory operations
|
||||
* \param[in] ptr2ptr: Pointer to pointer to allocated memory.
|
||||
* When set to non `NULL`, pointer is freed and set to `NULL`
|
||||
* \note This function is thread safe when \ref LWMEM_CFG_OS is enabled
|
||||
*/
|
||||
void
|
||||
lwmem_free_s(void** ptr2ptr) {
|
||||
lwmem_free_s_ex(NULL, (ptr2ptr));
|
||||
}
|
||||
|
||||
/**
|
||||
* \note This is a wrapper for \ref lwmem_get_size_ex function.
|
||||
* It operates in default LwMEM instance and uses first available region for memory operations
|
||||
* \param[in] ptr: Pointer to allocated memory
|
||||
* \return Block size for user in units of bytes
|
||||
*/
|
||||
size_t
|
||||
lwmem_get_size(void* ptr) {
|
||||
return lwmem_get_size_ex(NULL, ptr);
|
||||
}
|
||||
|
||||
#endif /* LWMEM_CFG_FULL || __DOXYGEN__ */
|
||||
|
||||
/* Part of library used ONLY for LWMEM_DEV purposes */
|
||||
/* To validate and test library */
|
||||
|
||||
#if defined(LWMEM_DEV) && !__DOXYGEN__
|
||||
#if defined(LWMEM_DEV) && LWMEM_CFG_FULL && !__DOXYGEN__
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
@ -1070,14 +1308,16 @@ create_regions(size_t count, size_t size) {
|
||||
*
|
||||
* Length 1 entry more, to set default values for NULL entry
|
||||
*/
|
||||
if ((regions = calloc(count + 1, sizeof(*regions))) == NULL) {
|
||||
regions = calloc(count + 1, sizeof(*regions));
|
||||
if (regions == NULL) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/* Allocate memory for regions */
|
||||
for (size_t i = 0; i < count; ++i) {
|
||||
regions[i].size = size;
|
||||
if ((regions[i].start_addr = malloc(regions[i].size)) == NULL) {
|
||||
regions[i].start_addr = malloc(regions[i].size);
|
||||
if (regions[i].start_addr == NULL) {
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
|
@ -29,5 +29,5 @@
|
||||
* This file is part of LwMEM - Lightweight dynamic memory manager library.
|
||||
*
|
||||
* Author: Tilen MAJERLE <tilen@majerle.eu>
|
||||
* Version: v2.1.0
|
||||
* Version: v2.2.0
|
||||
*/
|
||||
|
@ -4,7 +4,7 @@
|
||||
*/
|
||||
|
||||
/*
|
||||
* Copyright (c) 2023 Tilen MAJERLE
|
||||
* Copyright (c) 2024 Tilen MAJERLE
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person
|
||||
* obtaining a copy of this software and associated documentation
|
||||
@ -29,7 +29,7 @@
|
||||
* This file is part of LwMEM - Lightweight dynamic memory manager library.
|
||||
*
|
||||
* Author: Tilen MAJERLE <tilen@majerle.eu>
|
||||
* Version: v2.1.0
|
||||
* Version: v2.2.0
|
||||
*/
|
||||
#include "system/lwmem_sys.h"
|
||||
|
||||
|
@ -4,7 +4,7 @@
|
||||
*/
|
||||
|
||||
/*
|
||||
* Copyright (c) 2023 Tilen MAJERLE
|
||||
* Copyright (c) 2024 Tilen MAJERLE
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person
|
||||
* obtaining a copy of this software and associated documentation
|
||||
@ -29,7 +29,7 @@
|
||||
* This file is part of LwMEM - Lightweight dynamic memory manager library.
|
||||
*
|
||||
* Author: Tilen MAJERLE <tilen@majerle.eu>
|
||||
* Version: v2.1.0
|
||||
* Version: v2.2.0
|
||||
*/
|
||||
#include "system/lwmem_sys.h"
|
||||
|
||||
|
@ -4,7 +4,7 @@
|
||||
*/
|
||||
|
||||
/*
|
||||
* Copyright (c) 2023 Tilen MAJERLE
|
||||
* Copyright (c) 2024 Tilen MAJERLE
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person
|
||||
* obtaining a copy of this software and associated documentation
|
||||
@ -29,13 +29,13 @@
|
||||
* This file is part of LwMEM - Lightweight dynamic memory manager library.
|
||||
*
|
||||
* Author: Tilen MAJERLE <tilen@majerle.eu>
|
||||
* Version: v2.1.0
|
||||
* Version: v2.2.0
|
||||
*/
|
||||
#include "system/lwmem_sys.h"
|
||||
|
||||
#if LWMEM_CFG_OS && !__DOXYGEN__
|
||||
|
||||
#include "Windows.h"
|
||||
#include "windows.h"
|
||||
|
||||
uint8_t
|
||||
lwmem_sys_mutex_create(LWMEM_CFG_OS_MUTEX_HANDLE* m) {
|
||||
@ -50,12 +50,7 @@ lwmem_sys_mutex_isvalid(LWMEM_CFG_OS_MUTEX_HANDLE* m) {
|
||||
|
||||
uint8_t
|
||||
lwmem_sys_mutex_wait(LWMEM_CFG_OS_MUTEX_HANDLE* m) {
|
||||
DWORD ret;
|
||||
ret = WaitForSingleObject(*m, INFINITE);
|
||||
if (ret != WAIT_OBJECT_0) {
|
||||
return 0;
|
||||
}
|
||||
return 1;
|
||||
return WaitForSingleObject(*m, INFINITE) == WAIT_OBJECT_0;
|
||||
}
|
||||
|
||||
uint8_t
|
||||
|
@ -1,8 +1,11 @@
|
||||
#include "lwmem/lwmem.h"
|
||||
#include <stdio.h>
|
||||
#include "lwmem/lwmem.h"
|
||||
|
||||
#if LWMEM_CFG_FULL
|
||||
|
||||
/* Assert check */
|
||||
#define ASSERT(x) do { \
|
||||
#define ASSERT(x) \
|
||||
do { \
|
||||
if (!(x)) { \
|
||||
printf("Assert on line %d failed with condition (" #x ")\r\n", (int)__LINE__); \
|
||||
} else { \
|
||||
@ -13,58 +16,60 @@
|
||||
/********************************************/
|
||||
/* Test case helpers */
|
||||
#define UINT_PTR_CAST(x) ((uintptr_t)(x))
|
||||
#define IS_ALLOC_IN_REGION(ptr, region) ASSERT( \
|
||||
UINT_PTR_CAST(ptr) >= UINT_PTR_CAST((region)->start_addr) \
|
||||
&& UINT_PTR_CAST(ptr) < (UINT_PTR_CAST((region)->start_addr) + (region)->size) \
|
||||
)
|
||||
#define IS_ALLOC_IN_REGION(ptr, region) \
|
||||
ASSERT(UINT_PTR_CAST(ptr) >= UINT_PTR_CAST((region)->start_addr) \
|
||||
&& UINT_PTR_CAST(ptr) < (UINT_PTR_CAST((region)->start_addr) + (region)->size))
|
||||
|
||||
/********************************************/
|
||||
/* Configuration for default lwmem instance */
|
||||
|
||||
/* Region memory declaration */
|
||||
uint8_t lw_mem1[1024], lw_mem2[256], lw_mem3[128];
|
||||
static struct {
|
||||
uint8_t m1[128];
|
||||
uint8_t m2[256];
|
||||
uint8_t m3[1024];
|
||||
} lw_mem;
|
||||
|
||||
/* Regions descriptor */
|
||||
lwmem_region_t
|
||||
lw_regions[] = {
|
||||
{ lw_mem3, sizeof(lw_mem3) },
|
||||
{ lw_mem2, sizeof(lw_mem2) },
|
||||
{ lw_mem1, sizeof(lw_mem1) },
|
||||
{ NULL, 0 }
|
||||
static lwmem_region_t lw_regions[] = {
|
||||
{lw_mem.m1, sizeof(lw_mem.m1)},
|
||||
{lw_mem.m2, sizeof(lw_mem.m2)},
|
||||
{lw_mem.m3, sizeof(lw_mem.m3)},
|
||||
{NULL, 0},
|
||||
};
|
||||
|
||||
/********************************************/
|
||||
/********************************************/
|
||||
/* Configuration for custom lwmem instance */
|
||||
/* LwMEM instance */
|
||||
lwmem_t lw_c;
|
||||
static lwmem_t lw_c;
|
||||
|
||||
/* Region memory declaration */
|
||||
uint8_t lw_c_mem1[1024], lw_c_mem2[256], lw_c_mem3[128];
|
||||
static struct {
|
||||
uint8_t m1[128];
|
||||
uint8_t m2[256];
|
||||
uint8_t m3[1024];
|
||||
} lw_mem_c;
|
||||
|
||||
/* Regions descriptor */
|
||||
lwmem_region_t
|
||||
lw_c_regions[] = {
|
||||
{ lw_c_mem3, sizeof(lw_c_mem3) },
|
||||
{ lw_c_mem2, sizeof(lw_c_mem2) },
|
||||
{ lw_c_mem1, sizeof(lw_c_mem1) },
|
||||
{ NULL, 0 }
|
||||
static lwmem_region_t lw_c_regions[] = {
|
||||
{lw_mem_c.m1, sizeof(lw_mem_c.m1)},
|
||||
{lw_mem_c.m2, sizeof(lw_mem_c.m2)},
|
||||
{lw_mem_c.m3, sizeof(lw_mem_c.m3)},
|
||||
{NULL, 0},
|
||||
};
|
||||
|
||||
/********************************************/
|
||||
|
||||
void
|
||||
lwmem_test_run(void) {
|
||||
void* ptr_1, * ptr_2, * ptr_3;
|
||||
void* ptr_c_1, * ptr_c_2, * ptr_c_3;
|
||||
void *ptr_1 = NULL, *ptr_2 = NULL, *ptr_3 = NULL;
|
||||
void *ptr_c_1 = NULL, *ptr_c_2 = NULL, *ptr_c_3 = NULL;
|
||||
|
||||
/* Initialize default lwmem instance */
|
||||
/* Use one of 2 possible function calls: */
|
||||
lwmem_assignmem(lw_regions);
|
||||
//lwmem_assignmem_ex(NULL, lw_regions);
|
||||
|
||||
/* Initialize another, custom instance */
|
||||
lwmem_assignmem_ex(&lw_c, lw_c_regions);
|
||||
|
||||
/* Regions initialized... */
|
||||
|
||||
/********************************************/
|
||||
@ -73,15 +78,18 @@ lwmem_test_run(void) {
|
||||
|
||||
/* Allocation of 64 bytes must in in first region */
|
||||
ptr_1 = lwmem_malloc(64);
|
||||
ASSERT(ptr_1 != NULL);
|
||||
IS_ALLOC_IN_REGION(ptr_1, &lw_regions[0]);
|
||||
|
||||
/* Allocation of 256 bytes can only be in 3rd region */
|
||||
ptr_2 = lwmem_malloc(256);
|
||||
ASSERT(ptr_2 != NULL);
|
||||
IS_ALLOC_IN_REGION(ptr_2, &lw_regions[2]);
|
||||
|
||||
/* Allocation of 128 bytes can be in second or third region (depends on memory availability),
|
||||
but in case of these tests it can be (and should be) in second region */
|
||||
ptr_3 = lwmem_malloc(128);
|
||||
ASSERT(ptr_3 != NULL);
|
||||
IS_ALLOC_IN_REGION(ptr_3, &lw_regions[1]);
|
||||
|
||||
/* Free all pointers to default state */
|
||||
@ -92,10 +100,12 @@ lwmem_test_run(void) {
|
||||
/* Force allocation region to be used */
|
||||
/* Allocation of 16-bytes forced to 2nd region */
|
||||
ptr_1 = lwmem_malloc_ex(NULL, &lw_regions[1], 16);
|
||||
ASSERT(ptr_1 != NULL);
|
||||
IS_ALLOC_IN_REGION(ptr_1, &lw_regions[1]);
|
||||
|
||||
/* Allocate ptr 2 in any region of default lwmem, the first available must be 1st region */
|
||||
ptr_2 = lwmem_malloc_ex(NULL, NULL, 16);
|
||||
ASSERT(ptr_2 != NULL);
|
||||
IS_ALLOC_IN_REGION(ptr_2, &lw_regions[0]);
|
||||
|
||||
/* Free pointers */
|
||||
@ -106,28 +116,36 @@ lwmem_test_run(void) {
|
||||
/* Run tests on custom region */
|
||||
/********************************************/
|
||||
|
||||
/* Initialize another, custom instance */
|
||||
lwmem_assignmem_ex(&lw_c, lw_c_regions);
|
||||
|
||||
/* Allocation of 64 bytes must in in first region */
|
||||
ptr_c_1 = lwmem_malloc_ex(&lw_c, NULL, 64);
|
||||
ASSERT(ptr_c_1 != NULL);
|
||||
IS_ALLOC_IN_REGION(ptr_c_1, &lw_c_regions[0]);
|
||||
|
||||
/* Allocation of 256 bytes can only be in 3rd region */
|
||||
ptr_c_2 = lwmem_malloc_ex(&lw_c, NULL, 256);
|
||||
ASSERT(ptr_c_2 != NULL);
|
||||
IS_ALLOC_IN_REGION(ptr_c_2, &lw_c_regions[2]);
|
||||
|
||||
/* Allocation of 128 bytes can be in second or third region (depends on memory availability),
|
||||
but in case of these tests it can be (and should be) in second region */
|
||||
ptr_c_3 = lwmem_malloc_ex(&lw_c, NULL, 128);
|
||||
ASSERT(ptr_c_3 != NULL);
|
||||
IS_ALLOC_IN_REGION(ptr_c_3, &lw_c_regions[1]);
|
||||
|
||||
/* Free all pointers to default state */
|
||||
lwmem_free(ptr_c_1);
|
||||
lwmem_free(ptr_c_2);
|
||||
lwmem_free(ptr_c_3);
|
||||
|
||||
printf("Done\r\n");
|
||||
}
|
||||
|
||||
/* For debug purposes */
|
||||
lwmem_region_t* regions_used;
|
||||
size_t regions_count = 4; /* Use only 1 region for debug purposes of non-free areas */
|
||||
static lwmem_region_t* regions_used;
|
||||
static size_t regions_count = 4; /* Use only 1 region for debug purposes of non-free areas */
|
||||
|
||||
void
|
||||
lwmem_test_memory_structure(void) {
|
||||
@ -156,11 +174,15 @@ lwmem_test_memory_structure(void) {
|
||||
|
||||
/* Test case 1, allocate 3 blocks, each of different size */
|
||||
/* We know that sizeof internal metadata block is 8 bytes on win32 */
|
||||
printf("\r\n\r\nAllocating 4 pointers and freeing first and third..\r\n");
|
||||
printf("\r\n------------------------------------------------------------------------\r\n");
|
||||
printf("Allocating 4 pointers\r\n\r\n");
|
||||
ptr1 = lwmem_malloc(8);
|
||||
ptr2 = lwmem_malloc(4);
|
||||
ptr3 = lwmem_malloc(4);
|
||||
ptr4 = lwmem_malloc(16);
|
||||
lwmem_debug_print(1, 1);
|
||||
printf("\r\n------------------------------------------------------------------------\r\n");
|
||||
printf("Freeing first and third pointers\r\n\r\n");
|
||||
lwmem_free(ptr1); /* Free but keep value for future comparison */
|
||||
lwmem_free(ptr3); /* Free but keep value for future comparison */
|
||||
lwmem_debug_print(1, 1);
|
||||
@ -183,7 +205,7 @@ lwmem_test_memory_structure(void) {
|
||||
printf("State 3b\r\n");
|
||||
rptr2 = lwmem_realloc(ptr2, 20);
|
||||
lwmem_debug_print(1, 1);
|
||||
ASSERT(rptr2 == ptr2);
|
||||
ASSERT(rptr2 == ptr1);
|
||||
|
||||
/* Create 3c case */
|
||||
printf("\r\n------------------------------------------------------------------------\r\n");
|
||||
@ -200,4 +222,11 @@ lwmem_test_memory_structure(void) {
|
||||
rptr4 = lwmem_realloc(ptr2, 36);
|
||||
lwmem_debug_print(1, 1);
|
||||
ASSERT(rptr4 != ptr1 && rptr4 != ptr2 && rptr4 != ptr3 && rptr4 != ptr4);
|
||||
|
||||
printf("ptr1: %08X\r\nptr2: %08X\r\nptr3: %08X\r\nptr4: %08X\r\n", (unsigned)ptr1, (unsigned)ptr2, (unsigned)ptr3,
|
||||
(unsigned)ptr4);
|
||||
printf("r_ptr1: %08X\r\nr_ptr2: %08X\r\nr_ptr3: %08X\r\nr_ptr4: %08X\r\n", (unsigned)rptr1, (unsigned)rptr2,
|
||||
(unsigned)rptr3, (unsigned)rptr4);
|
||||
}
|
||||
|
||||
#endif /* LWMEM_CFG_FULL */
|
68
tests/lwmem_test_simple.c
Normal file
68
tests/lwmem_test_simple.c
Normal file
@ -0,0 +1,68 @@
|
||||
#include <stdio.h>
|
||||
#include "lwmem/lwmem.h"
|
||||
|
||||
#if !LWMEM_CFG_FULL
|
||||
|
||||
/* Assert check */
|
||||
#define ASSERT(x) \
|
||||
do { \
|
||||
if (!(x)) { \
|
||||
printf("Assert on line %d failed with condition (" #x ")\r\n", (int)__LINE__); \
|
||||
} else { \
|
||||
printf("Assert on line %d passed with condition (" #x ")\r\n", (int)__LINE__); \
|
||||
} \
|
||||
} while (0)
|
||||
|
||||
/********************************************/
|
||||
/* Configuration for default lwmem instance */
|
||||
|
||||
/* Region memory declaration */
|
||||
static uint8_t lw_mem1[1024], lw_mem2[256], lw_mem3[128];
|
||||
|
||||
/* Regions descriptor */
|
||||
static lwmem_region_t lw_regions_too_many[] = {
|
||||
{lw_mem3, sizeof(lw_mem3)},
|
||||
{lw_mem2, sizeof(lw_mem2)},
|
||||
{lw_mem1, sizeof(lw_mem1)},
|
||||
{NULL, 0},
|
||||
};
|
||||
|
||||
/********************************************/
|
||||
/********************************************/
|
||||
/* Region memory declaration */
|
||||
/* Use uint32 for alignment reasons */
|
||||
static uint32_t lw_c_mem1[64 / 4];
|
||||
|
||||
/* Regions descriptor */
|
||||
static lwmem_region_t lw_c_regions[] = {
|
||||
{lw_c_mem1, sizeof(lw_c_mem1)},
|
||||
{NULL, 0},
|
||||
};
|
||||
|
||||
/********************************************/
|
||||
|
||||
void
|
||||
lwmem_test_simple_run(void) {
|
||||
size_t retval;
|
||||
void* ptr;
|
||||
|
||||
/* Should fail -> too many regions */
|
||||
retval = lwmem_assignmem(lw_regions_too_many);
|
||||
ASSERT(retval == 0);
|
||||
|
||||
/* Should fly now */
|
||||
retval = lwmem_assignmem(lw_c_regions);
|
||||
ASSERT(retval != 0);
|
||||
|
||||
/* We have 64 bytes from now on */
|
||||
|
||||
/* Try to allocate memory */
|
||||
ptr = lwmem_malloc(32);
|
||||
ASSERT(ptr != NULL);
|
||||
ptr = lwmem_malloc(32);
|
||||
ASSERT(ptr != NULL);
|
||||
ptr = lwmem_malloc(4);
|
||||
ASSERT(ptr == NULL);
|
||||
}
|
||||
|
||||
#endif /* !LWMEM_CFG_FULL */
|
Loading…
x
Reference in New Issue
Block a user