Merge branch 'feature/sphinx' into develop

This commit is contained in:
Tilen Majerle 2019-12-07 03:51:42 +01:00
commit 11acbe6029
46 changed files with 3296 additions and 539 deletions

1
.gitignore vendored
View File

@ -23,6 +23,7 @@
*.__i *.__i
*.i *.i
*.txt *.txt
!docs/*.txt
RTE/ RTE/
# IAR Settings # IAR Settings

20
docs/Makefile Normal file
View File

@ -0,0 +1,20 @@
# Minimal makefile for Sphinx documentation
#
# You can set these variables from the command line, and also
# from the environment for the first two.
SPHINXOPTS ?=
SPHINXBUILD ?= sphinx-build
SOURCEDIR = .
BUILDDIR = _build
# Put it first so that "make" without argument is like "make help".
help:
@$(SPHINXBUILD) -M help "$(SOURCEDIR)" "$(BUILDDIR)" $(SPHINXOPTS) $(O)
.PHONY: help Makefile
# Catch-all target: route all unknown targets to Sphinx using the new
# "make mode" option. $(O) is meant as a shortcut for $(SPHINXOPTS).
%: Makefile
@$(SPHINXBUILD) -M $@ "$(SOURCEDIR)" "$(BUILDDIR)" $(SPHINXOPTS) $(O)

View File

@ -0,0 +1,11 @@
API reference
=============
List of all the modules:
.. toctree::
:maxdepth: 2
lwmem
lwmem_config
lwmem_sys

View File

@ -0,0 +1,6 @@
.. _api_lwmem:
LwMEM
=====
.. doxygengroup:: LWMEM

View File

@ -0,0 +1,6 @@
.. _api_lwmem_config:
LwMEM Configuration
===================
.. doxygengroup:: LWMEM_CONFIG

View File

@ -0,0 +1,9 @@
.. _api_lwmem_sys:
System functions
================
System function are used in conjunction with thread safety.
Please check :ref:`thread_safety` section for more information
.. doxygengroup:: LWMEM_SYS

105
docs/conf.py Normal file
View File

@ -0,0 +1,105 @@
# Configuration file for the Sphinx documentation builder.
#
# This file only contains a selection of the most common options. For a full
# list see the documentation:
# https://www.sphinx-doc.org/en/master/usage/configuration.html
# -- Path setup --------------------------------------------------------------
# If extensions (or modules to document with autodoc) are in another directory,
# add these directories to sys.path here. If the directory is relative to the
# documentation root, use os.path.abspath to make it absolute, like shown here.
#
# import os
# import sys
# sys.path.insert(0, os.path.abspath('.'))
from sphinx.builders.html import StandaloneHTMLBuilder
import subprocess, os
# Run doxygen first
# read_the_docs_build = os.environ.get('READTHEDOCS', None) == 'True'
# if read_the_docs_build:
subprocess.call('doxygen doxy_lwmem.doxy', shell=True)
# -- Project information -----------------------------------------------------
project = 'LwMEM'
copyright = '2019, Tilen Majerle'
author = 'Tilen MAJERLE'
# The full version, including alpha/beta/rc tags
release = '1.2.0'
# -- General configuration ---------------------------------------------------
# Add any Sphinx extension module names here, as strings. They can be
# extensions coming with Sphinx (named 'sphinx.ext.*') or your custom
# ones.
extensions = [
'sphinx.ext.autodoc',
'sphinx.ext.intersphinx',
'sphinx.ext.autosectionlabel',
'sphinx.ext.todo',
'sphinx.ext.coverage',
'sphinx.ext.mathjax',
'sphinx.ext.ifconfig',
'sphinx.ext.viewcode',
'breathe',
]
# Add any paths that contain templates here, relative to this directory.
templates_path = ['templates']
# List of patterns, relative to source directory, that match files and
# directories to ignore when looking for source files.
# This pattern also affects html_static_path and html_extra_path.
exclude_patterns = ['_build', 'Thumbs.db', '.DS_Store']
highlight_language = 'c'
# -- Options for HTML output -------------------------------------------------
# The theme to use for HTML and HTML Help pages. See the documentation for
# a list of builtin themes.
#
html_theme = 'sphinx_rtd_theme'
html_theme_options = {
'canonical_url': '',
'analytics_id': '', # Provided by Google in your dashboard
'display_version': True,
'prev_next_buttons_location': 'bottom',
'style_external_links': False,
'logo_only': False,
# Toc options
'collapse_navigation': True,
'sticky_navigation': True,
'navigation_depth': 4,
'includehidden': True,
'titles_only': False
}
html_logo = 'static/images/logo_tm.png'
github_url = 'https://github.com/MaJerle/lwmem'
# Add any paths that contain custom static files (such as style sheets) here,
# relative to this directory. They are copied after the builtin static files,
# so a file named "default.css" will overwrite the builtin "default.css".
html_static_path = ['static']
html_css_files = [
'css/common.css',
'css/custom.css',
]
master_doc = 'index'
#
# Breathe configuration
#
#
#
breathe_projects = {
"lwmem": "_build/xml/"
}
breathe_default_project = "lwmem"
breathe_default_members = ('members', 'undoc-members')

2456
docs/doxy_lwmem.doxy Normal file

File diff suppressed because it is too large Load Diff

View File

@ -1,12 +0,0 @@
#ifndef LWMEM_HDR_CONFIG_H
#define LWMEM_HDR_CONFIG_H
/* Rename this file to "lwmem_config.h" for your application */
/* Enable operating system support */
#define LWMEM_CFG_OS 1
/* After user configuration, call default config to merge config together */
#include "lwmem/lwmem_config_default.h"
#endif /* LWMEM_HDR_CONFIG_H */

View File

@ -1,14 +0,0 @@
#ifndef LWMEM_HDR_CONFIG_H
#define LWMEM_HDR_CONFIG_H
/* Rename this file to "lwmem_config.h" for your application */
/*
* Open "include/lwmem/lwmem_config_default.h" and
* copy & replace here settings you want to change values
*/
/* After user configuration, call default config to merge config together */
#include "lwmem/lwmem_config_default.h"
#endif /* LWMEM_HDR_CONFIG_H */

View File

