From 4b21f2f2c2bd20af796a4921471881038bf3c7cd Mon Sep 17 00:00:00 2001 From: Y <469960757@qq.com> Date: Fri, 10 Feb 2023 16:14:22 +0800 Subject: [PATCH 01/45] =?UTF-8?q?fix:=20compiler=20error=20error:=20unknow?= =?UTF-8?q?n=20type=20name=20=E2=80=98size=5Ft=E2=80=99?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- lwmem/src/include/lwmem/lwmem.h | 1 + 1 file changed, 1 insertion(+) diff --git a/lwmem/src/include/lwmem/lwmem.h b/lwmem/src/include/lwmem/lwmem.h index d854627..e42e1c1 100644 --- a/lwmem/src/include/lwmem/lwmem.h +++ b/lwmem/src/include/lwmem/lwmem.h @@ -36,6 +36,7 @@ #include #include +#include #include "lwmem/lwmem_opt.h" #ifdef __cplusplus From f2451fb2a83723d43a5b97155cb97a901aecb20e Mon Sep 17 00:00:00 2001 From: Tilen Majerle Date: Sun, 19 Feb 2023 12:21:41 +0100 Subject: [PATCH 02/45] Fix wrong change in version for vscode files --- .vscode/tasks.json | 2 +- .../stm32/lwmem_rtos_stm32l496_discovery/.vscode/tasks.json | 2 +- examples/stm32/lwmem_stm32l496_discovery/.vscode/tasks.json | 2 +- examples/win32/.vscode/tasks.json | 2 +- 4 files changed, 4 insertions(+), 4 deletions(-) diff --git a/.vscode/tasks.json b/.vscode/tasks.json index 7a24c4a..09422ee 100644 --- a/.vscode/tasks.json +++ b/.vscode/tasks.json @@ -1,5 +1,5 @@ { - "version": "2.1.0", + "version": "2.0.0", "tasks": [ { "type": "cppbuild", diff --git a/examples/stm32/lwmem_rtos_stm32l496_discovery/.vscode/tasks.json b/examples/stm32/lwmem_rtos_stm32l496_discovery/.vscode/tasks.json index 448dbf0..fe4c345 100644 --- a/examples/stm32/lwmem_rtos_stm32l496_discovery/.vscode/tasks.json +++ b/examples/stm32/lwmem_rtos_stm32l496_discovery/.vscode/tasks.json @@ -1,5 +1,5 @@ { - "version": "2.1.0", + "version": "2.0.0", "tasks": [ { "type": "cppbuild", diff --git a/examples/stm32/lwmem_stm32l496_discovery/.vscode/tasks.json b/examples/stm32/lwmem_stm32l496_discovery/.vscode/tasks.json index 448dbf0..fe4c345 100644 --- a/examples/stm32/lwmem_stm32l496_discovery/.vscode/tasks.json +++ b/examples/stm32/lwmem_stm32l496_discovery/.vscode/tasks.json @@ -1,5 +1,5 @@ { - "version": "2.1.0", + "version": "2.0.0", "tasks": [ { "type": "cppbuild", diff --git a/examples/win32/.vscode/tasks.json b/examples/win32/.vscode/tasks.json index 5bc8468..e526563 100644 --- a/examples/win32/.vscode/tasks.json +++ b/examples/win32/.vscode/tasks.json @@ -1,5 +1,5 @@ { - "version": "2.1.0", + "version": "2.0.0", "tasks": [ { "type": "cppbuild", From 78887318cb200a75ba29df788b8769cbebef6172 Mon Sep 17 00:00:00 2001 From: Tilen Majerle Date: Sun, 19 Feb 2023 12:42:43 +0100 Subject: [PATCH 03/45] Fix documentation --- docs/conf.py | 2 +- docs/get-started/index.rst | 2 +- docs/index.rst | 1 + 3 files changed, 3 insertions(+), 2 deletions(-) diff --git a/docs/conf.py b/docs/conf.py index 032fb7c..0c06c69 100644 --- a/docs/conf.py +++ b/docs/conf.py @@ -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 diff --git a/docs/get-started/index.rst b/docs/get-started/index.rst index ac1ea31..ea34715 100644 --- a/docs/get-started/index.rst +++ b/docs/get-started/index.rst @@ -62,7 +62,7 @@ Next step is to add the library to the project, by means of source files to comp * 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 -* Add source files from ``lwmem/src/`` folder to toolchain build. These files are built by `C/C++` compiler +* Add source files from ``lwmem/src/`` folder to toolchain build. These files are built by `C/C++` compiler. CMake configuration comes with the library, allows users to include library in the project as **subdirectory** and **library**. * Copy ``lwmem/src/include/lwmem/lwmem_opts_template.h`` to project folder and rename it to ``lwmem_opts.h`` * Build the project diff --git a/docs/index.rst b/docs/index.rst index 3d67aae..f482951 100644 --- a/docs/index.rst +++ b/docs/index.rst @@ -87,3 +87,4 @@ Table of contents LwRB - Ring buffer LwSHELL - Shell LwUTIL - Utility functions + LwWDG - RTOS task watchdog From eb7b09e7456c9870d2410c62b4b56d998bbe3e5f Mon Sep 17 00:00:00 2001 From: Tilen Majerle Date: Sun, 23 Apr 2023 17:51:34 +0200 Subject: [PATCH 04/45] Remove entering/exiting debug messages --- .../stm32/lwmem_rtos_stm32l496_discovery/CMakeLists.txt | 4 ---- examples/stm32/lwmem_stm32l496_discovery/CMakeLists.txt | 4 ---- lwmem/CMakeLists.txt | 6 ------ 3 files changed, 14 deletions(-) diff --git a/examples/stm32/lwmem_rtos_stm32l496_discovery/CMakeLists.txt b/examples/stm32/lwmem_rtos_stm32l496_discovery/CMakeLists.txt index 7859dc6..ab24046 100644 --- a/examples/stm32/lwmem_rtos_stm32l496_discovery/CMakeLists.txt +++ b/examples/stm32/lwmem_rtos_stm32l496_discovery/CMakeLists.txt @@ -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 $ ${EXECUTABLE}.bin ) - -message("Exiting ${CMAKE_CURRENT_LIST_DIR}/CMakeLists.txt") diff --git a/examples/stm32/lwmem_stm32l496_discovery/CMakeLists.txt b/examples/stm32/lwmem_stm32l496_discovery/CMakeLists.txt index 553edb4..d016ed2 100644 --- a/examples/stm32/lwmem_stm32l496_discovery/CMakeLists.txt +++ b/examples/stm32/lwmem_stm32l496_discovery/CMakeLists.txt @@ -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 $ ${EXECUTABLE}.bin ) - -message("Exiting ${CMAKE_CURRENT_LIST_DIR}/CMakeLists.txt") diff --git a/lwmem/CMakeLists.txt b/lwmem/CMakeLists.txt index ed6ca1e..d6601c9 100644 --- a/lwmem/CMakeLists.txt +++ b/lwmem/CMakeLists.txt @@ -1,8 +1,5 @@ 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) @@ -18,6 +15,3 @@ 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") From d05a760aa5b729bef0014651c14fb153453fbd1b Mon Sep 17 00:00:00 2001 From: Tilen Majerle Date: Sun, 7 May 2023 15:27:33 +0200 Subject: [PATCH 05/45] Change logo icon --- docs/static/images/logo_tm.png | Bin 3338 -> 19296 bytes docs/static/images/logo_tm_full.png | Bin 17470 -> 23650 bytes 2 files changed, 0 insertions(+), 0 deletions(-) diff --git a/docs/static/images/logo_tm.png b/docs/static/images/logo_tm.png index 51ef5776e1fa5f334f4e94495669feed77eca0f7..4b0be88e5a0db1405c599f9579ab1d31eed57ebf 100644 GIT binary patch literal 19296 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 K&pB!x^#1_MR`ELk literal 3338 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 diff --git a/docs/static/images/logo_tm_full.png b/docs/static/images/logo_tm_full.png index 3e5ba6544885a88614d35bf27e0cbcdefa1286c6..970d835160ed6f11b74be4fcba1e9662a2960c5c 100644 GIT binary patch literal 23650 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 XM6dma(=Bf(!_rdIQ!RgB`|5uHl2YG# From 2c62f1cdd6118e5e9e415d6ed84581570a5654da Mon Sep 17 00:00:00 2001 From: Tilen Majerle Date: Sun, 7 May 2023 15:44:04 +0200 Subject: [PATCH 06/45] Fix requirements.txt file to avoid liburl3 failure --- docs/requirements.txt | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/docs/requirements.txt b/docs/requirements.txt index 834b1bb..bf1bde0 100644 --- a/docs/requirements.txt +++ b/docs/requirements.txt @@ -1,7 +1,8 @@ -breathe>=4.9.1 -colorama -docutils==0.16 sphinx>=3.5.1 +breathe>=4.9.1 +urllib3==1.26.15 +docutils==0.16 +colorama sphinx_rtd_theme>=1.0.0 sphinx-tabs sphinxcontrib-svg2pdfconverter From d5a595e03cb2d279f50bfe1fbee4c25a3aed5869 Mon Sep 17 00:00:00 2001 From: Tilen Majerle Date: Sun, 7 May 2023 15:49:34 +0200 Subject: [PATCH 07/45] Change contribution text --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 4b81873..0a6dae4 100644 --- a/README.md +++ b/README.md @@ -22,7 +22,7 @@ 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: From 6f4d286f47ce8db8974c637bc3238f0496402bc5 Mon Sep 17 00:00:00 2001 From: Tilen Majerle Date: Sun, 28 May 2023 12:04:53 +0200 Subject: [PATCH 08/45] Apply new .clang-format --- .clang-format | 4 ++-- lwmem/src/include/lwmem/lwmem.h | 2 +- lwmem/src/lwmem/lwmem.c | 34 ++++++++++++++++----------------- 3 files changed, 20 insertions(+), 20 deletions(-) diff --git a/.clang-format b/.clang-format index 1fad350..0227352 100644 --- a/.clang-format +++ b/.clang-format @@ -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 diff --git a/lwmem/src/include/lwmem/lwmem.h b/lwmem/src/include/lwmem/lwmem.h index e42e1c1..2570a9f 100644 --- a/lwmem/src/include/lwmem/lwmem.h +++ b/lwmem/src/include/lwmem/lwmem.h @@ -35,8 +35,8 @@ #define LWMEM_HDR_H #include -#include #include +#include #include "lwmem/lwmem_opt.h" #ifdef __cplusplus diff --git a/lwmem/src/lwmem/lwmem.c b/lwmem/src/lwmem/lwmem.c index 02e755c..427186c 100644 --- a/lwmem/src/lwmem/lwmem.c +++ b/lwmem/src/lwmem/lwmem.c @@ -124,13 +124,13 @@ * * Default size is size of meta block */ -#define LWMEM_BLOCK_MIN_SIZE (LWMEM_BLOCK_META_SIZE) +#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)) +#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 @@ -139,9 +139,9 @@ * \param[in] in_pp: Previous previous of input block * \param[in] in_p: Previous of input block */ -#define LWMEM_GET_PREV_CURR_OF_BLOCK(in_lwobj, in_b, in_pp, in_p) \ +#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); \ + 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) @@ -156,10 +156,10 @@ /* Statistics part */ #if LWMEM_CFG_ENABLE_STATS #define LWMEM_INC_STATS(field) (++(field)) -#define LWMEM_UPDATE_MIN_FREE(lwobj) \ +#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; \ + 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 @@ -369,7 +369,7 @@ prv_alloc(lwmem_t* const lwobj, const lwmem_region_t* region, const size_t size) /* Set default values */ prev = &(lwobj->start_block); /* Use pointer from custom lwmem block */ - curr = prev->next; /* Curr represents first actual free block */ + curr = prev->next; /* Curr represents first actual free block */ /* * If region is not set to NULL, @@ -431,7 +431,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 */ + LWMEM_BLOCK_SET_ALLOC(curr); /* Set block as allocated */ LWMEM_UPDATE_MIN_FREE(lwobj); LWMEM_INC_STATS(lwobj->stats.nr_alloc); @@ -592,8 +592,8 @@ prv_realloc(lwmem_t* const lwobj, const lwmem_region_t* region, void* const ptr, 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 */ - return ptr; /* Return existing pointer */ + LWMEM_BLOCK_SET_ALLOC(block); /* Set block as allocated */ + return ptr; /* Return existing pointer */ } /* @@ -625,8 +625,8 @@ prv_realloc(lwmem_t* const lwobj, const lwmem_region_t* region, void* const ptr, 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 */ - return new_data_ptr; /* Return new data ptr */ + LWMEM_BLOCK_SET_ALLOC(block); /* Set block as allocated */ + return new_data_ptr; /* Return new data ptr */ } /* @@ -669,8 +669,8 @@ prv_realloc(lwmem_t* const lwobj, const lwmem_region_t* region, void* const ptr, 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 */ - return new_data_ptr; /* Return new data ptr */ + LWMEM_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 */ @@ -691,7 +691,7 @@ prv_realloc(lwmem_t* const lwobj, const lwmem_region_t* region, void* const ptr, 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 */ + prv_free(lwobj, ptr); /* Free input pointer */ } return retval; } @@ -760,7 +760,7 @@ lwmem_assignmem_ex(lwmem_t* lwobj, const lwmem_region_t* regions) { #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 */ +#endif /* LWMEM_CFG_OS */ ) { return 0; } From e8b1080ca1144893d2f5e46f835c7003ce13cfa4 Mon Sep 17 00:00:00 2001 From: Tilen Majerle Date: Thu, 20 Jul 2023 22:15:58 +0200 Subject: [PATCH 09/45] Update link for new LwCELL, add C11 standard note --- README.md | 2 +- docs/index.rst | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/README.md b/README.md index 0a6dae4..d8c90ea 100644 --- a/README.md +++ b/README.md @@ -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 diff --git a/docs/index.rst b/docs/index.rst index f482951..3d344b6 100644 --- a/docs/index.rst +++ b/docs/index.rst @@ -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 @@ -78,7 +78,7 @@ Table of contents LwESP - ESP-AT library LwEVT - Event manager LwGPS - GPS NMEA parser - LwGSM - GSM-AT library + LwCELL - Cellular modem host AT library LwJSON - JSON parser LwMEM - Memory manager LwOW - OneWire with UART From f37e8ca9158b82690edc7b5c69a4cfd6ba10be91 Mon Sep 17 00:00:00 2001 From: Tilen Majerle Date: Sun, 27 Aug 2023 19:48:33 +0200 Subject: [PATCH 10/45] Fix double colon --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index d8c90ea..0e1d0b6 100644 --- a/README.md +++ b/README.md @@ -19,7 +19,7 @@ ## Contribute -Fresh contributions are always welcome. Simple instructions to proceed:: +Fresh contributions are always welcome. Simple instructions to proceed: 1. Fork Github repository 2. Follow [C style & coding rules](https://github.com/MaJerle/c-code-style) already used in the project From b819ffe94740f23c68d9df0ea28614c63e43bac1 Mon Sep 17 00:00:00 2001 From: Tilen Majerle Date: Mon, 28 Aug 2023 21:42:55 +0200 Subject: [PATCH 11/45] Add readthedocs YAML file --- .readthedocs.yaml | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) create mode 100644 .readthedocs.yaml diff --git a/.readthedocs.yaml b/.readthedocs.yaml new file mode 100644 index 0000000..dd64b05 --- /dev/null +++ b/.readthedocs.yaml @@ -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 From cc28adc2ca1086bb8fdc8b86f393e743795e7bd5 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Tue, 3 Oct 2023 03:26:14 +0000 Subject: [PATCH 12/45] Bump urllib3 from 1.26.15 to 1.26.17 in /docs Bumps [urllib3](https://github.com/urllib3/urllib3) from 1.26.15 to 1.26.17. - [Release notes](https://github.com/urllib3/urllib3/releases) - [Changelog](https://github.com/urllib3/urllib3/blob/main/CHANGES.rst) - [Commits](https://github.com/urllib3/urllib3/compare/1.26.15...1.26.17) --- updated-dependencies: - dependency-name: urllib3 dependency-type: direct:production ... Signed-off-by: dependabot[bot] --- docs/requirements.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/requirements.txt b/docs/requirements.txt index bf1bde0..27e9780 100644 --- a/docs/requirements.txt +++ b/docs/requirements.txt @@ -1,6 +1,6 @@ sphinx>=3.5.1 breathe>=4.9.1 -urllib3==1.26.15 +urllib3==1.26.17 docutils==0.16 colorama sphinx_rtd_theme>=1.0.0 From 2bba4b30247cca0fdca5f88191a7e830a8594cb5 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Wed, 18 Oct 2023 01:19:15 +0000 Subject: [PATCH 13/45] Bump urllib3 from 1.26.17 to 1.26.18 in /docs Bumps [urllib3](https://github.com/urllib3/urllib3) from 1.26.17 to 1.26.18. - [Release notes](https://github.com/urllib3/urllib3/releases) - [Changelog](https://github.com/urllib3/urllib3/blob/main/CHANGES.rst) - [Commits](https://github.com/urllib3/urllib3/compare/1.26.17...1.26.18) --- updated-dependencies: - dependency-name: urllib3 dependency-type: direct:production ... Signed-off-by: dependabot[bot] --- docs/requirements.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/requirements.txt b/docs/requirements.txt index 27e9780..d70b1a4 100644 --- a/docs/requirements.txt +++ b/docs/requirements.txt @@ -1,6 +1,6 @@ sphinx>=3.5.1 breathe>=4.9.1 -urllib3==1.26.17 +urllib3==1.26.18 docutils==0.16 colorama sphinx_rtd_theme>=1.0.0 From 3c2f33c294f7de07dbd81dbd633cd650c58acaef Mon Sep 17 00:00:00 2001 From: Tilen Majerle Date: Mon, 20 Nov 2023 21:18:28 +0100 Subject: [PATCH 14/45] Apply clang-tidy --- .clang-tidy | 19 ++++++++++ .vscode/settings.json | 11 ++++-- lwmem/src/include/lwmem/lwmem_opt.h | 27 ++++++++++++++ lwmem/src/lwmem/lwmem.c | 55 +++++++++++++---------------- 4 files changed, 80 insertions(+), 32 deletions(-) create mode 100644 .clang-tidy diff --git a/.clang-tidy b/.clang-tidy new file mode 100644 index 0000000..1aaa846 --- /dev/null +++ b/.clang-tidy @@ -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 \ No newline at end of file diff --git a/.vscode/settings.json b/.vscode/settings.json index 3b59a00..91ebf1d 100644 --- a/.vscode/settings.json +++ b/.vscode/settings.json @@ -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" }, - "esbonio.sphinx.confDir": "" + "esbonio.sphinx.confDir": "", + "C_Cpp.codeAnalysis.clangTidy.useBuildPath": true } \ No newline at end of file diff --git a/lwmem/src/include/lwmem/lwmem_opt.h b/lwmem/src/include/lwmem/lwmem_opt.h index b17b5ce..b543ea4 100644 --- a/lwmem/src/include/lwmem/lwmem_opt.h +++ b/lwmem/src/include/lwmem/lwmem_opt.h @@ -103,6 +103,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 + /** * \} */ diff --git a/lwmem/src/lwmem/lwmem.c b/lwmem/src/lwmem/lwmem.c index 427186c..f5a2386 100644 --- a/lwmem/src/lwmem/lwmem.c +++ b/lwmem/src/lwmem/lwmem.c @@ -39,10 +39,6 @@ #include "system/lwmem_sys.h" #endif /* LWMEM_CFG_OS */ -#define LWMEM_MEMSET memset -#define LWMEM_MEMCPY memcpy -#define LWMEM_MEMMOVE memmove - /** * \brief Transform alignment number (power of `2`) to bits */ @@ -176,19 +172,19 @@ static lwmem_t lwmem_default; * \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) { +prv_get_region_addr_size(const lwmem_region_t* region, uint8_t** msa, size_t* msz) { size_t mem_size; uint8_t* mem_start_addr; - if (region == NULL || msa == NULL || ms == NULL) { + if (region == NULL || msa == NULL || msz == NULL) { return 0; } *msa = NULL; - *ms = 0; + *msz = 0; /* Check region size and align it to config bits */ mem_size = region->size & ~LWMEM_ALIGN_BITS; /* Size does not include lower bits */ @@ -209,7 +205,7 @@ prv_get_region_addr_size(const lwmem_region_t* region, uint8_t** msa, size_t* ms /* 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 +215,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 +230,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 +250,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,10 +262,10 @@ 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 * at the same time; follow next steps @@ -281,25 +277,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; } } From 2bc312feaa39b0fe3eaf3f70ce1f44826428443d Mon Sep 17 00:00:00 2001 From: Tilen Majerle Date: Mon, 20 Nov 2023 21:32:57 +0100 Subject: [PATCH 15/45] Update tidy. --- .vscode/settings.json | 6 +++--- dev/main.cpp | 4 ++-- lwmem/src/lwmem/lwmem.c | 1 + 3 files changed, 6 insertions(+), 5 deletions(-) diff --git a/.vscode/settings.json b/.vscode/settings.json index 91ebf1d..3608dd5 100644 --- a/.vscode/settings.json +++ b/.vscode/settings.json @@ -10,8 +10,8 @@ "lwmem_opt.h": "c", "array": "c", "string_view": "c", - "initializer_list": "c" + "initializer_list": "c", + "limits.h": "c" }, - "esbonio.sphinx.confDir": "", - "C_Cpp.codeAnalysis.clangTidy.useBuildPath": true + "esbonio.sphinx.confDir": "" } \ No newline at end of file diff --git a/dev/main.cpp b/dev/main.cpp index 62a4871..bddb83c 100644 --- a/dev/main.cpp +++ b/dev/main.cpp @@ -1,8 +1,8 @@ -#include "lwmem/lwmem.h" -#include "lwmem/lwmem.hpp" #include #include #include +#include "lwmem/lwmem.h" +#include "lwmem/lwmem.hpp" extern "C" void lwmem_test_run(void); extern "C" void lwmem_test_memory_structure(void); diff --git a/lwmem/src/lwmem/lwmem.c b/lwmem/src/lwmem/lwmem.c index f5a2386..3474a7d 100644 --- a/lwmem/src/lwmem/lwmem.c +++ b/lwmem/src/lwmem/lwmem.c @@ -33,6 +33,7 @@ */ #include "lwmem/lwmem.h" #include +#include #include #if LWMEM_CFG_OS From 76f54a0527f31340accaa58648f1d960c6d090eb Mon Sep 17 00:00:00 2001 From: Tilen Majerle Date: Mon, 20 Nov 2023 21:48:15 +0100 Subject: [PATCH 16/45] fix clang-tidy --- lwmem/src/lwmem/lwmem.c | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/lwmem/src/lwmem/lwmem.c b/lwmem/src/lwmem/lwmem.c index 3474a7d..59ee1d1 100644 --- a/lwmem/src/lwmem/lwmem.c +++ b/lwmem/src/lwmem/lwmem.c @@ -865,7 +865,8 @@ lwmem_calloc_ex(lwmem_t* lwobj, const lwmem_region_t* region, const size_t nitem lwobj = LWMEM_GET_LWOBJ(lwobj); LWMEM_PROTECT(lwobj); - if ((ptr = prv_alloc(lwobj, region, s)) != NULL) { + ptr = prv_alloc(lwobj, region, s); + if (ptr != NULL) { LWMEM_MEMSET(ptr, 0x00, s); } LWMEM_UNPROTECT(lwobj); @@ -1066,14 +1067,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; } } From a84ace2c87ad1befb66b59f289974a93fd3b58f7 Mon Sep 17 00:00:00 2001 From: Tilen Majerle Date: Tue, 28 Nov 2023 18:45:11 +0100 Subject: [PATCH 17/45] Add include path --- library.json | 3 +++ 1 file changed, 3 insertions(+) diff --git a/library.json b/library.json index 3e1f333..a7197fa 100644 --- a/library.json +++ b/library.json @@ -29,5 +29,8 @@ "build", "**/build" ] + }, + "build": { + "includeDir": "lwmem/src/include" } } \ No newline at end of file From 195ba53036870505052efcdc23e916cc58d2c8bf Mon Sep 17 00:00:00 2001 From: Tilen Majerle Date: Fri, 1 Dec 2023 17:11:02 +0100 Subject: [PATCH 18/45] Update docs --- docs/get-started/index.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/get-started/index.rst b/docs/get-started/index.rst index ea34715..f4ba963 100644 --- a/docs/get-started/index.rst +++ b/docs/get-started/index.rst @@ -70,7 +70,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:: From 275a7de240a032ec2585c7ea8772b7f0616003f2 Mon Sep 17 00:00:00 2001 From: Tilen Majerle Date: Fri, 8 Dec 2023 16:03:46 +0100 Subject: [PATCH 19/45] Improve docs and CMake configure_file --- CMakeLists.txt | 1 + docs/get-started/index.rst | 10 +++++++++- lwmem/CMakeLists.txt | 10 +++++++--- 3 files changed, 17 insertions(+), 4 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 89ba41f..3bef347 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -40,6 +40,7 @@ else() ) # Add subdir with lwmem and link to the project + set(LWMEM_OPTS_DIR ${CMAKE_CURRENT_LIST_DIR}/dev) add_subdirectory(lwmem) target_link_libraries(${PROJECT_NAME} lwmem) target_link_libraries(${PROJECT_NAME} lwmem_cpp) diff --git a/docs/get-started/index.rst b/docs/get-started/index.rst index f4ba963..e000848 100644 --- a/docs/get-started/index.rst +++ b/docs/get-started/index.rst @@ -66,6 +66,10 @@ Next step is to add the library to the project, by means of source files to comp * Copy ``lwmem/src/include/lwmem/lwmem_opts_template.h`` to project folder and rename it to ``lwmem_opts.h`` * Build the project +.. tip:: + If you are using *CMake* build system, you can add the library to the project by adding the *library's folder* + directory with ``add_directory()`` CMake command, followed by linking the target with ``target_link_libraries()`` + Configuration file ^^^^^^^^^^^^^^^^^^ @@ -78,7 +82,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_DIR`` before adding library's directory to the *CMake* project. + Variable must set the output directory path. CMake will copy the template file there, and name it as required. + +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 diff --git a/lwmem/CMakeLists.txt b/lwmem/CMakeLists.txt index d6601c9..4b7b6cd 100644 --- a/lwmem/CMakeLists.txt +++ b/lwmem/CMakeLists.txt @@ -5,8 +5,9 @@ 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) +# Add system port +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 @@ -14,4 +15,7 @@ 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 +# Create config file +if(DEFINED LWMEM_OPTS_DIR AND NOT EXISTS ${LWMEM_OPTS_DIR}/lwmem_opts.h) + configure_file(${CMAKE_CURRENT_LIST_DIR}/src/include/lwmem/lwmem_opts_template.h ${LWMEM_OPTS_DIR}/lwmem_opts.h COPYONLY) +endif() From 181c2c7dd92ddbc35a2c23278890ae35a3d78e81 Mon Sep 17 00:00:00 2001 From: Tilen Majerle Date: Sat, 9 Dec 2023 11:10:19 +0100 Subject: [PATCH 20/45] Create .cmake file to allow higher flexibility of end user --- lwmem/CMakeLists.txt | 20 +------------------- lwmem/library.cmake | 40 ++++++++++++++++++++++++++++++++++++++++ 2 files changed, 41 insertions(+), 19 deletions(-) create mode 100644 lwmem/library.cmake diff --git a/lwmem/CMakeLists.txt b/lwmem/CMakeLists.txt index 4b7b6cd..f05f91d 100644 --- a/lwmem/CMakeLists.txt +++ b/lwmem/CMakeLists.txt @@ -1,21 +1,3 @@ cmake_minimum_required(VERSION 3.22) -# 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) - -# Add system port -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) - -# Create config file -if(DEFINED LWMEM_OPTS_DIR AND NOT EXISTS ${LWMEM_OPTS_DIR}/lwmem_opts.h) - configure_file(${CMAKE_CURRENT_LIST_DIR}/src/include/lwmem/lwmem_opts_template.h ${LWMEM_OPTS_DIR}/lwmem_opts.h COPYONLY) -endif() +include(${CMAKE_CURRENT_LIST_DIR}/library.cmake) \ No newline at end of file diff --git a/lwmem/library.cmake b/lwmem/library.cmake new file mode 100644 index 0000000..0f6e3a2 --- /dev/null +++ b/lwmem/library.cmake @@ -0,0 +1,40 @@ +# 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 +) + +# 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 INTERFACE) +target_sources(lwmem PUBLIC ${lwmem_core_SRCS}) +target_include_directories(lwmem INTERFACE ${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 INTERFACE) +target_sources(lwmem_cpp PUBLIC ${lwmem_core_SRCS}) +target_include_directories(lwmem_cpp INTERFACE ${lwmem_include_DIRS}) +target_compile_options(lwmem_cpp PRIVATE ${LWMEM_COMPILE_OPTIONS}) +target_compile_definitions(lwmem_cpp PRIVATE ${LWMEM_COMPILE_DEFINITIONS}) + +# Create config file +if(DEFINED LWMEM_OPTS_DIR AND NOT EXISTS ${LWMEM_OPTS_DIR}/lwmem_opts.h) + configure_file(${CMAKE_CURRENT_LIST_DIR}/src/include/lwmem/lwmem_opts_template.h ${LWMEM_OPTS_DIR}/lwmem_opts.h COPYONLY) +endif() From 7aeab7a56e67489f0ea7bb5c51d0aaf45915e1e6 Mon Sep 17 00:00:00 2001 From: Tilen Majerle Date: Sat, 9 Dec 2023 16:49:22 +0100 Subject: [PATCH 21/45] Improve the cmake documentation --- docs/get-started/index.rst | 16 +++++++++++----- lwmem/library.cmake | 12 ++++++++++++ 2 files changed, 23 insertions(+), 5 deletions(-) diff --git a/docs/get-started/index.rst b/docs/get-started/index.rst index e000848..654ef1f 100644 --- a/docs/get-started/index.rst +++ b/docs/get-started/index.rst @@ -58,7 +58,17 @@ 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 +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: + +* ``CMakeLists.txt``: Is a wrapper and only includes ``library.cmake`` file. It is used if target application uses ``add_subdirectory`` and then uses ``target_link_libraries`` to include the library in the project +* ``library.cmake``: It is a fully configured set of variables. User must use ``include(path/to/library.cmake)`` to include the library and must manually add files/includes to the final target + +.. tip:: + Open ``library.cmake`` file and manually analyze all the possible variables you can set for full functionality. + +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 @@ -66,10 +76,6 @@ Next step is to add the library to the project, by means of source files to comp * Copy ``lwmem/src/include/lwmem/lwmem_opts_template.h`` to project folder and rename it to ``lwmem_opts.h`` * Build the project -.. tip:: - If you are using *CMake* build system, you can add the library to the project by adding the *library's folder* - directory with ``add_directory()`` CMake command, followed by linking the target with ``target_link_libraries()`` - Configuration file ^^^^^^^^^^^^^^^^^^ diff --git a/lwmem/library.cmake b/lwmem/library.cmake index 0f6e3a2..d16b79f 100644 --- a/lwmem/library.cmake +++ b/lwmem/library.cmake @@ -1,3 +1,15 @@ +# +# 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_DIR: If defined, it should set the folder path where options file shall be generated. +# 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 +# + # Library core sources set(lwmem_core_SRCS ${CMAKE_CURRENT_LIST_DIR}/src/lwmem/lwmem.c From 3dc6199a15e7e414ab51bb3f9117a82be2add42b Mon Sep 17 00:00:00 2001 From: Tilen Majerle Date: Sat, 9 Dec 2023 17:06:39 +0100 Subject: [PATCH 22/45] Add AUTHORS file --- AUTHORS | 4 ++++ 1 file changed, 4 insertions(+) create mode 100644 AUTHORS diff --git a/AUTHORS b/AUTHORS new file mode 100644 index 0000000..4e68df8 --- /dev/null +++ b/AUTHORS @@ -0,0 +1,4 @@ +Tilen Majerle +Tilen Majerle +Y <469960757@qq.com> +upbeat27 \ No newline at end of file From daa2a8890209c3e713c35e0b61df74a896f0b7d2 Mon Sep 17 00:00:00 2001 From: Tilen Majerle Date: Sat, 9 Dec 2023 17:13:47 +0100 Subject: [PATCH 23/45] Add authors in the docs file --- docs/authors/index.rst | 8 ++++++++ docs/index.rst | 1 + 2 files changed, 9 insertions(+) create mode 100644 docs/authors/index.rst diff --git a/docs/authors/index.rst b/docs/authors/index.rst new file mode 100644 index 0000000..4031a8c --- /dev/null +++ b/docs/authors/index.rst @@ -0,0 +1,8 @@ +.. _authors: + +Authors +======= + +List of authors and contributors to the library + +.. literalinclude:: ../../AUTHORS \ No newline at end of file diff --git a/docs/index.rst b/docs/index.rst index 3d344b6..152195e 100644 --- a/docs/index.rst +++ b/docs/index.rst @@ -67,6 +67,7 @@ Table of contents api-reference/index examples/index changelog/index + authors/index .. toctree:: :maxdepth: 2 From 7afa30a1e8bce80fb71ff95e806fea08f2a16464 Mon Sep 17 00:00:00 2001 From: Tilen Majerle Date: Sun, 17 Dec 2023 12:21:47 +0100 Subject: [PATCH 24/45] Fix GCC CMAKE compiler file --- .../cmake/gcc-arm-none-eabi.cmake | 11 +++++++---- .../cmake/gcc-arm-none-eabi.cmake | 11 +++++++---- 2 files changed, 14 insertions(+), 8 deletions(-) diff --git a/examples/stm32/lwmem_rtos_stm32l496_discovery/cmake/gcc-arm-none-eabi.cmake b/examples/stm32/lwmem_rtos_stm32l496_discovery/cmake/gcc-arm-none-eabi.cmake index 3577ff8..4048ae5 100644 --- a/examples/stm32/lwmem_rtos_stm32l496_discovery/cmake/gcc-arm-none-eabi.cmake +++ b/examples/stm32/lwmem_rtos_stm32l496_discovery/cmake/gcc-arm-none-eabi.cmake @@ -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) diff --git a/examples/stm32/lwmem_stm32l496_discovery/cmake/gcc-arm-none-eabi.cmake b/examples/stm32/lwmem_stm32l496_discovery/cmake/gcc-arm-none-eabi.cmake index 3577ff8..4048ae5 100644 --- a/examples/stm32/lwmem_stm32l496_discovery/cmake/gcc-arm-none-eabi.cmake +++ b/examples/stm32/lwmem_stm32l496_discovery/cmake/gcc-arm-none-eabi.cmake @@ -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) From 0c115bf57d6d4ef36aa222e20e6be692b2f0193c Mon Sep 17 00:00:00 2001 From: Tilen Majerle Date: Thu, 4 Jan 2024 21:39:27 +0100 Subject: [PATCH 25/45] Update copyright to 2024 & AUTHORS file --- dev/lwmem_opts.h | 2 +- .../inc/lwmem_opts.h | 2 +- .../lwmem_rtos_stm32l496_discovery/inc/main.h | 2 +- .../lwmem_rtos_stm32l496_discovery/src/main.c | 2 +- .../inc/lwmem_opts.h | 2 +- .../lwmem_stm32l496_discovery/inc/main.h | 2 +- .../lwmem_stm32l496_discovery/src/main.c | 2 +- examples/win32/lwmem_basic/lwmem_opts.h | 2 +- .../lwmem_multi_ins_multi_region/lwmem_opts.h | 2 +- .../win32/lwmem_multi_region/lwmem_opts.h | 2 +- examples/win32/lwmem_os/lwmem_opts.h | 2 +- lwmem/src/include/lwmem/lwmem.h | 26 +++++++++---------- lwmem/src/include/lwmem/lwmem_opt.h | 2 +- lwmem/src/include/lwmem/lwmem_opts_template.h | 2 +- lwmem/src/include/system/lwmem_sys.h | 2 +- lwmem/src/lwmem/lwmem.c | 2 +- lwmem/src/system/lwmem_sys_cmsis_os.c | 2 +- lwmem/src/system/lwmem_sys_threadx.c | 2 +- lwmem/src/system/lwmem_sys_win32.c | 2 +- 19 files changed, 31 insertions(+), 31 deletions(-) diff --git a/dev/lwmem_opts.h b/dev/lwmem_opts.h index 9c9bce8..40e978f 100644 --- a/dev/lwmem_opts.h +++ b/dev/lwmem_opts.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 diff --git a/examples/stm32/lwmem_rtos_stm32l496_discovery/inc/lwmem_opts.h b/examples/stm32/lwmem_rtos_stm32l496_discovery/inc/lwmem_opts.h index 27f8119..0d8f03a 100644 --- a/examples/stm32/lwmem_rtos_stm32l496_discovery/inc/lwmem_opts.h +++ b/examples/stm32/lwmem_rtos_stm32l496_discovery/inc/lwmem_opts.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 diff --git a/examples/stm32/lwmem_rtos_stm32l496_discovery/inc/main.h b/examples/stm32/lwmem_rtos_stm32l496_discovery/inc/main.h index e3fd5d3..3637afe 100644 --- a/examples/stm32/lwmem_rtos_stm32l496_discovery/inc/main.h +++ b/examples/stm32/lwmem_rtos_stm32l496_discovery/inc/main.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 diff --git a/examples/stm32/lwmem_rtos_stm32l496_discovery/src/main.c b/examples/stm32/lwmem_rtos_stm32l496_discovery/src/main.c index 0a68844..982e174 100644 --- a/examples/stm32/lwmem_rtos_stm32l496_discovery/src/main.c +++ b/examples/stm32/lwmem_rtos_stm32l496_discovery/src/main.c @@ -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 diff --git a/examples/stm32/lwmem_stm32l496_discovery/inc/lwmem_opts.h b/examples/stm32/lwmem_stm32l496_discovery/inc/lwmem_opts.h index 7762a8b..cded8c8 100644 --- a/examples/stm32/lwmem_stm32l496_discovery/inc/lwmem_opts.h +++ b/examples/stm32/lwmem_stm32l496_discovery/inc/lwmem_opts.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 diff --git a/examples/stm32/lwmem_stm32l496_discovery/inc/main.h b/examples/stm32/lwmem_stm32l496_discovery/inc/main.h index e3fd5d3..3637afe 100644 --- a/examples/stm32/lwmem_stm32l496_discovery/inc/main.h +++ b/examples/stm32/lwmem_stm32l496_discovery/inc/main.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 diff --git a/examples/stm32/lwmem_stm32l496_discovery/src/main.c b/examples/stm32/lwmem_stm32l496_discovery/src/main.c index e11c079..d86c1ad 100644 --- a/examples/stm32/lwmem_stm32l496_discovery/src/main.c +++ b/examples/stm32/lwmem_stm32l496_discovery/src/main.c @@ -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 diff --git a/examples/win32/lwmem_basic/lwmem_opts.h b/examples/win32/lwmem_basic/lwmem_opts.h index 7762a8b..cded8c8 100644 --- a/examples/win32/lwmem_basic/lwmem_opts.h +++ b/examples/win32/lwmem_basic/lwmem_opts.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 diff --git a/examples/win32/lwmem_multi_ins_multi_region/lwmem_opts.h b/examples/win32/lwmem_multi_ins_multi_region/lwmem_opts.h index 7762a8b..cded8c8 100644 --- a/examples/win32/lwmem_multi_ins_multi_region/lwmem_opts.h +++ b/examples/win32/lwmem_multi_ins_multi_region/lwmem_opts.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 diff --git a/examples/win32/lwmem_multi_region/lwmem_opts.h b/examples/win32/lwmem_multi_region/lwmem_opts.h index 7762a8b..cded8c8 100644 --- a/examples/win32/lwmem_multi_region/lwmem_opts.h +++ b/examples/win32/lwmem_multi_region/lwmem_opts.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 diff --git a/examples/win32/lwmem_os/lwmem_opts.h b/examples/win32/lwmem_os/lwmem_opts.h index e86dbbe..c81b6ea 100644 --- a/examples/win32/lwmem_os/lwmem_opts.h +++ b/examples/win32/lwmem_os/lwmem_opts.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 diff --git a/lwmem/src/include/lwmem/lwmem.h b/lwmem/src/include/lwmem/lwmem.h index 2570a9f..29e3d4e 100644 --- a/lwmem/src/include/lwmem/lwmem.h +++ b/lwmem/src/include/lwmem/lwmem.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 @@ -60,23 +60,23 @@ 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 */ - 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 */ + 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 */ } lwmem_block_t; /** * \brief Statistics structure */ 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 nr_alloc; /*!< Number of all allocated blocks in single instance */ - uint32_t nr_free; /*!< Number of frees in the LwMEM instance */ + 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 nr_alloc; /*!< Number of all allocated blocks in single instance */ + uint32_t nr_free; /*!< Number of frees in the LwMEM instance */ } lwmem_stats_t; /** @@ -95,7 +95,7 @@ typedef struct lwmem { #endif /* LWMEM_CFG_ENABLE_STATS || __DOXYGEN__ */ #if defined(LWMEM_DEV) && !__DOXYGEN__ lwmem_block_t start_block_first_use; /*!< Value of start block for very first time. - This is used only during validation process and is removed in final use */ + This is used only during validation process and is removed in final use */ #endif /* defined(LWMEM_DEV) && !__DOXYGEN__ */ } lwmem_t; diff --git a/lwmem/src/include/lwmem/lwmem_opt.h b/lwmem/src/include/lwmem/lwmem_opt.h index b543ea4..4181dda 100644 --- a/lwmem/src/include/lwmem/lwmem_opt.h +++ b/lwmem/src/include/lwmem/lwmem_opt.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 diff --git a/lwmem/src/include/lwmem/lwmem_opts_template.h b/lwmem/src/include/lwmem/lwmem_opts_template.h index deb5e80..e7b92c8 100644 --- a/lwmem/src/include/lwmem/lwmem_opts_template.h +++ b/lwmem/src/include/lwmem/lwmem_opts_template.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 diff --git a/lwmem/src/include/system/lwmem_sys.h b/lwmem/src/include/system/lwmem_sys.h index a837d89..c6a92ab 100644 --- a/lwmem/src/include/system/lwmem_sys.h +++ b/lwmem/src/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 diff --git a/lwmem/src/lwmem/lwmem.c b/lwmem/src/lwmem/lwmem.c index 59ee1d1..b206e3d 100644 --- a/lwmem/src/lwmem/lwmem.c +++ b/lwmem/src/lwmem/lwmem.c @@ -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 diff --git a/lwmem/src/system/lwmem_sys_cmsis_os.c b/lwmem/src/system/lwmem_sys_cmsis_os.c index a327f78..16ecb60 100644 --- a/lwmem/src/system/lwmem_sys_cmsis_os.c +++ b/lwmem/src/system/lwmem_sys_cmsis_os.c @@ -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 diff --git a/lwmem/src/system/lwmem_sys_threadx.c b/lwmem/src/system/lwmem_sys_threadx.c index f6713ef..af4b7ee 100644 --- a/lwmem/src/system/lwmem_sys_threadx.c +++ b/lwmem/src/system/lwmem_sys_threadx.c @@ -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 diff --git a/lwmem/src/system/lwmem_sys_win32.c b/lwmem/src/system/lwmem_sys_win32.c index 0a7bb8e..2b29ac0 100644 --- a/lwmem/src/system/lwmem_sys_win32.c +++ b/lwmem/src/system/lwmem_sys_win32.c @@ -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 From ebcb1fee742d22254288e9dfe8217b25bfe2107d Mon Sep 17 00:00:00 2001 From: Tilen Majerle Date: Tue, 27 Feb 2024 21:20:23 +0100 Subject: [PATCH 26/45] Update license --- LICENSE | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/LICENSE b/LICENSE index 3702ca4..42c1b5c 100644 --- a/LICENSE +++ b/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 From cb0ef2a035b8c3363130f200c92b4e296acdb90e Mon Sep 17 00:00:00 2001 From: Tilen Majerle Date: Tue, 19 Mar 2024 21:34:24 +0100 Subject: [PATCH 27/45] Update library CMake system, to support automatic creation of options file, if user doesn't provide one --- CMakeLists.txt | 2 +- docs/get-started/index.rst | 4 ++-- lwmem/library.cmake | 19 +++++++++++++++---- 3 files changed, 18 insertions(+), 7 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 3bef347..21dd482 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -40,7 +40,7 @@ else() ) # Add subdir with lwmem and link to the project - set(LWMEM_OPTS_DIR ${CMAKE_CURRENT_LIST_DIR}/dev) + 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) diff --git a/docs/get-started/index.rst b/docs/get-started/index.rst index 654ef1f..6a7d77f 100644 --- a/docs/get-started/index.rst +++ b/docs/get-started/index.rst @@ -89,8 +89,8 @@ and it should be copied (or simply renamed in-place) and named ``lwmem_opts.h`` include paths have access to it by using ``#include "lwmem_opts.h"``. .. tip:: - If you are using *CMake* build system, define the variable ``LWMEM_OPTS_DIR`` before adding library's directory to the *CMake* project. - Variable must set the output directory path. CMake will copy the template file there, and name it as required. + 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, 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 diff --git a/lwmem/library.cmake b/lwmem/library.cmake index d16b79f..2917049 100644 --- a/lwmem/library.cmake +++ b/lwmem/library.cmake @@ -1,15 +1,20 @@ # +# 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_DIR: If defined, it should set the folder path where options file shall be generated. +# 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 @@ -23,6 +28,7 @@ set(lwmem_core_cpp_SRCS # Setup include directories set(lwmem_include_DIRS ${CMAKE_CURRENT_LIST_DIR}/src/include + ${LWMEM_CUSTOM_INC_DIR} ) # Add system port @@ -46,7 +52,12 @@ target_include_directories(lwmem_cpp INTERFACE ${lwmem_include_DIRS}) target_compile_options(lwmem_cpp PRIVATE ${LWMEM_COMPILE_OPTIONS}) target_compile_definitions(lwmem_cpp PRIVATE ${LWMEM_COMPILE_DEFINITIONS}) -# Create config file -if(DEFINED LWMEM_OPTS_DIR AND NOT EXISTS ${LWMEM_OPTS_DIR}/lwmem_opts.h) - configure_file(${CMAKE_CURRENT_LIST_DIR}/src/include/lwmem/lwmem_opts_template.h ${LWMEM_OPTS_DIR}/lwmem_opts.h COPYONLY) +# 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) + From d7a159cf0f90d99eaf140b44f0705ad227b86eb7 Mon Sep 17 00:00:00 2001 From: Tilen Majerle Date: Tue, 19 Mar 2024 21:41:47 +0100 Subject: [PATCH 28/45] Improve documentation --- docs/get-started/index.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/get-started/index.rst b/docs/get-started/index.rst index 6a7d77f..1ae3537 100644 --- a/docs/get-started/index.rst +++ b/docs/get-started/index.rst @@ -90,7 +90,7 @@ and it should be copied (or simply renamed in-place) and named ``lwmem_opts.h`` .. 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, one will be generated in the build directory. + 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 From 517ef1fceeedb35d13d1ce47a58632690ce16883 Mon Sep 17 00:00:00 2001 From: Tilen Majerle Date: Sat, 22 Jun 2024 15:13:34 +0200 Subject: [PATCH 29/45] Improve the getting started documentation - how to add library to project with CMake config --- docs/get-started/index.rst | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/docs/get-started/index.rst b/docs/get-started/index.rst index 1ae3537..264843d 100644 --- a/docs/get-started/index.rst +++ b/docs/get-started/index.rst @@ -57,22 +57,22 @@ 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. +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: -* ``CMakeLists.txt``: Is a wrapper and only includes ``library.cmake`` file. It is used if target application uses ``add_subdirectory`` and then uses ``target_link_libraries`` to include the library in the project -* ``library.cmake``: It is a fully configured set of variables. User must use ``include(path/to/library.cmake)`` to include the library and must manually add files/includes to the final target +* ``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 ``add_subdirectory`` **CMake** command, followed by ``target_link_libraries`` to add library as an external library. .. tip:: - Open ``library.cmake`` file and manually analyze all the possible variables you can set for full functionality. + 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 -* Add source files from ``lwmem/src/`` folder to toolchain build. These files are built by `C/C++` compiler. CMake configuration comes with the library, allows users to include library in the project as **subdirectory** and **library**. +* Add source files from ``lwmem/src/`` folder to toolchain build. These files are built by `C/C++` compiler * Copy ``lwmem/src/include/lwmem/lwmem_opts_template.h`` to project folder and rename it to ``lwmem_opts.h`` * Build the project From a3c3352370685d8e215ce24935601ab8ac57b1c9 Mon Sep 17 00:00:00 2001 From: Tilen Majerle Date: Sat, 22 Jun 2024 15:17:22 +0200 Subject: [PATCH 30/45] Update authors --- AUTHORS | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/AUTHORS b/AUTHORS index 4e68df8..a96c3af 100644 --- a/AUTHORS +++ b/AUTHORS @@ -1,4 +1,4 @@ Tilen Majerle +upbeat27 Tilen Majerle -Y <469960757@qq.com> -upbeat27 \ No newline at end of file +Y <469960757@qq.com> \ No newline at end of file From 2b083176a0dcbc2a5a81c8165c7738a3e443a84d Mon Sep 17 00:00:00 2001 From: Tilen Majerle Date: Sat, 22 Jun 2024 19:27:00 +0200 Subject: [PATCH 31/45] Update getting started guide --- docs/get-started/index.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/get-started/index.rst b/docs/get-started/index.rst index 264843d..4128428 100644 --- a/docs/get-started/index.rst +++ b/docs/get-started/index.rst @@ -63,7 +63,7 @@ Next step is to add the library to the project, by means of source files to comp *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 ``add_subdirectory`` **CMake** command, followed by ``target_link_libraries`` to add library as an external library. +* ``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. From 3e2cb7d08b6865975a2987c3658c79b27180aef2 Mon Sep 17 00:00:00 2001 From: Tilen Majerle Date: Mon, 19 Aug 2024 21:30:31 +0200 Subject: [PATCH 32/45] Change the parameter name to make it less ambigious --- lwmem/src/include/lwmem/lwmem.h | 22 +++++++++++----------- 1 file changed, 11 insertions(+), 11 deletions(-) diff --git a/lwmem/src/include/lwmem/lwmem.h b/lwmem/src/include/lwmem/lwmem.h index 29e3d4e..7af7803 100644 --- a/lwmem/src/include/lwmem/lwmem.h +++ b/lwmem/src/include/lwmem/lwmem.h @@ -136,7 +136,7 @@ lwmem_region_t regions[] = { \endcode * \return `0` on failure, number of final regions used for memory manager on success */ -#define lwmem_assignmem(regions) lwmem_assignmem_ex(NULL, (regions)) +#define lwmem_assignmem(regions) lwmem_assignmem_ex(NULL, (regions)) /** * \note This is a wrapper for \ref lwmem_malloc_ex function. @@ -145,7 +145,7 @@ lwmem_region_t regions[] = { * \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)) +#define lwmem_malloc(size) lwmem_malloc_ex(NULL, NULL, (size)) /** * \note This is a wrapper for \ref lwmem_calloc_ex function. @@ -155,7 +155,7 @@ lwmem_region_t regions[] = { * \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)) +#define lwmem_calloc(nitems, size) lwmem_calloc_ex(NULL, NULL, (nitems), (size)) /** * \note This is a wrapper for \ref lwmem_realloc_ex function. @@ -166,19 +166,19 @@ lwmem_region_t regions[] = { * \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)) +#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`. + * \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 */ -#define lwmem_realloc_s(ptrptr, size) lwmem_realloc_s_ex(NULL, NULL, (ptrptr), (size)) +#define lwmem_realloc_s(ptr2ptr, size) lwmem_realloc_s_ex(NULL, NULL, (ptr2ptr), (size)) /** * \note This is a wrapper for \ref lwmem_free_ex function. @@ -186,16 +186,16 @@ lwmem_region_t regions[] = { * \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)) +#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. + * \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 */ -#define lwmem_free_s(ptrptr) lwmem_free_s_ex(NULL, (ptrptr)) +#define lwmem_free_s(ptr2ptr) lwmem_free_s_ex(NULL, (ptr2ptr)) /** * \note This is a wrapper for \ref lwmem_get_size_ex function. @@ -203,14 +203,14 @@ lwmem_region_t regions[] = { * \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)) +#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)) +#define lwmem_get_stats(stats) lwmem_get_stats_ex(NULL, (stats)) #if defined(LWMEM_DEV) && !__DOXYGEN__ unsigned char lwmem_debug_create_regions(lwmem_region_t** regs_out, size_t count, size_t size); From 756a7bce1dc4a03b35fc5e7e6d34b1ad14308b37 Mon Sep 17 00:00:00 2001 From: Tilen M Date: Tue, 3 Sep 2024 21:42:01 +0200 Subject: [PATCH 33/45] Update CMake to expose lib as PUBLIC/PRIVATE and not INTERFACE --- CHANGELOG.md | 2 ++ lwmem/library.cmake | 12 ++++++------ 2 files changed, 8 insertions(+), 6 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 4133354..b3d10c5 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,6 +2,8 @@ ## Develop +- Rework library CMake with removed INTERFACE type + ## v2.1.0 - Split CMakeLists.txt files between library and executable diff --git a/lwmem/library.cmake b/lwmem/library.cmake index 2917049..a8cde02 100644 --- a/lwmem/library.cmake +++ b/lwmem/library.cmake @@ -39,16 +39,16 @@ set(lwmem_core_SRCS ${lwmem_core_SRCS} endif() # Register core library -add_library(lwmem INTERFACE) -target_sources(lwmem PUBLIC ${lwmem_core_SRCS}) -target_include_directories(lwmem INTERFACE ${lwmem_include_DIRS}) +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 INTERFACE) -target_sources(lwmem_cpp PUBLIC ${lwmem_core_SRCS}) -target_include_directories(lwmem_cpp INTERFACE ${lwmem_include_DIRS}) +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}) From 05942ae576b28960a826769ba7055ce08c700549 Mon Sep 17 00:00:00 2001 From: Tilen M Date: Wed, 4 Sep 2024 21:13:29 +0200 Subject: [PATCH 34/45] Improve the CMakeLists library usage --- CMakeLists.txt | 27 +++++---------------------- lwmem/library.cmake | 15 ++++++++------- 2 files changed, 13 insertions(+), 29 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 21dd482..dbb61cc 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -6,10 +6,7 @@ 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 @@ -17,31 +14,17 @@ else() # 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() diff --git a/lwmem/library.cmake b/lwmem/library.cmake index a8cde02..e5db275 100644 --- a/lwmem/library.cmake +++ b/lwmem/library.cmake @@ -1,4 +1,4 @@ -# +# # LIB_PREFIX: LWMEM # # This file provides set of variables for end user @@ -16,12 +16,12 @@ set(LWMEM_CUSTOM_INC_DIR ${CMAKE_CURRENT_BINARY_DIR}/lib_inc) # Library core sources -set(lwmem_core_SRCS +set(lwmem_core_SRCS ${CMAKE_CURRENT_LIST_DIR}/src/lwmem/lwmem.c ) # C++ extension -set(lwmem_core_cpp_SRCS +set(lwmem_core_cpp_SRCS ${CMAKE_CURRENT_LIST_DIR}/src/lwmem/lwmem.cpp ) @@ -33,9 +33,9 @@ set(lwmem_include_DIRS # 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 -) + set(lwmem_core_SRCS ${lwmem_core_SRCS} + ${CMAKE_CURRENT_LIST_DIR}/src/system/lwmem_sys_${LWMEM_SYS_PORT}.c + ) endif() # Register core library @@ -51,6 +51,7 @@ 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) @@ -59,5 +60,5 @@ if(NOT LWMEM_OPTS_FILE) 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) +configure_file(${LWMEM_OPTS_FILE} ${LWMEM_CUSTOM_INC_DIR}/lwmem_opts.h COPYONLY) From 54ff6c1aeebfa82a6a77c145b05643894e2316f6 Mon Sep 17 00:00:00 2001 From: Tilen M Date: Sun, 6 Oct 2024 13:20:40 +0200 Subject: [PATCH 35/45] add option to disable realloc and free --- CHANGELOG.md | 1 + lwmem/src/include/lwmem/lwmem.h | 18 ++++++++++++++---- lwmem/src/include/lwmem/lwmem.hpp | 2 ++ lwmem/src/include/lwmem/lwmem_opt.h | 15 +++++++++++++++ lwmem/src/lwmem/lwmem.c | 27 ++++++++++++++++----------- 5 files changed, 48 insertions(+), 15 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index b3d10c5..20eef79 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -3,6 +3,7 @@ ## Develop - Rework library CMake with removed INTERFACE type +- Add `LWMEM_CFG_SUPPORT_REALLOC_AND_FREE` to disable realloc and free functions ## v2.1.0 diff --git a/lwmem/src/include/lwmem/lwmem.h b/lwmem/src/include/lwmem/lwmem.h index 7af7803..b7dc3a4 100644 --- a/lwmem/src/include/lwmem/lwmem.h +++ b/lwmem/src/include/lwmem/lwmem.h @@ -110,11 +110,13 @@ 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_SUPPORT_REALLOC_AND_FREE || __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); 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_SUPPORT_REALLOC_AND_FREE || __DOXYGEN__ */ #if LWMEM_CFG_ENABLE_STATS || __DOXYGEN__ void lwmem_get_stats_ex(lwmem_t* lwobj, lwmem_stats_t* stats); #endif /* LWMEM_CFG_ENABLE_STATS || __DOXYGEN__ */ @@ -136,7 +138,7 @@ lwmem_region_t regions[] = { \endcode * \return `0` on failure, number of final regions used for memory manager on success */ -#define lwmem_assignmem(regions) lwmem_assignmem_ex(NULL, (regions)) +#define lwmem_assignmem(regions) lwmem_assignmem_ex(NULL, (regions)) /** * \note This is a wrapper for \ref lwmem_malloc_ex function. @@ -145,7 +147,7 @@ lwmem_region_t regions[] = { * \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)) +#define lwmem_malloc(size) lwmem_malloc_ex(NULL, NULL, (size)) /** * \note This is a wrapper for \ref lwmem_calloc_ex function. @@ -155,7 +157,9 @@ lwmem_region_t regions[] = { * \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)) +#define lwmem_calloc(nitems, size) lwmem_calloc_ex(NULL, NULL, (nitems), (size)) + +#if LWMEM_CFG_SUPPORT_REALLOC_AND_FREE || __DOXYGEN__ /** * \note This is a wrapper for \ref lwmem_realloc_ex function. @@ -205,12 +209,18 @@ lwmem_region_t regions[] = { */ #define lwmem_get_size(ptr) lwmem_get_size_ex(NULL, (ptr)) +#endif /* LWMEM_CFG_SUPPORT_REALLOC_AND_FREE || __DOXYGEN__ */ + +#if LWMEM_CFG_ENABLE_STATS || __DOXYGEN__ + /** * \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)) +#define lwmem_get_stats(stats) lwmem_get_stats_ex(NULL, (stats)) + +#endif /* LWMEM_CFG_ENABLE_STATS || __DOXYGEN__ */ #if defined(LWMEM_DEV) && !__DOXYGEN__ unsigned char lwmem_debug_create_regions(lwmem_region_t** regs_out, size_t count, size_t size); diff --git a/lwmem/src/include/lwmem/lwmem.hpp b/lwmem/src/include/lwmem/lwmem.hpp index 2240947..5f40bca 100644 --- a/lwmem/src/include/lwmem/lwmem.hpp +++ b/lwmem/src/include/lwmem/lwmem.hpp @@ -93,6 +93,7 @@ class LwmemLight { return lwmem_calloc_ex(&m_lw, nullptr, nitems, size); } +#if LWMEM_CFG_SUPPORT_REALLOC_AND_FREE || __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_SUPPORT_REALLOC_AND_FREE || __DOXYGEN__ */ private: /* Delete unused constructors */ diff --git a/lwmem/src/include/lwmem/lwmem_opt.h b/lwmem/src/include/lwmem/lwmem_opt.h index 4181dda..81b200f 100644 --- a/lwmem/src/include/lwmem/lwmem_opt.h +++ b/lwmem/src/include/lwmem/lwmem_opt.h @@ -85,6 +85,21 @@ extern "C" { #define LWMEM_CFG_ALIGN_NUM ((size_t)4) #endif +/** + * \brief Enables `1` or disables `0` full memory management support. + * + * When enabled, library supports allocation, reallocation and freeing of the memory. + * When disabled, library only supports allocation, which is useful for + * power up memory initialization only. + * + * \note When disabled, \ref lwmem_get_size_ex is also not available, + * as it is assumed that user won't frequently ask for size of + * previously allocated block if realloc isn't being used + */ +#ifndef LWMEM_CFG_SUPPORT_REALLOC_AND_FREE +#define LWMEM_CFG_SUPPORT_REALLOC_AND_FREE 1 +#endif + /** * \brief Enables `1` or disables `0` memory cleanup on free operation (or realloc). * diff --git a/lwmem/src/lwmem/lwmem.c b/lwmem/src/lwmem/lwmem.c index b206e3d..969e3bc 100644 --- a/lwmem/src/lwmem/lwmem.c +++ b/lwmem/src/lwmem/lwmem.c @@ -435,6 +435,8 @@ prv_alloc(lwmem_t* const lwobj, const lwmem_region_t* region, const size_t size) return retval; } +#if LWMEM_CFG_SUPPORT_REALLOC_AND_FREE + /** * \brief Free input pointer * \param[in] lwobj: LwMEM instance. Set to `NULL` to use default instance @@ -653,15 +655,12 @@ prv_realloc(lwmem_t* const lwobj, const lwmem_region_t* region, void* const ptr, */ LWMEM_MEMMOVE(new_data_ptr, old_data_ptr, block_size); /* Copy old buffer size to new location */ - 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 */ @@ -684,14 +683,16 @@ 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; } +#endif /* LWMEM_CFG_SUPPORT_REALLOC_AND_FREE */ + /** * \brief Initializes and assigns user regions for memory used by allocator algorithm * \param[in] lwobj: LwMEM instance. Set to `NULL` to use default instance @@ -873,6 +874,8 @@ lwmem_calloc_ex(lwmem_t* lwobj, const lwmem_region_t* region, const size_t nitem return ptr; } +#if LWMEM_CFG_SUPPORT_REALLOC_AND_FREE || __DOXYGEN__ + /** * \brief Reallocates already allocated memory with new size in specific lwmem instance and region. * @@ -1022,6 +1025,8 @@ lwmem_get_size_ex(lwmem_t* lwobj, void* ptr) { return len; } +#endif /* LWMEM_CFG_SUPPORT_REALLOC_AND_FREE || __DOXYGEN__ */ + #if LWMEM_CFG_ENABLE_STATS || __DOXYGEN__ /** From f217a0b2d6ed672b1f8e4d5a2da2ddc5ba2f5a7b Mon Sep 17 00:00:00 2001 From: Tilen Majerle Date: Tue, 8 Oct 2024 06:40:38 +0200 Subject: [PATCH 36/45] Check the region size after address alignment --- lwmem/src/lwmem/lwmem.c | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/lwmem/src/lwmem/lwmem.c b/lwmem/src/lwmem/lwmem.c index 969e3bc..34b8513 100644 --- a/lwmem/src/lwmem/lwmem.c +++ b/lwmem/src/lwmem/lwmem.c @@ -203,6 +203,12 @@ prv_get_region_addr_size(const lwmem_region_t* region, uint8_t** msa, size_t* ms 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 */ + if (mem_size < (2 * LWMEM_BLOCK_MIN_SIZE)) { + return 0; + } + /* Check final memory size */ if (mem_size >= (2 * LWMEM_BLOCK_MIN_SIZE)) { *msa = mem_start_addr; From 5887323fb0c2260c4596ead539299cceb9806bcf Mon Sep 17 00:00:00 2001 From: Tilen Majerle Date: Wed, 9 Oct 2024 05:25:27 +0200 Subject: [PATCH 37/45] make macros classic wrapper functions --- lwmem/src/include/lwmem/lwmem.h | 93 +++----------------------- lwmem/src/lwmem/lwmem.c | 114 ++++++++++++++++++++++++++++++++ 2 files changed, 122 insertions(+), 85 deletions(-) diff --git a/lwmem/src/include/lwmem/lwmem.h b/lwmem/src/include/lwmem/lwmem.h index b7dc3a4..5698584 100644 --- a/lwmem/src/include/lwmem/lwmem.h +++ b/lwmem/src/include/lwmem/lwmem.h @@ -121,93 +121,16 @@ size_t lwmem_get_size_ex(lwmem_t* lwobj, void* ptr); void lwmem_get_stats_ex(lwmem_t* lwobj, 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)) - -/** - * \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)) +size_t lwmem_assignmem(const lwmem_region_t* regions); +void* lwmem_malloc(size_t size); +void* lwmem_calloc(size_t nitems, size_t size); #if LWMEM_CFG_SUPPORT_REALLOC_AND_FREE || __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 - */ -#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] 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 - */ -#define lwmem_realloc_s(ptr2ptr, size) 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 - */ -#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] 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 - */ -#define lwmem_free_s(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 - */ -#define lwmem_get_size(ptr) lwmem_get_size_ex(NULL, (ptr)) +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_SUPPORT_REALLOC_AND_FREE || __DOXYGEN__ */ diff --git a/lwmem/src/lwmem/lwmem.c b/lwmem/src/lwmem/lwmem.c index 34b8513..5c1d644 100644 --- a/lwmem/src/lwmem/lwmem.c +++ b/lwmem/src/lwmem/lwmem.c @@ -1054,6 +1054,120 @@ lwmem_get_stats_ex(lwmem_t* lwobj, 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 + */ +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_SUPPORT_REALLOC_AND_FREE || __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_SUPPORT_REALLOC_AND_FREE || __DOXYGEN__ */ + /* Part of library used ONLY for LWMEM_DEV purposes */ /* To validate and test library */ From 254ea2855ff338cfc2de00368ef8eea1c9584bc6 Mon Sep 17 00:00:00 2001 From: Tilen Majerle Date: Wed, 9 Oct 2024 05:25:53 +0200 Subject: [PATCH 38/45] set size before modifying it --- lwmem/src/lwmem/lwmem.c | 1 + 1 file changed, 1 insertion(+) diff --git a/lwmem/src/lwmem/lwmem.c b/lwmem/src/lwmem/lwmem.c index 5c1d644..be867bb 100644 --- a/lwmem/src/lwmem/lwmem.c +++ b/lwmem/src/lwmem/lwmem.c @@ -198,6 +198,7 @@ prv_get_region_addr_size(const lwmem_region_t* region, uint8_t** msa, size_t* ms * 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)); From 7e45fe460c5936d5bf56afcd83c4fd94eb84b2fd Mon Sep 17 00:00:00 2001 From: Tilen Majerle Date: Wed, 9 Oct 2024 05:27:10 +0200 Subject: [PATCH 39/45] simple implementation for grow-only malloc (minimalistic) --- CMakeLists.txt | 1 + dev/lwmem_opts.h | 9 +- dev/main.cpp | 11 +- .../example_realloc_enlarge_full.c | 29 +- .../example_realloc_enlarge_full_log.c | 2 +- lwmem/src/include/lwmem/lwmem.h | 14 +- lwmem/src/lwmem/lwmem.c | 292 ++++++++++++------ tests/lwmem_test.c | 117 ++++--- tests/lwmem_test_simple.c | 68 ++++ 9 files changed, 380 insertions(+), 163 deletions(-) create mode 100644 tests/lwmem_test_simple.c diff --git a/CMakeLists.txt b/CMakeLists.txt index dbb61cc..838327c 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -10,6 +10,7 @@ else() 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 diff --git a/dev/lwmem_opts.h b/dev/lwmem_opts.h index 40e978f..5eb8912 100644 --- a/dev/lwmem_opts.h +++ b/dev/lwmem_opts.h @@ -41,9 +41,10 @@ * Open "include/lwmem/lwmem_opt.h" and * copy & replace here settings you want to change values */ -#define LWMEM_CFG_OS 1 -#define LWMEM_CFG_OS_MUTEX_HANDLE HANDLE -#define LWMEM_CFG_ENABLE_STATS 0 -#define LWMEM_CFG_CLEAN_MEMORY 1 +#define LWMEM_CFG_OS 1 +#define LWMEM_CFG_OS_MUTEX_HANDLE HANDLE +#define LWMEM_CFG_ENABLE_STATS 0 +#define LWMEM_CFG_CLEAN_MEMORY 1 +#define LWMEM_CFG_SUPPORT_REALLOC_AND_FREE 1 #endif /* LWMEM_HDR_OPTS_H */ diff --git a/dev/main.cpp b/dev/main.cpp index bddb83c..e04b8ec 100644 --- a/dev/main.cpp +++ b/dev/main.cpp @@ -5,20 +5,29 @@ #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_SUPPORT_REALLOC_AND_FREE 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_SUPPORT_REALLOC_AND_FREE manager.free(ret); +#endif /* LWMEM_CFG_SUPPORT_REALLOC_AND_FREE */ +#endif return 0; } diff --git a/docs/examples_src/example_realloc_enlarge_full.c b/docs/examples_src/example_realloc_enlarge_full.c index 2cc8f74..9d6c349 100644 --- a/docs/examples_src/example_realloc_enlarge_full.c +++ b/docs/examples_src/example_realloc_enlarge_full.c @@ -1,19 +1,20 @@ -#define ASSERT(x) do { \ - if (!(x)) { \ - printf("Assert failed with condition (" # x ")\r\n"); \ - } else {\ - printf("Assert passed with condition (" # x ")\r\n"); \ - }\ -} while (0) +#define ASSERT(x) \ + do { \ + if (!(x)) { \ + printf("Assert failed with condition (" #x ")\r\n"); \ + } else { \ + printf("Assert passed with condition (" #x ")\r\n"); \ + } \ + } while (0) /* For debug purposes */ lwmem_region_t* regions_used; -size_t regions_count = 1; /* Use only 1 region for debug purposes of non-free areas */ +size_t regions_count = 1; /* Use only 1 region for debug purposes of non-free areas */ int main(void) { - uint8_t* ptr1, *ptr2, *ptr3, *ptr4; - uint8_t* rptr1, *rptr2, *rptr3, *rptr4; + uint8_t *ptr1, *ptr2, *ptr3, *ptr4; + uint8_t *rptr1, *rptr2, *rptr3, *rptr4; /* Create regions for debug purpose */ if (!lwmem_debug_create_regions(®ions_used, regions_count, 128)) { @@ -31,11 +32,11 @@ main(void) { ptr2 = lwmem_malloc(4); ptr3 = lwmem_malloc(4); ptr4 = lwmem_malloc(16); - lwmem_free(ptr1); /* Free but keep value for future comparison */ - lwmem_free(ptr3); /* Free but keep value for future comparison */ + 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); printf("Debug above is effectively state 3\r\n"); - lwmem_debug_save_state(); /* Every restore operations rewinds here */ + lwmem_debug_save_state(); /* Every restore operations rewinds here */ /* We always try to reallocate pointer ptr2 */ @@ -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"); diff --git a/docs/examples_src/example_realloc_enlarge_full_log.c b/docs/examples_src/example_realloc_enlarge_full_log.c index 3755d2a..4a11289 100644 --- a/docs/examples_src/example_realloc_enlarge_full_log.c +++ b/docs/examples_src/example_realloc_enlarge_full_log.c @@ -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! diff --git a/lwmem/src/include/lwmem/lwmem.h b/lwmem/src/include/lwmem/lwmem.h index 5698584..54f9041 100644 --- a/lwmem/src/include/lwmem/lwmem.h +++ b/lwmem/src/include/lwmem/lwmem.h @@ -83,10 +83,16 @@ typedef struct { * \brief LwMEM main structure */ typedef struct lwmem { - 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 */ +#if LWMEM_CFG_SUPPORT_REALLOC_AND_FREE + 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_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__ */ @@ -112,7 +118,7 @@ void* lwmem_malloc_ex(lwmem_t* lwobj, const lwmem_region_t* region, const size_t void* lwmem_calloc_ex(lwmem_t* lwobj, const lwmem_region_t* region, const size_t nitems, const size_t size); #if LWMEM_CFG_SUPPORT_REALLOC_AND_FREE || __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); diff --git a/lwmem/src/lwmem/lwmem.c b/lwmem/src/lwmem/lwmem.c index be867bb..da181cf 100644 --- a/lwmem/src/lwmem/lwmem.c +++ b/lwmem/src/lwmem/lwmem.c @@ -169,6 +169,8 @@ */ static lwmem_t lwmem_default; +#if LWMEM_CFG_SUPPORT_REALLOC_AND_FREE + /** * \brief Get region aligned start address and aligned size * \param[in] region: Region to check for size and address @@ -187,12 +189,6 @@ prv_get_region_addr_size(const lwmem_region_t* region, uint8_t** msa, size_t* ms *msa = NULL; *msz = 0; - /* Check region size and align it to config bits */ - mem_size = region->size & ~LWMEM_ALIGN_BITS; /* Size does not include lower bits */ - if (mem_size < (2 * LWMEM_BLOCK_MIN_SIZE)) { - return 0; - } - /* * Start address must be aligned to configuration * Increase start address and decrease effective region size @@ -442,8 +438,6 @@ prv_alloc(lwmem_t* const lwobj, const lwmem_region_t* region, const size_t size) return retval; } -#if LWMEM_CFG_SUPPORT_REALLOC_AND_FREE - /** * \brief Free input pointer * \param[in] lwobj: LwMEM instance. Set to `NULL` to use default instance @@ -582,8 +576,7 @@ 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 */ + if ((LWMEM_TO_BYTE_PTR(block) + block_size) == LWMEM_TO_BYTE_PTR(prev->next) && (block_size + prev->next->size) >= final_size) { /* Size is greater or equal to requested */ /* @@ -593,8 +586,8 @@ 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 */ @@ -624,10 +617,10 @@ 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 */ - block = prev; /* Move block pointer to previous one */ + 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 */ + 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 */ @@ -698,79 +691,21 @@ prv_realloc(lwmem_t* const lwobj, const lwmem_region_t* region, void* const ptr, return retval; } -#endif /* LWMEM_CFG_SUPPORT_REALLOC_AND_FREE */ - /** - * \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 + * \brief Assign the memory structure for advanced memory allocation system + * + * \param lwobj + * \param regions + * \return size_t */ -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; +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; - 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 - * - * Invalid entry is considered as "end-of-region" indicator - */ - if (regions[i].size == 0 && regions[i].start_addr == NULL) { - len = i; - if (len == 0) { - return 0; - } - break; - } - - /* 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; } @@ -831,6 +766,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_SUPPORT_REALLOC_AND_FREE */ + +/** + * \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_SUPPORT_REALLOC_AND_FREE */ + +/** + * \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 || (((size_t)LWMEM_CFG_ALIGN_NUM) & (((size_t)LWMEM_CFG_ALIGN_NUM) - 1)) > 0 +#if LWMEM_CFG_SUPPORT_REALLOC_AND_FREE + || lwobj->end_block != NULL /* Init function may only be called once per lwmem instance */ +#else + || lwobj->is_initialized /* Already initialized? */ +#endif /* LWMEM_CFG_SUPPORT_REALLOC_AND_FREE */ + ) { + 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_SUPPORT_REALLOC_AND_FREE + /* + * 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_SUPPORT_REALLOC_AND_FREE */ + + /* 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_SUPPORT_REALLOC_AND_FREE + return prv_assignmem(lwobj, regions); +#else /* LWMEM_CFG_SUPPORT_REALLOC_AND_FREE */ + return prv_assignmem_simple(lwobj, regions); +#endif /* LWMEM_CFG_SUPPORT_REALLOC_AND_FREE */ +} + /** * \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 @@ -843,10 +933,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_SUPPORT_REALLOC_AND_FREE ptr = prv_alloc(lwobj, region, size); +#else /* LWMEM_CFG_SUPPORT_REALLOC_AND_FREE */ + ptr = prv_alloc_simple(lwobj, region, size); +#endif /* LWMEM_CFG_SUPPORT_REALLOC_AND_FREE */ LWMEM_UNPROTECT(lwobj); return ptr; } @@ -856,7 +952,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. @@ -868,16 +964,22 @@ 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); - ptr = prv_alloc(lwobj, region, s); - if (ptr != NULL) { - LWMEM_MEMSET(ptr, 0x00, s); - } +#if LWMEM_CFG_SUPPORT_REALLOC_AND_FREE + ptr = prv_alloc(lwobj, region, alloc_size); +#else /* LWMEM_CFG_SUPPORT_REALLOC_AND_FREE */ + ptr = prv_alloc_simple(lwobj, region, alloc_size); +#endif /* LWMEM_CFG_SUPPORT_REALLOC_AND_FREE */ LWMEM_UNPROTECT(lwobj); + + if (ptr != NULL) { + LWMEM_MEMSET(ptr, 0x00, alloc_size); + } return ptr; } @@ -943,7 +1045,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; diff --git a/tests/lwmem_test.c b/tests/lwmem_test.c index 3737c2b..559e231 100644 --- a/tests/lwmem_test.c +++ b/tests/lwmem_test.c @@ -1,70 +1,75 @@ -#include "lwmem/lwmem.h" #include +#include "lwmem/lwmem.h" + +#if LWMEM_CFG_SUPPORT_REALLOC_AND_FREE /* 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) +#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) /********************************************/ /* 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 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)) /********************************************/ /* 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,33 +116,41 @@ 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) { - uint8_t* ptr1, *ptr2, *ptr3, *ptr4; - uint8_t* rptr1, *rptr2, *rptr3, *rptr4; + uint8_t *ptr1, *ptr2, *ptr3, *ptr4; + uint8_t *rptr1, *rptr2, *rptr3, *rptr4; size_t used_regions; /* @@ -156,16 +174,20 @@ 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_free(ptr1); /* Free but keep value for future comparison */ - lwmem_free(ptr3); /* Free but keep value for future comparison */ + 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); printf("Debug above is effectively state 3\r\n"); - lwmem_debug_save_state(); /* Every restore operations rewinds here */ + lwmem_debug_save_state(); /* Every restore operations rewinds here */ /* We always try to reallocate pointer ptr2 */ @@ -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); -} \ No newline at end of file + + 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_SUPPORT_REALLOC_AND_FREE */ \ No newline at end of file diff --git a/tests/lwmem_test_simple.c b/tests/lwmem_test_simple.c new file mode 100644 index 0000000..19fcc06 --- /dev/null +++ b/tests/lwmem_test_simple.c @@ -0,0 +1,68 @@ +#include +#include "lwmem/lwmem.h" + +#if !LWMEM_CFG_SUPPORT_REALLOC_AND_FREE + +/* 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_SUPPORT_REALLOC_AND_FREE */ \ No newline at end of file From e937a49d3011d9a46e52291a5cef654f022212cf Mon Sep 17 00:00:00 2001 From: Tilen Majerle Date: Wed, 9 Oct 2024 05:27:17 +0200 Subject: [PATCH 40/45] update changelog --- CHANGELOG.md | 1 + 1 file changed, 1 insertion(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 20eef79..5c89552 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -4,6 +4,7 @@ - Rework library CMake with removed INTERFACE type - Add `LWMEM_CFG_SUPPORT_REALLOC_AND_FREE` to disable realloc and free functions +- Implement support for simple (no realloc, no free, grow-only malloc) allocation mechanism ## v2.1.0 From 14740ff4f56bd11cba934c8b024dc0b14e57aafc Mon Sep 17 00:00:00 2001 From: Tilen Majerle Date: Wed, 9 Oct 2024 09:20:35 +0200 Subject: [PATCH 41/45] remove unnecessary comments --- lwmem/src/lwmem/lwmem.c | 333 ++++++++++++++++++++-------------------- 1 file changed, 166 insertions(+), 167 deletions(-) diff --git a/lwmem/src/lwmem/lwmem.c b/lwmem/src/lwmem/lwmem.c index da181cf..0d13964 100644 --- a/lwmem/src/lwmem/lwmem.c +++ b/lwmem/src/lwmem/lwmem.c @@ -500,177 +500,176 @@ 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)) { - block_size = block->size & ~LWMEM_ALLOC_BIT; /* Get actual block size, without memory allocation bit */ + if (!LWMEM_BLOCK_IS_ALLOC(block)) { - /* Check current block size is the same as new requested size */ - if (block_size == final_size) { - return ptr; /* Just return pointer, nothing to do */ - } - - /* - * Abbreviations - * - * - "Current block" or "Input block" is allocated block from input variable "ptr" - * - "Next free block" is next free block, on address space after input block - * - "Prev free block" is last free block, on address space before input block - * - "PrevPrev free block" is previous free block of "Prev free block" - */ - - /* - * When new requested size is smaller than existing one, - * it is enough to modify size of current block only. - * - * If new requested size is much smaller than existing one, - * check if it is possible to create new empty block and add it to list of empty blocks - * - * Application returns same pointer - */ - if (final_size < block_size) { - if ((block_size - final_size) >= LWMEM_BLOCK_MIN_SIZE) { - prv_split_too_big_block(lwobj, block, final_size); /* Split block if it is too big */ - } else { - /* - * It is not possible to create new empty block at the end of input block - * - * But if next free block is just after input block, - * it is possible to find this block and increase it by "block_size - final_size" bytes - */ - - /* Find free blocks before input block */ - LWMEM_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) - && prev->next->size > 0) { /* Must not be end of region indicator */ - /* Make temporary variables as prev->next will point to different location */ - const size_t tmp_size = prev->next->size; - void* const tmp_next = prev->next->next; - - /* Shift block up, effectively increase its size */ - 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 */ - - block->size = final_size; /* Block size is requested size */ - } - } - LWMEM_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); - - /* If entry could not be found, there is a hard error */ - if (prev == NULL) { - return NULL; - } - - /* Order of variables is: | prevprev ---> prev --->--->--->--->--->--->--->--->--->---> prev->next | */ - /* | (input_block, which is not on a list) | */ - /* 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) - && (block_size + prev->next->size) >= final_size) { /* Size is greater or equal to requested */ - - /* - * Merge blocks together by increasing current block with size of next free one - * and remove next free from list of free blocks - */ - 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 */ - - 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 */ - return ptr; /* Return existing pointer */ - } - - /* - * Check if "block" and last free before "prev" create contiguous memory with size of at least new requested size. - * - * 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 */ - /* 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); - - /* - * If memmove overwrites metadata of current block (when shifting content up), - * it is not an issue as we know its size (block_size) and next is already NULL. - * - * Memmove must be used to guarantee move of data as addresses + their sizes may overlap - * - * Metadata of "prev" are not modified during memmove - */ - LWMEM_MEMMOVE(new_data_ptr, old_data_ptr, block_size); - - 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 */ - 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 */ - return new_data_ptr; /* Return new data ptr */ - } - - /* - * At this point, it was not possible to expand existing block with free before or free after due to: - * - Input block & next free block do not create contiguous block or its new size is too small - * - Previous free block & input block do not create contiguous block or its new size is too small - * - * 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 */ - - /* 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); - - /* - * If memmove overwrites metadata of current block (when shifting content up), - * it is not an issue as we know its size (block_size) and next is already NULL. - * - * Memmove must be used to guarantee move of data as addresses and their sizes may overlap - * - * 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 */ - - /* 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 */ - /* 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 */ - return new_data_ptr; /* Return new data ptr */ - } - } else { /* 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 */ + if (block_size == final_size) { + return ptr; /* Just return pointer, nothing to do */ + } + + /* + * Abbreviations + * + * - "Current block" or "Input block" is allocated block from input variable "ptr" + * - "Next free block" is next free block, on address space after input block + * - "Prev free block" is last free block, on address space before input block + * - "PrevPrev free block" is previous free block of "Prev free block" + */ + + /* + * When new requested size is smaller than existing one, + * it is enough to modify size of current block only. + * + * If new requested size is much smaller than existing one, + * check if it is possible to create new empty block and add it to list of empty blocks + * + * Application returns same pointer + */ + if (final_size < block_size) { + if ((block_size - final_size) >= LWMEM_BLOCK_MIN_SIZE) { + prv_split_too_big_block(lwobj, block, final_size); /* Split block if it is too big */ + } else { + /* + * It is not possible to create new empty block at the end of input block + * + * But if next free block is just after input block, + * it is possible to find this block and increase it by "block_size - final_size" bytes + */ + + /* Find free blocks before input block */ + LWMEM_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) + && prev->next->size > 0) { /* Must not be end of region indicator */ + /* Make temporary variables as prev->next will point to different location */ + const size_t tmp_size = prev->next->size; + void* const tmp_next = prev->next->next; + + /* Shift block up, effectively increase its size */ + 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; + + /* 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 */ + 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); + + /* If entry could not be found, there is a hard error */ + if (prev == NULL) { + return NULL; + } + + /* Order of variables is: | prevprev ---> prev --->--->--->--->--->--->--->--->--->---> prev->next | */ + /* | (input_block, which is not on a list) | */ + /* 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) + && (block_size + prev->next->size) >= final_size) { + + /* + * Merge blocks together by increasing current block with size of next free one + * and remove next free from list of free blocks + */ + 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 */ + + 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 */ + return ptr; /* Return existing pointer */ + } + + /* + * Check if "block" and last free before "prev" create contiguous memory with size of at least new requested size. + * + * 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) && (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); + + /* + * If memmove overwrites metadata of current block (when shifting content up), + * it is not an issue as we know its size (block_size) and next is already NULL. + * + * Memmove must be used to guarantee move of data as addresses + their sizes may overlap + * + * Metadata of "prev" are not modified during memmove + */ + LWMEM_MEMMOVE(new_data_ptr, old_data_ptr, block_size); + + 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 */ + 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 */ + return new_data_ptr; /* Return new data ptr */ + } + + /* + * At this point, it was not possible to expand existing block with free before or free after due to: + * - Input block & next free block do not create contiguous block or its new size is too small + * - Previous free block & input block do not create contiguous block or its new size is too small + * + * 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) + && (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); + void* const new_data_ptr = LWMEM_GET_PTR_FROM_BLOCK(prev); + + /* + * If memmove overwrites metadata of current block (when shifting content up), + * it is not an issue as we know its size (block_size) and next is already NULL. + * + * Memmove must be used to guarantee move of data as addresses and their sizes may overlap + * + * Metadata of "prev" are not modified during memmove + */ + LWMEM_MEMMOVE(new_data_ptr, old_data_ptr, block_size); + + /* 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 */ + + /* 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 */ + return new_data_ptr; /* Return new data ptr */ + } /* * If application reaches this point, it means: From 187bc462ebd67879b7abbb787c12638ed4ea84c2 Mon Sep 17 00:00:00 2001 From: Tilen Majerle Date: Wed, 9 Oct 2024 15:49:23 +0200 Subject: [PATCH 42/45] Change macro to LWMEM_CFG_FULL --- CHANGELOG.md | 2 +- dev/lwmem_opts.h | 10 +-- dev/main.cpp | 6 +- lwmem/src/include/lwmem/lwmem.h | 10 +-- lwmem/src/include/lwmem/lwmem.hpp | 4 +- lwmem/src/include/lwmem/lwmem_opt.h | 21 +++-- lwmem/src/lwmem/lwmem.c | 128 ++++++++++++++-------------- tests/lwmem_test.c | 4 +- tests/lwmem_test_simple.c | 4 +- 9 files changed, 97 insertions(+), 92 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 5c89552..3f59345 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -3,7 +3,7 @@ ## Develop - Rework library CMake with removed INTERFACE type -- Add `LWMEM_CFG_SUPPORT_REALLOC_AND_FREE` to disable realloc and free functions +- 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 diff --git a/dev/lwmem_opts.h b/dev/lwmem_opts.h index 5eb8912..c673313 100644 --- a/dev/lwmem_opts.h +++ b/dev/lwmem_opts.h @@ -41,10 +41,10 @@ * Open "include/lwmem/lwmem_opt.h" and * copy & replace here settings you want to change values */ -#define LWMEM_CFG_OS 1 -#define LWMEM_CFG_OS_MUTEX_HANDLE HANDLE -#define LWMEM_CFG_ENABLE_STATS 0 -#define LWMEM_CFG_CLEAN_MEMORY 1 -#define LWMEM_CFG_SUPPORT_REALLOC_AND_FREE 1 +#define LWMEM_CFG_OS 1 +#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 */ diff --git a/dev/main.cpp b/dev/main.cpp index e04b8ec..55b26b5 100644 --- a/dev/main.cpp +++ b/dev/main.cpp @@ -13,7 +13,7 @@ static Lwmem::LwmemLight<1024> manager; int main(void) { -#if LWMEM_CFG_SUPPORT_REALLOC_AND_FREE +#if LWMEM_CFG_FULL lwmem_test_memory_structure(); //lwmem_test_run(); #else @@ -24,9 +24,9 @@ main(void) { /* Test C++ code */ void* ret = manager.malloc(123); std::cout << ret << std::endl; -#if LWMEM_CFG_SUPPORT_REALLOC_AND_FREE +#if LWMEM_CFG_FULL manager.free(ret); -#endif /* LWMEM_CFG_SUPPORT_REALLOC_AND_FREE */ +#endif /* LWMEM_CFG_FULL */ #endif return 0; diff --git a/lwmem/src/include/lwmem/lwmem.h b/lwmem/src/include/lwmem/lwmem.h index 54f9041..93b4057 100644 --- a/lwmem/src/include/lwmem/lwmem.h +++ b/lwmem/src/include/lwmem/lwmem.h @@ -84,7 +84,7 @@ typedef struct { */ typedef struct lwmem { size_t mem_available_bytes; /*!< Memory size available for allocation */ -#if LWMEM_CFG_SUPPORT_REALLOC_AND_FREE +#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_regions_count; /*!< Number of regions used for allocation */ @@ -116,13 +116,13 @@ 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_SUPPORT_REALLOC_AND_FREE || __DOXYGEN__ +#if LWMEM_CFG_FULL || __DOXYGEN__ void* lwmem_realloc_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_SUPPORT_REALLOC_AND_FREE || __DOXYGEN__ */ +#endif /* LWMEM_CFG_FULL || __DOXYGEN__ */ #if LWMEM_CFG_ENABLE_STATS || __DOXYGEN__ void lwmem_get_stats_ex(lwmem_t* lwobj, lwmem_stats_t* stats); #endif /* LWMEM_CFG_ENABLE_STATS || __DOXYGEN__ */ @@ -131,14 +131,14 @@ size_t lwmem_assignmem(const lwmem_region_t* regions); void* lwmem_malloc(size_t size); void* lwmem_calloc(size_t nitems, size_t size); -#if LWMEM_CFG_SUPPORT_REALLOC_AND_FREE || __DOXYGEN__ +#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_SUPPORT_REALLOC_AND_FREE || __DOXYGEN__ */ +#endif /* LWMEM_CFG_FULL || __DOXYGEN__ */ #if LWMEM_CFG_ENABLE_STATS || __DOXYGEN__ diff --git a/lwmem/src/include/lwmem/lwmem.hpp b/lwmem/src/include/lwmem/lwmem.hpp index 5f40bca..ae218b1 100644 --- a/lwmem/src/include/lwmem/lwmem.hpp +++ b/lwmem/src/include/lwmem/lwmem.hpp @@ -93,7 +93,7 @@ class LwmemLight { return lwmem_calloc_ex(&m_lw, nullptr, nitems, size); } -#if LWMEM_CFG_SUPPORT_REALLOC_AND_FREE || __DOXYGEN__ +#if LWMEM_CFG_FULL || __DOXYGEN__ /** * \brief Reallocate block of memory * \param ptr: Pointer to previously allocated memory block @@ -115,7 +115,7 @@ class LwmemLight { free(void* ptr) { lwmem_free_ex(&m_lw, ptr); } -#endif /* LWMEM_CFG_SUPPORT_REALLOC_AND_FREE || __DOXYGEN__ */ +#endif /* LWMEM_CFG_FULL || __DOXYGEN__ */ private: /* Delete unused constructors */ diff --git a/lwmem/src/include/lwmem/lwmem_opt.h b/lwmem/src/include/lwmem/lwmem_opt.h index 81b200f..0b135e0 100644 --- a/lwmem/src/include/lwmem/lwmem_opt.h +++ b/lwmem/src/include/lwmem/lwmem_opt.h @@ -88,16 +88,21 @@ extern "C" { /** * \brief Enables `1` or disables `0` full memory management support. * - * When enabled, library supports allocation, reallocation and freeing of the memory. - * When disabled, library only supports allocation, which is useful for - * power up memory initialization only. + * When enabled (default config), library supports allocation, reallocation and freeing of the memory. + * - Memory allocation and [c]allocation + * - Memory reallocation + * - Memory allocation in user defined memory regions + * - Memory freeing * - * \note When disabled, \ref lwmem_get_size_ex is also not available, - * as it is assumed that user won't frequently ask for size of - * previously allocated block if realloc isn't being used + * 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_SUPPORT_REALLOC_AND_FREE -#define LWMEM_CFG_SUPPORT_REALLOC_AND_FREE 1 +#ifndef LWMEM_CFG_FULL +#define LWMEM_CFG_FULL 1 #endif /** diff --git a/lwmem/src/lwmem/lwmem.c b/lwmem/src/lwmem/lwmem.c index 0d13964..b62929b 100644 --- a/lwmem/src/lwmem/lwmem.c +++ b/lwmem/src/lwmem/lwmem.c @@ -40,10 +40,43 @@ #include "system/lwmem_sys.h" #endif /* LWMEM_CFG_OS */ +#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 */ + +/** + * \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 */ -#define LWMEM_ALIGN_BITS ((size_t)(((size_t)LWMEM_CFG_ALIGN_NUM) - 1)) +#define LWMEM_ALIGN_BITS ((size_t)(((size_t)LWMEM_CFG_ALIGN_NUM) - 1)) /** * \brief Aligns input value to next alignment bits @@ -60,18 +93,20 @@ * - Input: `7`; Output: `8` * - Input: `8`; Output: `8` */ -#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)) +#define LWMEM_ALIGN(x) (((x) + (LWMEM_ALIGN_BITS)) & ~(LWMEM_ALIGN_BITS)) /** * \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)) +#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 @@ -121,13 +156,7 @@ * * Default size is size of meta block */ -#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)) +#define LWMEM_BLOCK_MIN_SIZE (LWMEM_BLOCK_META_SIZE) /** * \brief Gets block before input block (marked as prev) and its previous free block @@ -142,35 +171,6 @@ (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 */ - -/** - * \brief LwMEM default structure used by application - */ -static lwmem_t lwmem_default; - -#if LWMEM_CFG_SUPPORT_REALLOC_AND_FREE - /** * \brief Get region aligned start address and aligned size * \param[in] region: Region to check for size and address @@ -765,7 +765,7 @@ prv_assignmem(lwmem_t* lwobj, const lwmem_region_t* regions) { return lwobj->mem_regions_count; /* Return number of regions used by manager */ } -#else /* LWMEM_CFG_SUPPORT_REALLOC_AND_FREE */ +#else /* LWMEM_CFG_FULL */ /** * \brief Assign the regions for simple algorithm @@ -828,7 +828,7 @@ prv_alloc_simple(lwmem_t* const lwobj, const lwmem_region_t* region, const size_ return retval; } -#endif /* LWMEM_CFG_SUPPORT_REALLOC_AND_FREE */ +#endif /* LWMEM_CFG_FULL */ /** * \brief Initializes and assigns user regions for memory used by allocator algorithm @@ -858,11 +858,11 @@ lwmem_assignmem_ex(lwmem_t* lwobj, const lwmem_region_t* regions) { /* Check first things first */ if (regions == NULL || (((size_t)LWMEM_CFG_ALIGN_NUM) & (((size_t)LWMEM_CFG_ALIGN_NUM) - 1)) > 0 -#if LWMEM_CFG_SUPPORT_REALLOC_AND_FREE +#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_SUPPORT_REALLOC_AND_FREE */ +#endif /* LWMEM_CFG_FULL */ ) { return 0; } @@ -883,7 +883,7 @@ lwmem_assignmem_ex(lwmem_t* lwobj, const lwmem_region_t* regions) { break; } -#if !LWMEM_CFG_SUPPORT_REALLOC_AND_FREE +#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. @@ -891,7 +891,7 @@ lwmem_assignmem_ex(lwmem_t* lwobj, const lwmem_region_t* regions) { else if (idx > 0) { return 0; } -#endif /* LWMEM_CFG_SUPPORT_REALLOC_AND_FREE */ +#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)) { @@ -913,11 +913,11 @@ lwmem_assignmem_ex(lwmem_t* lwobj, const lwmem_region_t* regions) { return 0; } -#if LWMEM_CFG_SUPPORT_REALLOC_AND_FREE +#if LWMEM_CFG_FULL return prv_assignmem(lwobj, regions); -#else /* LWMEM_CFG_SUPPORT_REALLOC_AND_FREE */ +#else /* LWMEM_CFG_FULL */ return prv_assignmem_simple(lwobj, regions); -#endif /* LWMEM_CFG_SUPPORT_REALLOC_AND_FREE */ +#endif /* LWMEM_CFG_FULL */ } /** @@ -937,11 +937,11 @@ lwmem_malloc_ex(lwmem_t* lwobj, const lwmem_region_t* region, const size_t size) lwobj = LWMEM_GET_LWOBJ(lwobj); LWMEM_PROTECT(lwobj); -#if LWMEM_CFG_SUPPORT_REALLOC_AND_FREE +#if LWMEM_CFG_FULL ptr = prv_alloc(lwobj, region, size); -#else /* LWMEM_CFG_SUPPORT_REALLOC_AND_FREE */ +#else /* LWMEM_CFG_FULL */ ptr = prv_alloc_simple(lwobj, region, size); -#endif /* LWMEM_CFG_SUPPORT_REALLOC_AND_FREE */ +#endif /* LWMEM_CFG_FULL */ LWMEM_UNPROTECT(lwobj); return ptr; } @@ -969,11 +969,11 @@ lwmem_calloc_ex(lwmem_t* lwobj, const lwmem_region_t* region, const size_t nitem lwobj = LWMEM_GET_LWOBJ(lwobj); LWMEM_PROTECT(lwobj); -#if LWMEM_CFG_SUPPORT_REALLOC_AND_FREE +#if LWMEM_CFG_FULL ptr = prv_alloc(lwobj, region, alloc_size); -#else /* LWMEM_CFG_SUPPORT_REALLOC_AND_FREE */ +#else /* LWMEM_CFG_FULL */ ptr = prv_alloc_simple(lwobj, region, alloc_size); -#endif /* LWMEM_CFG_SUPPORT_REALLOC_AND_FREE */ +#endif /* LWMEM_CFG_FULL */ LWMEM_UNPROTECT(lwobj); if (ptr != NULL) { @@ -982,7 +982,7 @@ lwmem_calloc_ex(lwmem_t* lwobj, const lwmem_region_t* region, const size_t nitem return ptr; } -#if LWMEM_CFG_SUPPORT_REALLOC_AND_FREE || __DOXYGEN__ +#if LWMEM_CFG_FULL || __DOXYGEN__ /** * \brief Reallocates already allocated memory with new size in specific lwmem instance and region. @@ -1133,7 +1133,7 @@ lwmem_get_size_ex(lwmem_t* lwobj, void* ptr) { return len; } -#endif /* LWMEM_CFG_SUPPORT_REALLOC_AND_FREE || __DOXYGEN__ */ +#endif /* LWMEM_CFG_FULL || __DOXYGEN__ */ #if LWMEM_CFG_ENABLE_STATS || __DOXYGEN__ @@ -1203,7 +1203,7 @@ lwmem_calloc(size_t nitems, size_t size) { return lwmem_calloc_ex(NULL, NULL, nitems, size); } -#if LWMEM_CFG_SUPPORT_REALLOC_AND_FREE || __DOXYGEN__ +#if LWMEM_CFG_FULL || __DOXYGEN__ /** * \note This is a wrapper for \ref lwmem_realloc_ex function. @@ -1268,12 +1268,12 @@ lwmem_get_size(void* ptr) { return lwmem_get_size_ex(NULL, ptr); } -#endif /* LWMEM_CFG_SUPPORT_REALLOC_AND_FREE || __DOXYGEN__ */ +#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 #include diff --git a/tests/lwmem_test.c b/tests/lwmem_test.c index 559e231..e9a725d 100644 --- a/tests/lwmem_test.c +++ b/tests/lwmem_test.c @@ -1,7 +1,7 @@ #include #include "lwmem/lwmem.h" -#if LWMEM_CFG_SUPPORT_REALLOC_AND_FREE +#if LWMEM_CFG_FULL /* Assert check */ #define ASSERT(x) \ @@ -229,4 +229,4 @@ lwmem_test_memory_structure(void) { (unsigned)rptr3, (unsigned)rptr4); } -#endif /* LWMEM_CFG_SUPPORT_REALLOC_AND_FREE */ \ No newline at end of file +#endif /* LWMEM_CFG_FULL */ \ No newline at end of file diff --git a/tests/lwmem_test_simple.c b/tests/lwmem_test_simple.c index 19fcc06..d1c9f7a 100644 --- a/tests/lwmem_test_simple.c +++ b/tests/lwmem_test_simple.c @@ -1,7 +1,7 @@ #include #include "lwmem/lwmem.h" -#if !LWMEM_CFG_SUPPORT_REALLOC_AND_FREE +#if !LWMEM_CFG_FULL /* Assert check */ #define ASSERT(x) \ @@ -65,4 +65,4 @@ lwmem_test_simple_run(void) { ASSERT(ptr == NULL); } -#endif /* !LWMEM_CFG_SUPPORT_REALLOC_AND_FREE */ \ No newline at end of file +#endif /* !LWMEM_CFG_FULL */ \ No newline at end of file From dbf2cdfd4c2eebf9ee4341d98883397e211609f7 Mon Sep 17 00:00:00 2001 From: Tilen Majerle Date: Sat, 12 Oct 2024 05:57:28 +0200 Subject: [PATCH 43/45] remove casting, implement static alignment size check --- lwmem/src/include/lwmem/lwmem_opt.h | 2 +- lwmem/src/lwmem/lwmem.c | 7 ++++++- 2 files changed, 7 insertions(+), 2 deletions(-) diff --git a/lwmem/src/include/lwmem/lwmem_opt.h b/lwmem/src/include/lwmem/lwmem_opt.h index 0b135e0..4465f3f 100644 --- a/lwmem/src/include/lwmem/lwmem_opt.h +++ b/lwmem/src/include/lwmem/lwmem_opt.h @@ -82,7 +82,7 @@ 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 /** diff --git a/lwmem/src/lwmem/lwmem.c b/lwmem/src/lwmem/lwmem.c index b62929b..783db12 100644 --- a/lwmem/src/lwmem/lwmem.c +++ b/lwmem/src/lwmem/lwmem.c @@ -62,6 +62,11 @@ #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 */ @@ -857,7 +862,7 @@ lwmem_assignmem_ex(lwmem_t* lwobj, const lwmem_region_t* regions) { lwobj = LWMEM_GET_LWOBJ(lwobj); /* Check first things first */ - if (regions == NULL || (((size_t)LWMEM_CFG_ALIGN_NUM) & (((size_t)LWMEM_CFG_ALIGN_NUM) - 1)) > 0 + if (regions == NULL #if LWMEM_CFG_FULL || lwobj->end_block != NULL /* Init function may only be called once per lwmem instance */ #else From cc89b1b755054873316bd91289169b55c381078a Mon Sep 17 00:00:00 2001 From: Tilen Majerle Date: Sat, 12 Oct 2024 06:09:27 +0200 Subject: [PATCH 44/45] move more internal code to functions --- lwmem/src/lwmem/lwmem.c | 62 ++++++++++++++++++++--------------------- 1 file changed, 31 insertions(+), 31 deletions(-) diff --git a/lwmem/src/lwmem/lwmem.c b/lwmem/src/lwmem/lwmem.c index 783db12..cf92bb2 100644 --- a/lwmem/src/lwmem/lwmem.c +++ b/lwmem/src/lwmem/lwmem.c @@ -123,18 +123,6 @@ static lwmem_t lwmem_default; */ #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 @@ -167,14 +155,26 @@ static lwmem_t 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) +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 Set block as allocated + * \param[in] block: Block to set as allocated + */ +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 @@ -185,8 +185,8 @@ static lwmem_t lwmem_default; */ static uint8_t prv_get_region_addr_size(const lwmem_region_t* region, uint8_t** msa, size_t* msz) { - size_t mem_size; - uint8_t* mem_start_addr; + size_t mem_size = 0; + uint8_t* mem_start_addr = NULL; if (region == NULL || msa == NULL || msz == NULL) { return 0; @@ -345,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; } @@ -435,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); @@ -481,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 */ @@ -547,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) @@ -567,14 +567,14 @@ prv_realloc(lwmem_t* const lwobj, const lwmem_region_t* region, void* const ptr, block->size = final_size; /* Block size is requested size */ } } - LWMEM_BLOCK_SET_ALLOC(block); /* Set block as allocated */ - return ptr; /* Return existing pointer */ + 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) { @@ -600,7 +600,7 @@ prv_realloc(lwmem_t* const lwobj, const lwmem_region_t* region, void* const ptr, 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 */ } @@ -632,7 +632,7 @@ prv_realloc(lwmem_t* const lwobj, const lwmem_region_t* region, void* const ptr, 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 */ } @@ -672,7 +672,7 @@ prv_realloc(lwmem_t* const lwobj, const lwmem_region_t* region, void* const ptr, 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 */ } From c36034a686c894e47e3a8b9cbdf86fa19a82d23d Mon Sep 17 00:00:00 2001 From: Tilen M Date: Sat, 12 Oct 2024 15:13:19 +0200 Subject: [PATCH 45/45] release v2.2.0 --- CHANGELOG.md | 2 ++ README.md | 1 + docs/index.rst | 1 + docs/user-manual/index.rst | 1 + docs/user-manual/light-version.rst | 19 +++++++++++++++++++ library.json | 2 +- lwmem/src/include/lwmem/lwmem.h | 15 ++------------- lwmem/src/include/lwmem/lwmem.hpp | 2 +- lwmem/src/include/lwmem/lwmem_opt.h | 4 ++-- lwmem/src/include/lwmem/lwmem_opts_template.h | 2 +- lwmem/src/include/system/lwmem_sys.h | 2 +- lwmem/src/lwmem/lwmem.c | 13 +++++++++++-- lwmem/src/lwmem/lwmem.cpp | 2 +- lwmem/src/system/lwmem_sys_cmsis_os.c | 2 +- lwmem/src/system/lwmem_sys_threadx.c | 2 +- lwmem/src/system/lwmem_sys_win32.c | 11 +++-------- 16 files changed, 49 insertions(+), 32 deletions(-) create mode 100644 docs/user-manual/light-version.rst diff --git a/CHANGELOG.md b/CHANGELOG.md index 3f59345..7be6735 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,6 +2,8 @@ ## 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 diff --git a/README.md b/README.md index 0e1d0b6..4e73f86 100644 --- a/README.md +++ b/README.md @@ -13,6 +13,7 @@ * 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 diff --git a/docs/index.rst b/docs/index.rst index 152195e..63c3aba 100644 --- a/docs/index.rst +++ b/docs/index.rst @@ -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 diff --git a/docs/user-manual/index.rst b/docs/user-manual/index.rst index 6ead08e..7469f4b 100644 --- a/docs/user-manual/index.rst +++ b/docs/user-manual/index.rst @@ -9,4 +9,5 @@ User manual how-it-works instances realloc-algorithm + light-version thread-safety \ No newline at end of file diff --git a/docs/user-manual/light-version.rst b/docs/user-manual/light-version.rst new file mode 100644 index 0000000..3f8eada --- /dev/null +++ b/docs/user-manual/light-version.rst @@ -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 diff --git a/library.json b/library.json index a7197fa..aa4ac05 100644 --- a/library.json +++ b/library.json @@ -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": { diff --git a/lwmem/src/include/lwmem/lwmem.h b/lwmem/src/include/lwmem/lwmem.h index 93b4057..7ff3ea1 100644 --- a/lwmem/src/include/lwmem/lwmem.h +++ b/lwmem/src/include/lwmem/lwmem.h @@ -29,7 +29,7 @@ * This file is part of LwMEM - Lightweight dynamic memory manager library. * * Author: Tilen MAJERLE - * Version: v2.1.0 + * Version: v2.2.0 */ #ifndef LWMEM_HDR_H #define LWMEM_HDR_H @@ -125,6 +125,7 @@ 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__ */ size_t lwmem_assignmem(const lwmem_region_t* regions); @@ -137,20 +138,8 @@ 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 LWMEM_CFG_ENABLE_STATS || __DOXYGEN__ - -/** - * \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)) - -#endif /* LWMEM_CFG_ENABLE_STATS || __DOXYGEN__ */ - #if defined(LWMEM_DEV) && !__DOXYGEN__ unsigned char lwmem_debug_create_regions(lwmem_region_t** regs_out, size_t count, size_t size); void lwmem_debug_save_state(void); diff --git a/lwmem/src/include/lwmem/lwmem.hpp b/lwmem/src/include/lwmem/lwmem.hpp index ae218b1..cad3dab 100644 --- a/lwmem/src/include/lwmem/lwmem.hpp +++ b/lwmem/src/include/lwmem/lwmem.hpp @@ -29,7 +29,7 @@ * This file is part of LwMEM - Lightweight dynamic memory manager library. * * Author: Tilen MAJERLE - * Version: v2.1.0 + * Version: v2.2.0 */ #ifndef LWMEM_HDR_HPP #define LWMEM_HDR_HPP diff --git a/lwmem/src/include/lwmem/lwmem_opt.h b/lwmem/src/include/lwmem/lwmem_opt.h index 4465f3f..e0b7df1 100644 --- a/lwmem/src/include/lwmem/lwmem_opt.h +++ b/lwmem/src/include/lwmem/lwmem_opt.h @@ -29,7 +29,7 @@ * This file is part of LwMEM - Lightweight dynamic memory manager library. * * Author: Tilen MAJERLE - * Version: v2.1.0 + * Version: v2.2.0 */ #ifndef LWMEM_OPT_HDR_H #define LWMEM_OPT_HDR_H @@ -89,7 +89,7 @@ extern "C" { * \brief Enables `1` or disables `0` full memory management support. * * When enabled (default config), library supports allocation, reallocation and freeing of the memory. - * - Memory allocation and [c]allocation + * - Memory [c]allocation * - Memory reallocation * - Memory allocation in user defined memory regions * - Memory freeing diff --git a/lwmem/src/include/lwmem/lwmem_opts_template.h b/lwmem/src/include/lwmem/lwmem_opts_template.h index e7b92c8..68dbfa6 100644 --- a/lwmem/src/include/lwmem/lwmem_opts_template.h +++ b/lwmem/src/include/lwmem/lwmem_opts_template.h @@ -29,7 +29,7 @@ * This file is part of LwMEM - Lightweight dynamic memory manager library. * * Author: Tilen MAJERLE - * Version: v2.1.0 + * Version: v2.2.0 */ #ifndef LWMEM_OPTS_HDR_H #define LWMEM_OPTS_HDR_H diff --git a/lwmem/src/include/system/lwmem_sys.h b/lwmem/src/include/system/lwmem_sys.h index c6a92ab..841b7d4 100644 --- a/lwmem/src/include/system/lwmem_sys.h +++ b/lwmem/src/include/system/lwmem_sys.h @@ -29,7 +29,7 @@ * This file is part of LwMEM - Lightweight dynamic memory manager library. * * Author: Tilen MAJERLE - * Version: v2.1.0 + * Version: v2.2.0 */ #ifndef LWMEM_SYS_HDR_H #define LWMEM_SYS_HDR_H diff --git a/lwmem/src/lwmem/lwmem.c b/lwmem/src/lwmem/lwmem.c index cf92bb2..9300227 100644 --- a/lwmem/src/lwmem/lwmem.c +++ b/lwmem/src/lwmem/lwmem.c @@ -29,7 +29,7 @@ * This file is part of LwMEM - Lightweight dynamic memory manager library. * * Author: Tilen MAJERLE - * Version: v2.1.0 + * Version: v2.2.0 */ #include "lwmem/lwmem.h" #include @@ -1146,7 +1146,7 @@ lwmem_get_size_ex(lwmem_t* lwobj, void* ptr) { * \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) { @@ -1159,6 +1159,15 @@ 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__ */ /** diff --git a/lwmem/src/lwmem/lwmem.cpp b/lwmem/src/lwmem/lwmem.cpp index 4229285..ea5fc14 100644 --- a/lwmem/src/lwmem/lwmem.cpp +++ b/lwmem/src/lwmem/lwmem.cpp @@ -29,5 +29,5 @@ * This file is part of LwMEM - Lightweight dynamic memory manager library. * * Author: Tilen MAJERLE - * Version: v2.1.0 + * Version: v2.2.0 */ diff --git a/lwmem/src/system/lwmem_sys_cmsis_os.c b/lwmem/src/system/lwmem_sys_cmsis_os.c index 16ecb60..9db2f44 100644 --- a/lwmem/src/system/lwmem_sys_cmsis_os.c +++ b/lwmem/src/system/lwmem_sys_cmsis_os.c @@ -29,7 +29,7 @@ * This file is part of LwMEM - Lightweight dynamic memory manager library. * * Author: Tilen MAJERLE - * Version: v2.1.0 + * Version: v2.2.0 */ #include "system/lwmem_sys.h" diff --git a/lwmem/src/system/lwmem_sys_threadx.c b/lwmem/src/system/lwmem_sys_threadx.c index af4b7ee..500c0e2 100644 --- a/lwmem/src/system/lwmem_sys_threadx.c +++ b/lwmem/src/system/lwmem_sys_threadx.c @@ -29,7 +29,7 @@ * This file is part of LwMEM - Lightweight dynamic memory manager library. * * Author: Tilen MAJERLE - * Version: v2.1.0 + * Version: v2.2.0 */ #include "system/lwmem_sys.h" diff --git a/lwmem/src/system/lwmem_sys_win32.c b/lwmem/src/system/lwmem_sys_win32.c index 2b29ac0..3a50386 100644 --- a/lwmem/src/system/lwmem_sys_win32.c +++ b/lwmem/src/system/lwmem_sys_win32.c @@ -29,13 +29,13 @@ * This file is part of LwMEM - Lightweight dynamic memory manager library. * * Author: Tilen MAJERLE - * 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