@ -1,31 +0,0 @@
/* Config header in lwmem_config.h file */
#define LWMEM_CFG_OS_MUTEX_HANDLE osMutexId
/* System file */
uint8_t
lwmem_sys_mutex_create(LWMEM_CFG_OS_MUTEX_HANDLE* m) {
osMutexDef(mut);
*m = osMutexCreate(osMutex(mut));
return 1;
}
uint8_t
lwmem_sys_mutex_isvalid(LWMEM_CFG_OS_MUTEX_HANDLE* m) {
return *m != NULL;
}
uint8_t
lwmem_sys_mutex_wait(LWMEM_CFG_OS_MUTEX_HANDLE* m) {
if (osMutexWait(*m, osWaitForever) != osOK) {
return 0;
}
return 1;
}
uint8_t
lwmem_sys_mutex_release(LWMEM_CFG_OS_MUTEX_HANDLE* m) {
if (osMutexRelease(*m) != osOK) {
return 0;
}
return 1;
}

View File

@ -0,0 +1,27 @@
#include "lwmem/lwmem.h"
void* ptr;
/* Create regions, address and length of regions */
static
lwmem_region_t regions[] = {
/* Set start address and size of each region */
{ (void *)0x10000000, 0x00001000 },
{ (void *)0xA0000000, 0x00008000 },
{ (void *)0xC0000000, 0x00008000 },
};
/* Later in the initialization process */
/* Assign regions for manager */
lwmem_assignmem(regions, sizeof(regions) / sizeof(regions[0]));
ptr = lwmem_malloc(8); /* Allocate 8 bytes of memory */
if (ptr != NULL) {
/* Allocation successful */
}
/* Later... */ /* Free allocated memory */
lwmem_free(ptr);
ptr = NULL;
/* .. or */
lwmem_free_s(&ptr);

View File

@ -0,0 +1,69 @@
.. _get_started:
Get started
===========
.. _download_library:
Download library
^^^^^^^^^^^^^^^^
Library is primarly hosted on `Github <https://github.com/MaJerle/lwmem>`_.
* Download latest release from `releases area <https://github.com/MaJerle/lwmem/releases>`_ on Github
* Clone `develop` branch for latest development
Download from releases
**********************
All releases are available on Github releases `releases area <https://github.com/MaJerle/lwmem/releases>`_.
Clone from Github
*****************
First-time clone
""""""""""""""""
* Download and install ``git`` if not already
* Open console and navigate to path in the system to clone repository to. Use command ``cd your_path``
* Run ``git clone --recurse-submodules https://github.com/MaJerle/lwmem`` command to clone repository including submodules or
* Run ``git clone --recurse-submodules --branch develop https://github.com/MaJerle/lwmem`` to clone `development` branch
* Navigate to ``examples`` directory and run favourite example
Update cloned to latest version
"""""""""""""""""""""""""""""""
* Open console and navigate to path in the system where your resources repository is. Use command ``cd your_path``
* Run ``git pull origin master --recurse-submodules`` command to pull latest changes and to fetch latest changes from submodules
* Run ``git submodule foreach git pull origin master`` to update & merge all submodules
Add library to project
^^^^^^^^^^^^^^^^^^^^^^
At this point it is assumed that you have successfully download library, either cloned it or from releases page.
* Copy ``lwmem`` folder to your project
* Add ``lwmem/src/include`` folder to `include path` of your toolchain
* Add source files from ``lwmem/src/`` folder to toolchain build
* Copy ``lwmem/src/include/lwmem/lwmem_config_template.h`` to project folder and rename it to ``lwmem_config.h``
* Build the project
Configuration file
^^^^^^^^^^^^^^^^^^
Library comes with template config file, which can be modified according to needs.
This file shall be named ``lwmem_config.h`` and its default template looks like the one below:
.. tip::
Check :ref:`api_lwmem_config` section for possible configuration settings
.. literalinclude:: ../../lwmem/src/include/lwmem/lwmem_config_template.h
:language: c
Minimal example code
^^^^^^^^^^^^^^^^^^^^
Run below example to test and verify library
.. literalinclude:: ../examples/example_minimal.c
:language: c

56
docs/index.rst Normal file
View File

@ -0,0 +1,56 @@
LwMEM documentation!
====================
LwMEM is lightweight dynamic memory manager optimized for embedded systems.
.. class::center
:ref:`download_library` · `Github <https://github.com/MaJerle/lwmem>`_
Features
^^^^^^^^
* Written in ANSI C99, 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 free block
* Supports different memory regions to allow use of fragmented memories
* Suitable for embedded applications with fragmented memories
* Suitable for automotive applications
* Supports advanced free/realloc algorithms to optimize memory usage
* Operating system ready, thread-safe API
* User friendly MIT license
Requirements
^^^^^^^^^^^^
* C compiler
* Less than ``2kB`` of memory
Contribute
^^^^^^^^^^
We always welcome new contributors. To be as efficient as possible, we recommend:
#. Fork Github repository
#. Respect `C style & coding rules <https://github.com/MaJerle/c-code-style>`_ used by the library
#. Make a pull request to ``develop`` branch with new features or bug fixes
Alternatively you may:
#. Report a bug
#. Ask for a feature request
License
^^^^^^^
.. literalinclude:: license.txt
Table of contents
^^^^^^^^^^^^^^^^^
.. toctree::
:maxdepth: 2
get-started/index
user-manual/index
api-reference/index

21
docs/license.txt Normal file
View File

@ -0,0 +1,21 @@
Copyright (c) 2019 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 in the Software without restriction,
including without limitation the rights to use, copy, modify, merge,
publish, distribute, sublicense, and/or sell copies of the Software,
and to permit persons to whom the Software is furnished to do so,
subject to the following conditions:
The above copyright notice and this permission notice shall be
included in all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE
AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
OTHER DEALINGS IN THE SOFTWARE.

35
docs/make.bat Normal file
View File

@ -0,0 +1,35 @@
@ECHO OFF
pushd %~dp0
REM Command file for Sphinx documentation
if "%SPHINXBUILD%" == "" (
set SPHINXBUILD=sphinx-build
)
set SOURCEDIR=.
set BUILDDIR=_build
if "%1" == "" goto help
%SPHINXBUILD% >NUL 2>NUL
if errorlevel 9009 (
echo.
echo.The 'sphinx-build' command was not found. Make sure you have Sphinx
echo.installed, then set the SPHINXBUILD environment variable to point
echo.to the full path of the 'sphinx-build' executable. Alternatively you
echo.may add the Sphinx directory to PATH.
echo.
echo.If you don't have Sphinx installed, grab it from
echo.http://sphinx-doc.org/
exit /b 1
)
%SPHINXBUILD% -M %1 %SOURCEDIR% %BUILDDIR% %SPHINXOPTS% %O%
goto end
:help
%SPHINXBUILD% -M help %SOURCEDIR% %BUILDDIR% %SPHINXOPTS% %O%
:end
popd

7
docs/requirements.txt Normal file
View File

@ -0,0 +1,7 @@
breathe>=4.9.1
colorama
docutils>=0.14
sphinx>=2.0.1
sphinx_rtd_theme
sphinx-tabs
sphinxcontrib-svg2pdfconverter

View File

@ -1,403 +0,0 @@
/**
* \page page_appnote Application note
* \tableofcontents
*
* \section sect_getting_started Getting started
*
* Repository <a href="https://github.com/MaJerle/lwmem"><b>lwmem is hosted on Github</b></a>. It combines source code and example projects.
*
* \subsection sect_clone Clone repository
*
* \par First-time clone
*
* - Download and install `git` if not already
* - Open console and navigate to path in the system to clone repository to. Use command `cd your_path`
* - Run `git clone --recurse-submodules https://github.com/MaJerle/lwmem` command to clone repository including submodules
* - Navigate to `examples` directory and run favourite example
*
* \par Already cloned, update to latest version
*
* - Open console and navigate to path in the system where your resources repository is. Use command `cd your_path`
* - Run `git pull origin master --recurse-submodules` command to pull latest changes and to fetch latest changes from submodules
* - Run `git submodule foreach git pull origin master` to update & merge all submodules
*
* \section sect_config Library configuration
*
* To make library as efficient as possible, different configuration parameters are available
* to make sure all the requirements are met for different purposes as possible.
*
* A list of all configurations can be found in \ref LWMEM_CONFIG section.
*
* \subsection sect_conf_file Project configuration file
*
* Library comes with `2` configuration files:
*
* - Default configuration file `lwmem_config_default.h`
* - Project template configuration file `lwmem_config_template.h`
*
* When project is started, user has to rename template file to `lwmem_config.h`
* and if required, it should override default settings in this file.
*
* Default template file comes with something like this:
*
* \include _lwmem_config_template.h
*
* If bigger buffer is required, modification must be made like following:
*
* \include _lwmem_config.h
*
* \note Always modify default settings by overriding them in user's custom `lwmem_config.h` file
* which was previously renamed from `lwmem_config_template.h`
*
* \section sect_how_it_works How memory allocation works
*
* For the sake of example memory manager on images uses `3` regions:
*
* - Region `1` memory starts at `0x1000 0000` and is `0x0000 1000` bytes long
* - Region `2` memory starts at `0xA000 0000` and is `0x0000 8000` bytes long
* - Region `3` memory starts at `0xC000 0000` and is `0x0000 8000` bytes long
* - Total size of memory used by application for memory manager is `0x0001 1000` bytes or `69 kB`
*
* Furthermore, example assumes:
*
* - Size of any kind of pointer is `4-bytes`, `sizeof(any_pointer_type) = 4`
* - Size of `size_t` type is `4-bytes`, `sizeof(size_t) = 4`
*
* In C code, defining these regions for memory manager would look similar to example below.
*
* \include example_regions_definitions.c
*
* After the initialization process, memory is written with some values, available on picture below.
*
* \image html structure_default.svg Default memory structure after initialization
*
* Memory managers sets some default values, these are:
*
* - All regions are connected through single linked list. Each member of linked list represents free memory slot
* - `Start block` is variable in the library and points to first free memory on the list. By default, this is beginning of first region
* - Each region consists of `2 free slots`
* - One at the end of each region. It takes `8 bytes` of memory:
* - Size of slot is set to `0` and it means no available memory
* - Its `next` value points to next free slot in another region. Set to `NULL` if there is no free slot available anymore after or in case of last region on a list
* - One on beginning of region. It also takes `8 bytes` of memory:
* - Size of slot is set to `region_size - 8`, ignoring size of last slot.
* Effective size of memory application may allocate in region is always for `2` meta slots less than region size,
* which means `max_app_malloc_size = region_size - 2 * 8 bytes`
* - Its `next` value points to end slot in the same region
*
* When application calls one of allocation functions and if requested size of memory is less than maximal one,
* manager will allocate desired memory and will mark it as used. If requested size is bigger than available memory
* in first region, manager will continue to check size of next free slots in other regions.
*
* \image html structure_first_alloc.svg Memory structure after first allocation
*
* - Light red background slot indicates memory `in use`.
* - All blocks marked `in use` have:
* - `next` value is set to `NULL`
* - `size` value has MSB bit set to `1`, indicating block is allocated and the rest of bits represent size of block, including metadata size
* - If application asks for `8 bytes`, fields are written as `next = 0x0000 0000` and `size = 0x8000 000F`
* - `Start block` now points to free slot somewhere in the middle of region
*
* Follow description of bottom image for more information about allocation and deallocation.
*
* \image html structure_alloc_free_steps.svg Step-by-step memory structure after multiple allocations and deallocations
*
* Image shows only first region to simplify process. Same procedure applies to other regions aswell.
*
* - `Case A`: Second block allocated. Remaining memory is now smaller and `Start block` points to it
* - `Case B`: Third block allocated. Remaining memory is now smaller and `Start block` points to it
* - `Case C`: Forth block allocated. Remaining memory is now smaller and `Start block` points to it
* - `Case D`: Third block freed and added back to linked list of free slots.
* - `Case E`: Forth block freed. Manager detects blocks before and after current are free and merges all to one big contiguous block
* - `Case F`: First block freed. `Start block` points to it as it has been added back to linked list
* - `Case G`: Second block freed. Manager detects blocks before and after current are free and merges all to one big contiguous block.
* - No any memory allocated anymore, regions are back to default state
*
* \section sect_realloc_how_it_works Optimized re-allocation algorithm
*
* why would you need re-allocation algorithm at first place?
*
* Sometimes application uses variable length of memory,
* specially when number of (for example) elements in not fully known in advance.
* An example, application anticipates `12` numbers but may (for some reason) in some cases receive more than this.
* If application needs to hold all received numbers, it may be necessary to:
*
* - Option `1`: Increase memory block size using reallocations on demand
* - Option `2`: Use very big (do we know how much?) array, allocated statically or dynamically,
* which would hold all numbers at any time possible
*
* Application wants to use as less memory as possible, so we will take option `1`, to increase memory only on demand.
*
* Let's first define our region(s). For the sake of example, application uses single region:
*
* \include example_realloc_region.c
*
* When executed, it prints (test machine)
*
* \include example_realloc_region_log.c
*
* Next, application allocates memory for `12 integers`.
*
* \include example_realloc_first_malloc.c
*
* When executed, it prints (test machine)
*
* \include example_realloc_first_malloc_log.c
*
* We can see, there is one block with `64` bytes available.
* It means that manager spent `120 - 64 = 56` bytes to allocate memory for `12` integers.
*
* \note Every allocated block holds meta data.
* On test machine, `sizeof(int) = 4` therefore `8` bytes are used for metadata as `56 - 12 * sizeof(int) = 8`.
* Size of meta data header depends on CPU architecture and may be different on final architecture
*
* What happens, if (for some reason) application needs more memory than current block is?
* Let's say application needs to increase memory to be able to hold `13` integers.
*
* The easiest way would be:
*
* 1. Allocate new memory block with new size and check if allocation was successful
* 2. Manually copy content from old block to new block
* 3. Free old memory block
* 4. Use new block for all future operations
*
* \include example_realloc_custom_realloc.c
*
* When executed, it prints (test machine)
*
* \include example_realloc_custom_realloc_log.c
*
* Looking at the debug output:
*
* - Memory was successfully allocated for `12` integers, it took `56 bytes`
* - Memory was successfully allocated for another `13` integers , it took `64 bytes`
* - There is no more free memory available
* - First `12` integers array was successfully freed, manager has `56` bytes of free memory
* - Second `13` integers block was successfully freed, manager has all `120` bytes available for new allocations
*
* What would happen, if application needs to increase block size for `3` more bytes? From `12` to `15`.
* When same code is executed, but with `15` in second case:
*
* \include example_realloc_custom_realloc_log_2.c
*
* It was not possible to allocate new memory for `15` integers.
* We just need to increase for `3` more integers, which is `12 bytes`,
* there are `64` bytes of memory available, but we were not able to use them!
*
* The same effect would happen if application wants to decrease integer count from `15` to `12` numbers.
* There is not enough memory to allocate new block for `12` integers.
*
* \note Effectively it means that maximal block size we can allocate is less than `50%` of full memory,
* if we intend to increase it in the future using above method.
*
* \par Solution: Try to manipulate existing block as much as possible
*
* To avoid having multiple temporary allocations, we could only manipulate existing block to modify its size.
* Let's start with simplest example.
*
* \subsection sect_realloc_shrinking Shrinking existing block
*
* When applications tries to decrease memory size, manager could only modify block size parameters.
* This will effectively shrink block size and allow other parts of application to
* allocate memory using memory manager.
*
* \include example_realloc_shrink.c
*
* When executed, it prints (test machine)
*
* \include example_realloc_shrink_log.c
*
* \image html structure_realloc_shrink.svg New size is smaller than existing one
*
* Looking at the debug output and image above:
*
* - Memory was successfully allocated for `15` integers, it took `68` bytes; part `A` on image
* - Memory was successfully re-allocated to `12` integers, now it takes `56` bytes, part `B` on image
* - In both cases on image, final returned memory points to the same address
* - Manager does not need to copy data from existing memory to new address as it is the same memory used in both cases
* - Empty block start address has been modified and its size has been increased, part `B` on image
* - Reallocated block was successfully freed, manager has all `120` bytes for new allocations
*
* This was very basic and primitive example. However, it is not always possible to increase free block size.
* Consider new example and dedicated image below:
*
* \include example_realloc_shrink_fragmented.c
*
* \image html structure_realloc_shrink_fragmented.svg Decreasing size on fragmented blocks
*
* When executed, it prints (test machine)
*
* \include example_realloc_shrink_fragmented_log.c
*
* Looking at the debug output and image above:
*
* - Size of all `4` blocks is `24` bytes; `16` for user data, `8` for metadata
* - Reallocating block first time from `16` to `12` user data bytes did not affect internal memory structure
* - It is not possible to create new empty block as it would be too small, only `4` bytes available, minimum is `8` bytes
* - It is not possible to enlarge next empty block as current and next empty do not create contiguous block
* - Block is internally left unchanged
* - Reallocating block second time to `8` bytes was successful
* - Difference between old and new size is `8` bytes which is enough for new empty block.
* Its size is `8` bytes, effectively `0` for user data
*
* \par Summary for reallocation to smaller size
*
* When reallocating already allocated memory block, one of `3` cases will happen:
*
* - Case `1`: When current block and next free block could create contigouos block of memory,
* current block is decreased (size parameter) and next free is enlarged by the size difference
* - Case `2`: When difference between current size and new size is more or equal to minimal size for new empty block,
* new empty block is created with size `current_size - new_size` and added to list of free blocks
* - Case `3`: When difference between current size and new size is less than minimal size for new empty block,
* block is left unchanged
*
* \subsection sect_realloc_enlarging Enlarging existing block
*
* Things get more tricky when we need to enlarge existing block.
* Since we are increasing block size, we cannot just anticipate memory after already allocated block is free.
* We need to take some actions and optimize reallocation procedure.
*
* Possible memory structure cases are explained below.
*
* \note Size numbers represent block size, including meta size.
* Number `32` represents `24` user bytes and `8` metadata bytes.
*
* \par Free block before allocated [block] create one big contiguous block
*
* \image html structure_realloc_enlarge_1.svg Case 1: Free block before allocated [block] create one big contiguous block
*
* This is the simplest way to show how reallocation works. Let's start by code and output:
*
* \include example_realloc_enlarge_1.c
*
* When executed, it prints (test machine)
*
* \include example_realloc_enlarge_1_log.c
*
* Looking at the debug output and image above:
*
* - Allocation for first block of memory (`24` user bytes) uses `32` bytes of data
* - Reallocation is successful, block has been extended to `40` bytes and next free shrinked down to `80` bytes
*
* \par Free block after allocated [block] create one big contiguous block
*
* \image html structure_realloc_enlarge_2.svg Case 2: Free block after allocated [block] create one big contiguous block
*
* Second case is a block with free block as previous.
* As you can see on image, it is possible to reallocate existing block by moving it to the left.
* Example code which would effectively produce this:
*
* \include example_realloc_enlarge_2.c
*
* When executed, it prints (test machine)
*
* \include example_realloc_enlarge_2_log.c
*
* Looking at the debug output and image above:
*
* - First we allocate big block (`88` bytes), followed by smaller block (`32` bytes)
* - We then free big block to mark it as free. This is effectively state `2a`
* - During reallocation, manager did not find suitable block after, but did find suitable block before current one:
* - Empty block and allocated block are temporary merged to one big block (`120` bytes)
* - Content of allocated block is shifted up to beginning of big block
* - Big block is later splitted to required size, the rest is marked as free
* - This is effectively state `2b`
*
* \par Free block before and after allocated [block] create one big contiguous block
*
* \image html structure_realloc_enlarge_3.svg Case 2: Free block before and after allocated [block] create one big contiguous block
*
* In this example we always have `2` allocated blocks and we want to reallocate `green` block.
* `Red` block is there acting as an obstacle to show different application use cases.
*
* Image shows `4` optional cases. For every case, case labeled with `3` is initial state.
*
* \note Case labelled with `3` is initial state for any of `3a - 3d` cases
*
* Before moving to the description of the cases, let's make initial state with C code example
*
* \include example_realloc_enlarge_3.c
*
* When executed, it prints (test machine)
*
* \include example_realloc_enlarge_3_log.c
*
* As seen on the image (and confirmed in log), there are `3` free slots of `16, 12 and 56` bytes respectively.
*
* Cases:
* - Case `3a`: Application tries to reallocate green block from `12` to `16` bytes
* - Reallocation is successful, there is a free block just after and green block is successfully enlarged
* - Block after is shrinked from `12` to `8` bytes
* - Code example (follows initial state code example)
* \include example_realloc_enlarge_3a.c
* - When executed, it prints (test machine)
* \include example_realloc_enlarge_3a_log.c
* - Case `3b`: Application tries to reallocate green block from `12` to `28` bytes
* - Block after green is not big enough to merge them to one block (`12 + 12 < 28`)
* - Block before green is big enough (`16 + 12 >= 28`)
* - Green block is merged with previous free block and content is shifted to the beginning of new block
* - Code example (follows initial state code example)
* \include example_realloc_enlarge_3b.c
* - When executed, it prints (test machine)
* \include example_realloc_enlarge_3b_log.c
* - Case `3c`: Application tries to reallocate green block from `12` to `32` bytes
* - Block after green is not big enough to merge them to one block (`12 + 12 < 32`)
* - Block before green is also not big enough (`12 + 16 < 32`)
* - All three blocks together are big enough (`16 + 12 + 12 >= 32`)
* - All blocks are effectively merged together and there is a new temporary block with its size set to `40` bytes
* - Content of green block is shifted to the beginning of new block
* - New block is limited to `32` bytes, keeping `8` bytes marked as free at the end
* - Code example (follows initial state code example)
* \include example_realloc_enlarge_3c.c
* - When executed, it prints (test machine)
* \include example_realloc_enlarge_3c_log.c
* - Case `3d`: Application tries to reallocate green block from `12` to `44` bytes
* - None of the methods (`3a - 3c`) are available as blocks are too small
* - Completely new block is created and content is copied to it
* - Existing block is marked as free. Since all `3` free blocks create big contiguous block,
* we can merge them to one block with its size set to `40`
* - Code example (follows initial state code example)
* \include example_realloc_enlarge_3d.c
* - When executed, it prints (test machine)
* \include example_realloc_enlarge_3d_log.c
*
* \par Full code example with new debug output
*
* Advanced debugging features has been added for development purposes.
* It is now possible to simulate different cases within single executable,
* by storing states to different memories.
*
* Example has been implemented which runs on WIN32 and
* relies on dynamic allocation using `malloc` standard C function,
* to prepare blocks of memory later used by lwmem
*
* How it works:
* - Code prepares state `3` and saves memory to temporary memory for future restore
* - Code restores latest saved state (case `3`) and executes case `3a`
* - Code restores latest saved state (case `3`) and executes case `3b`
* - Code restores latest saved state (case `3`) and executes case `3c`
* - Code restores latest saved state (case `3`) and executes case `3d`
*
* Full code example
* \include example_realloc_enlarge_full.c
*
* When executed, it prints (test machine)
* \include example_realloc_enlarge_full_log.c
*
* \section sect_thread_safety Concurrent access & thread safety
*
* Many embedded applications run operating system and this is where thread safety is important.
* LwMEM by default uses single resource for all allocations, meaning that during memory operation (allocation, freeing)
* different threads MUST NEVER interrupt current running thread, or memory structure (and system) may collapse.
*
* \note Same concern applies when allocating/freeing memory from main thread and interrupt context,
* when not using operating system. It is advised NOT to do any LwMEM operation in interrupt context
* or memory structure (and system) may collapse.
*
* When using LwMEM in operating system environment, it is possible to use it with system protection functions.
* One more layer of functions needs to be implemented.
*
* Function description which needs to be implemented and added to project are available in \ref LWMEM_SYS section.
* Example codes are available in official git repository under `system` folder.
*
*/

View File

@ -1,10 +0,0 @@
/**
* \addtogroup LWMEM_CONFIG
* \{
*
* List of all possible library configuration settings.
*
* Please refer to \ref sect_config for more information how to setup custom config.
*
* \}
*/

View File

@ -1,13 +0,0 @@
/**
* \addtogroup LWMEM_SYS
* \{
*
* System functions, required when operating system mode is enabled.
*
* \par Example for CMSIS OS
*
* \include _lwmem_sys.c
*
* \}
*
*/

View File

@ -1,56 +0,0 @@
/**
* \mainpage
* \tableofcontents
*
* LwMEM is a dynamic memory manager which implements standard C allocation functions (`malloc`, `realloc`, `calloc`, `free`) and is platform independant.
*
* \section sect_features Features
*
* - Written in ANSI C99, 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 free block
* - Supports different memory regions to allow use of fragmented memories
* - Suitable for embedded applications with fragmented memories
* - Suitable for automotive applications
* - Supports advanced free/realloc algorithms to optimize memory usage
* - Operating system ready, thread-safe API
* - User friendly MIT license
*
* \section sect_resources Download & Resources
*
* - <a class="download_url" href="https://github.com/MaJerle/lwmem/releases">Download library at Github releases</a>
* - <a href="https://github.com/MaJerle/lwmem">Resources and examples repository</a>
* - Read \ref page_appnote before you start development
* - <a href="https://github.com/MaJerle/lwmem">Official development repository on Github</a>
*
* \section sect_contribute How to contribute
*
* - Official development repository is hosted on Github
* - <a href="https://github.com/MaJerle/c_code_style">Respect C style and coding rules</a>
*
* \section sect_license License
*
* \verbatim
* Copyright (c) 2019 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 in the Software without restriction,
* including without limitation the rights to use, copy, modify, merge,
* publish, distribute, sublicense, and/or sell copies of the Software,
* and to permit persons to whom the Software is furnished to do so,
* subject to the following conditions:
*
* The above copyright notice and this permission notice shall be
* included in all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
* OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE
* AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
* HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
* OTHER DEALINGS IN THE SOFTWARE. \endverbatim
*
*/

3
docs/static/css/common.css vendored Normal file
View File

@ -0,0 +1,3 @@
.center {
text-align: center;
}

0
docs/static/css/custom.css vendored Normal file
View File

BIN
docs/static/images/logo_tm.png vendored Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.3 KiB

BIN
docs/static/images/logo_tm_full.png vendored Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 17 KiB

View File

Before

Width:  |  Height:  |  Size: 124 KiB

After

Width:  |  Height:  |  Size: 124 KiB

View File

Before

Width:  |  Height:  |  Size: 27 KiB

After

Width:  |  Height:  |  Size: 27 KiB

View File

Before

Width:  |  Height:  |  Size: 29 KiB

After

Width:  |  Height:  |  Size: 29 KiB

View File

Before

Width:  |  Height:  |  Size: 28 KiB

After

Width:  |  Height:  |  Size: 28 KiB

View File

Before

Width:  |  Height:  |  Size: 28 KiB

After

Width:  |  Height:  |  Size: 28 KiB

View File

Before

Width:  |  Height:  |  Size: 101 KiB

After

Width:  |  Height:  |  Size: 101 KiB

View File

Before

Width:  |  Height:  |  Size: 28 KiB

After

Width:  |  Height:  |  Size: 28 KiB

View File

Before

Width:  |  Height:  |  Size: 57 KiB

After

Width:  |  Height:  |  Size: 57 KiB

View File

@ -0,0 +1,100 @@
.. _how_it_works:
How it works
============
This section shows different buffer corner cases and provides basic understanding how memory allocation works within firmware.
As it is already known, library supports multiple memory regions (or addresses) to allow multiple memory locations within embedded systems:
* Internal RAM memory
* External RAM memory
* Optional fragmented internal memory
For the sake of this understanding, application is using ``3`` regions
* Region ``1`` memory starts at ``0x1000 0000`` and is ``0x0000 1000`` bytes long
* Region ``2`` memory starts at ``0xA000 0000`` and is ``0x0000 8000`` bytes long
* Region ``3`` memory starts at ``0xC000 0000`` and is ``0x0000 8000`` bytes long
.. note::
Total size of memory used by application for memory manager is ``0x0001 1000`` bytes or ``69 kB``.
This is a sum of all ``3`` regions.
Example also assumes that:
* Size of any kind of pointer is ``4-bytes``, ``sizeof(any_pointer_type) = 4``
* Size of ``size_t`` type is ``4-bytes``, ``sizeof(size_t) = 4``
First step is to define custom regions and assign them to memory manager.
.. literalinclude:: ../examples/example_regions_definitions.c
:language: c
.. note::
Order of regions must be lower address first. Regions must not overlap with their sizes.
When calling ``lwmem_assignmem``, manager prepares memory blocks and assigns default values.
.. figure:: ../static/images/structure_default.svg
:align: center
:alt: Default memory structure after initialization
Default memory structure after initialization
Memory managers sets some default values, these are:
* All regions are connected through single linked list. Each member of linked list represents free memory slot
* Variable ``Start block`` is by default included in library and points to first free memory on the list
* Each region has ``2 free slot`` indicators
* One at the end of each region. It takes ``8 bytes`` of memory:
* Size of slot is set to ``0`` which `means no available memory`
* Its next value points to next free slot in another region. Set to ``NULL`` if there is no free slot available anymore after and is *last region* indicator
* One at the beginning of region. It also takes ``8 bytes`` of memory:
* Size of slot is set to ``region_size - 8``, ignoring size of last slot. Effective size of memory, application may allocate in region, is always for ``2`` meta slots less than region size, which means ``max_app_malloc_size = region_size - 2 - 8 bytes``
* Its next value points to end slot in the same region
When application tries to allocate piece of memory, library will check linked list of empty blocks until it finds first with sufficient size. If there is a block bigger than requested size, it will be marked as allocated and removed from linked list.
.. note::
Further optimizations are implemented, such as possibility to split block when requested size is smaller than empty block size is.
.. figure:: ../static/images/structure_first_alloc.svg
:align: center
:alt: Memory structure after first allocation
Memory structure after first allocation
* Light red background slot indicates memory in use.
* All blocks marked in use have
* ``next`` value is set to ``NULL``
* ``size`` value has MSB bit set to ``1``, indicating block *is allocated* and the rest of bits represent size of block, including metadata size
* If application asks for 8 bytes, fields are written as ``next = 0x0000 0000`` and ``size = 0x8000 000F``
* ``Start block`` now points to free slot somewhere in the middle of region
.. figure:: ../static/images/structure_alloc_free_steps.svg
:align: center
:alt: Step-by-step memory structure after multiple allocations and deallocations
Step-by-step memory structure after multiple allocations and deallocations
Image shows only first region to simplify process. Same procedure applies to other regions too.
* ``Case A``: Second block allocated. Remaining memory is now smaller and ``Start block points`` to it
* ``Case B``: Third block allocated. Remaining memory is now smaller and ``Start block points`` to it
* ``Case C``: Forth block allocated. Remaining memory is now smaller and ``Start block points`` to it
* ``Case D``: Third block freed and added back to linked list of free slots.
* ``Case E``: Forth block freed. Manager detects blocks before and after current are free and merges all to one big contiguous block
* ``Case F``: First block freed. ``Start block`` points to it as it has been added back to linked list
* ``Case G``: Second block freed. Manager detects blocks before and after current are free and merges all to one big contiguous block.
* No any memory allocated anymore, regions are back to default state
.. toctree::
:maxdepth: 2

View File

@ -0,0 +1,11 @@
.. _user_manual:
User manual
===========
.. toctree::
:maxdepth: 2
how-it-works
realloc-algorithm
thread-safety

View File

@ -0,0 +1,323 @@
.. _realloc_algorithm:
Reallocation algorithm
======================
What makes this library different to others is its ability for memory re-allocation.
This section explains how it works and how it achieves best performances and less memory fragmentation vs others.
Sometimes application uses variable length of memory,
especially when number of (as an example) elements in not fully known in advance.
For the sake of this example, application anticipates ``12`` numbers (`integers`) but may (due to unknown reason in some cases) receive more than this.
If application needs to hold all received numbers, it may be necessary to:
* Option ``1``: Increase memory block size using reallocations
* Option ``2``: Use very big (do we know how big?) array, allocated statically or dynamically, which would hold all numbers at any time possible
.. note::
LwMEM has been optimized to handle well option ``1``.
Application needs to define at least single region:
.. literalinclude:: ../examples/example_realloc_region.c
:language: c
When executed on test machine, it prints:
.. literalinclude:: ../examples/example_realloc_region_log.c
.. note::
Please check :ref:`how_it_works` section for more information
After region has been defined, application tries to allocate memory for ``12 integers``.
.. literalinclude:: ../examples/example_realloc_first_malloc.c
:language: c
When executed on test machine, it prints:
.. literalinclude:: ../examples/example_realloc_first_malloc_log.c
At first, manager had ``120`` bytes of available memory while after allocation of ``48`` bytes, it only left ``64`` bytes.
Effectively ``120 - 64 = 56`` bytes have been used to allocate ``48`` bytes of memory.
.. note::
Every allocated block holds meta data. On test machine, ``sizeof(int) = 4`` therefore ``8`` bytes are used for metadata as ``56 - 12 * sizeof(int) = 8``. Size of meta data header depends on CPU architecture and may be different between architectures
Application got necessary memory for ``12`` integers. How to proceed when application needs to extend size for one more integer?
Easiest would be to:
#. Allocate new memory block with new size and check if allocation was successful
#. Manually copy content from old block to new block
#. Free old memory block
#. Use new block for all future operations
Here is the code:
.. literalinclude:: ../examples/example_realloc_custom_realloc.c
:language: c
When executed on test machine, it prints:
.. literalinclude:: ../examples/example_realloc_custom_realloc_log.c
Outcome of the debug messages:
#. Memory was successfully allocated for ``12`` integers, it took ``56`` bytes
#. Memory was successfully allocated for another ``13`` integers , it took ``64`` bytes
#. There is no more free memory available
#. First ``12`` integers array was successfully freed, manager has ``56`` bytes of free memory
#. Second ``13`` integers block was successfully freed, manager has all ``120`` bytes available for new allocations
This was therefore successful custom reallocation from ``12`` to ``13`` integers.
Next step is to verify what would happen when application wants to reallocate to ``15`` integers instead.
When same code is executed (but with ``15`` instead of ``12``), it prints:
.. literalinclude:: ../examples/example_realloc_custom_realloc_log_2.c
Oooops! It is not anymore possible to allocate new block for new ``15`` integers as there was no available block with at least ``15 * sizeof(int) + metadata_size`` bytes of free memory.
.. note::
With this reallocation approach, maximal size of application block is only ``50%`` of region size. This is not the most effective memory manager!
Fortunately there is a solution. Every time application wants to resize existing block, manager tries to manipulate existing block and shrink or expand it.
Shrink existing block
^^^^^^^^^^^^^^^^^^^^^
Easiest reallocation algorithm is when application wants to decrease size of previously allocated memory.
When this is the case, manager only needs to change the size of existing block to lower value.
.. literalinclude:: ../examples/example_realloc_shrink.c
:language: c
When executed on test machine, it prints:
.. literalinclude:: ../examples/example_realloc_shrink_log.c
Outcome of our reallocation:
* Memory was successfully allocated for ``15`` integers, it took ``68`` bytes; part ``A`` on image
* Memory was successfully re-allocated to ``12`` integers, now it takes ``56`` bytes, part ``B`` on image
* In both cases on image, final returned memory points to the same address
* Manager does not need to copy data from existing memory to new address as it is the same memory used in both cases
* Empty block start address has been modified and its size has been increased, part ``B`` on image
* Reallocated block was successfully freed, manager has all ``120`` bytes for new allocations
.. tip::
This was a success now, much better.
However, it is not always possible to increase block size of next free block on linked list.
Consider new example and dedicated image below.
.. figure:: ../static/images/structure_realloc_shrink_fragmented.svg
:align: center
:alt: Shrinking fragmented memory block
Shrinking fragmented memory block
.. literalinclude:: ../examples/example_realloc_shrink_fragmented.c
:language: c
When executed on test machine, it prints:
.. literalinclude:: ../examples/example_realloc_shrink_fragmented_log.c
Outcome of this example:
* Size of all ``4`` blocks is ``24`` bytes; ``16`` for user data, ``8`` for metadata
* Reallocating block first time from ``16`` to ``12`` user data bytes did not affect internal memory structure
* It is not possible to create new empty block as it would be too small, only ``4`` bytes available, minimum is ``8`` bytes for meta data
* It is not possible to enlarge next empty block due to *current* and *next empty* do not create contiguous block
* Block is internally left unchanged
* Reallocating block second time to ``8`` bytes was a success
* Difference between old and new size is ``8`` bytes which is enough for new empty block
* Its size is ``8`` bytes, effectively ``0`` for user data due to meta size
Shrink existing block - summary
*******************************
When reallocating already allocated memory block, one of `3` cases will happen:
* Case ``1``: When *current* block and *next free* block could create contigouos block of memory, *current* block is decreased (size parameter) and *next free* is enlarged by the size difference
* Case ``2``: When difference between *current* size and *new* size is more or equal to minimal size for new empty block, new empty block is created with size ``current_size - new_size`` and added to list of free blocks
* Case ``3``: When difference between *current* size and *new* size is less than minimal size for new empty block, block is left unchanged
Enlarge existing block
^^^^^^^^^^^^^^^^^^^^^^
Now that you master procedure to shrink (or decrease) size of existing allocated memory block, it is time to understand how to enlarge it.
Things here are more complicated, however, they are still easy to understand.
Manager covers ``3`` potential cases:
* Case ``1``: Increase size of currently allocated block
* Case ``2``: Merge previous empty block with existing one and shift data up
* Case ``3``: Block before and after existing block together create contiguous block of memory
*Free block* after + *allocated block* create one big contiguous block
**********************************************************************
.. figure:: ../static/images/structure_realloc_enlarge_1.svg
:align: center
:alt: *Free block* after + *allocated block* create one big contiguous block
*Free block* after + *allocated block* create one big contiguous block
.. literalinclude:: ../examples/example_realloc_enlarge_1.c
:language: c
When executed on test machine, it prints:
.. literalinclude:: ../examples/example_realloc_enlarge_1_log.c
* Allocation for first block of memory (``24`` user bytes) uses ``32`` bytes of data
* Reallocation is successful, block has been extended to ``40`` bytes and next free block has been shrinked down to ``80`` bytes
*Free block* before + *allocated block* create one big contiguous block
***********************************************************************
.. figure:: ../static/images/structure_realloc_enlarge_2.svg
:align: center
:alt: *Free block* before + *allocated block* create one big contiguous block
*Free block* before + *allocated block* create one big contiguous block
.. literalinclude:: ../examples/example_realloc_enlarge_2.c
:language: c
When executed on test machine, it prints:
.. literalinclude:: ../examples/example_realloc_enlarge_2_log.c
* First application allocates big block (``88`` bytes), followed by smaller block (``32`` bytes)
* Application then frees big block to mark it as free. This is effectively state ``2a``
* During reallocation, manager did not find suitable block after *current* block, but it found suitable block before *current* block:
* Empty block and allocated block are temporary merged to one big block (``120`` bytes)
* Content of allocated block is shifted up to beginning of new big block
* Big block is then splitted to required size, the rest is marked as free
* This is effectively state ``2b``
*Free block* before + *free block* after + *allocated block* create one big contiguous block
********************************************************************************************
When application makes many allocations and frees of memory, there is a high risk of memory fragmentations.
Essentially small chunks of allocated memory prevent manager to allocate new, fresh, big block of memory.
When it comes to reallocating of existing block, it may happen that *first free block after* and *current block* create a contiguous block, but its combined size is not big enough. Same could happen with *last block before* + *current block*. However, it may be possible to combine *free block before* + *current block* + *free block after* current block together.
.. figure:: ../static/images/structure_realloc_enlarge_3.svg
:align: center
:alt: *Free block* before + *free block* after + *allocated block* create one big contiguous block
*Free block* before + *free block* after + *allocated block* create one big contiguous block
In this example manager has always ``2`` allocated blocks and application always wants to reallocate ``green`` block.
``Red`` block is acting as an obstacle to show different application use cases.
.. note::
Image shows ``4`` use cases. For each of them, case labeled with ``3`` is initial state.
Initial state ``3`` is generated using C code:
.. literalinclude:: ../examples/example_realloc_enlarge_3.c
:language: c
When executed on test machine, it prints:
.. literalinclude:: ../examples/example_realloc_enlarge_3_log.c
.. tip::
Image shows (and log confirms) ``3`` free slots of ``16, 12 and 56`` bytes in size respectively.
* Case ``3a``: Application tries to reallocate green block from ``12`` to ``16`` bytes
* Reallocation is successful, there is a free block just after and green block is successfully enlarged
* Block after is shrinked from ``12`` to ``8`` bytes
* Code example (follows initial state code example)
.. literalinclude:: ../examples/example_realloc_enlarge_3a.c
:language: c
* When executed on test machine, it prints:
.. literalinclude:: ../examples/example_realloc_enlarge_3a_log.c
* Case ``3b``: Application tries to reallocate green block from ``12`` to ``28`` bytes
* Block after green is not big enough to merge them to one block (``12 + 12 < 28``)
* Block before green is big enough (``16 + 12 >= 28``)
* Green block is merged with previous free block and content is shifted to the beginning of new block
.. literalinclude:: ../examples/example_realloc_enlarge_3b.c
:language: c
- When executed on test machine, it prints:
.. literalinclude:: ../examples/example_realloc_enlarge_3b_log.c
* Case ``3c``: Application tries to reallocate green block from ``12`` to ``32`` bytes
* Block after green is not big enough to merge them to one block (``12 + 12 < 32``)
* Block before green is also not big enough (``12 + 16 < 32``)
* All three blocks together are big enough (``16 + 12 + 12 >= 32``)
* All blocks are effectively merged together and there is a new temporary block with its size set to ``40`` bytes
* Content of green block is shifted to the beginning of new block
* New block is limited to ``32`` bytes, keeping ``8`` bytes marked as free at the end
.. literalinclude:: ../examples/example_realloc_enlarge_3c.c
:language: c
* When executed on test machine, it prints:
.. literalinclude:: ../examples/example_realloc_enlarge_3c_log.c
* Case ``3d``: Application tries to reallocate green block from ``12`` to ``44`` bytes
* None of the methods (``3a - 3c``) are available as blocks are too small
* Completely new block is created and content is copied to it
* Existing block is marked as free. All ``3`` free blocks create big contiguous block, they are merged to one block with its size set to ``40``
.. literalinclude:: ../examples/example_realloc_enlarge_3d.c
:language: c
* When executed on test machine, it prints:
.. literalinclude:: ../examples/example_realloc_enlarge_3d_log.c
Full test code with assert
**************************
Advanced debugging features have been added for development purposes.
It is now possible to simulate different cases within single executable, by storing states to different memories.
Example has been implemented for WIN32 and relies on dynamic allocation using ``malloc`` standard C function for main block data preparation.
How it works:
* Code prepares state 3 and saves memory to temporary memory for future restore
* Code restores latest saved state (case ``3``) and executes case ``3a``
* Code restores latest saved state (case ``3``) and executes case ``3b``
* Code restores latest saved state (case ``3``) and executes case ``3c``
* Code restores latest saved state (case ``3``) and executes case ``3d``
Initial state ``3`` is generated using C code:
.. literalinclude:: ../examples/example_realloc_enlarge_full.c
:language: c
When executed on test machine, it prints:
.. literalinclude:: ../examples/example_realloc_enlarge_full_log.c
.. toctree::
:maxdepth: 2

View File

@ -0,0 +1,30 @@
.. _thread_safety:
Thread safety
=============
With default configuration, LwMEM library is *not* thread safe.
This means whenever it is used with operating system, user must resolve it with care.
Library has locking mechanism support for thread safety, which needs to be enabled.
.. tip::
To enable thread-safety support, parameter `LWMEM_CFG_OS` must be set to `1`.
Please check :ref:`api_lwmem_config` for more information about other options.
After thread-safety features has been enabled, it is necessary to implement
``4`` low-level system functions.
.. tip::
System function template example is available in ``lwmem/src/system/`` folder.
Example code for ``CMSIS-OS V2``
.. note::
Check :ref:`api_lwmem_sys` section for function description
.. literalinclude:: ../../lwmem/src/system/lwmem_sys_cmsis_os.c
:language: c
.. toctree::
:maxdepth: 2