Merge branch 'feature/sphinx' into develop
1
.gitignore
vendored
@ -23,6 +23,7 @@
|
|||||||
*.__i
|
*.__i
|
||||||
*.i
|
*.i
|
||||||
*.txt
|
*.txt
|
||||||
|
!docs/*.txt
|
||||||
RTE/
|
RTE/
|
||||||
|
|
||||||
# IAR Settings
|
# IAR Settings
|
||||||
|
20
docs/Makefile
Normal 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)
|
11
docs/api-reference/index.rst
Normal file
@ -0,0 +1,11 @@
|
|||||||
|
API reference
|
||||||
|
=============
|
||||||
|
|
||||||
|
List of all the modules:
|
||||||
|
|
||||||
|
.. toctree::
|
||||||
|
:maxdepth: 2
|
||||||
|
|
||||||
|
lwmem
|
||||||
|
lwmem_config
|
||||||
|
lwmem_sys
|
6
docs/api-reference/lwmem.rst
Normal file
@ -0,0 +1,6 @@
|
|||||||
|
.. _api_lwmem:
|
||||||
|
|
||||||
|
LwMEM
|
||||||
|
=====
|
||||||
|
|
||||||
|
.. doxygengroup:: LWMEM
|
6
docs/api-reference/lwmem_config.rst
Normal file
@ -0,0 +1,6 @@
|
|||||||
|
.. _api_lwmem_config:
|
||||||
|
|
||||||
|
LwMEM Configuration
|
||||||
|
===================
|
||||||
|
|
||||||
|
.. doxygengroup:: LWMEM_CONFIG
|
9
docs/api-reference/lwmem_sys.rst
Normal 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
@ -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
@ -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 */
|
|
@ -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 */
|
|
@ -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;
|
|
||||||
}
|
|
27
docs/examples/example_minimal.c
Normal 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);
|
69
docs/get-started/index.rst
Normal 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
@ -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
@ -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
@ -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
@ -0,0 +1,7 @@
|
|||||||
|
breathe>=4.9.1
|
||||||
|
colorama
|
||||||
|
docutils>=0.14
|
||||||
|
sphinx>=2.0.1
|
||||||
|
sphinx_rtd_theme
|
||||||
|
sphinx-tabs
|
||||||
|
sphinxcontrib-svg2pdfconverter
|
@ -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.
|
|
||||||
*
|
|
||||||
*/
|
|
@ -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.
|
|
||||||
*
|
|
||||||
* \}
|
|
||||||
*/
|
|
@ -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
|
|
||||||
*
|
|
||||||
* \}
|
|
||||||
*
|
|
||||||
*/
|
|
@ -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
@ -0,0 +1,3 @@
|
|||||||
|
.center {
|
||||||
|
text-align: center;
|
||||||
|
}
|
0
docs/static/css/custom.css
vendored
Normal file
BIN
docs/static/images/logo_tm.png
vendored
Normal file
After Width: | Height: | Size: 3.3 KiB |
BIN
docs/static/images/logo_tm_full.png
vendored
Normal file
After Width: | Height: | Size: 17 KiB |
Before Width: | Height: | Size: 124 KiB After Width: | Height: | Size: 124 KiB |
Before Width: | Height: | Size: 27 KiB After Width: | Height: | Size: 27 KiB |
Before Width: | Height: | Size: 29 KiB After Width: | Height: | Size: 29 KiB |
Before Width: | Height: | Size: 28 KiB After Width: | Height: | Size: 28 KiB |
Before Width: | Height: | Size: 28 KiB After Width: | Height: | Size: 28 KiB |
Before Width: | Height: | Size: 101 KiB After Width: | Height: | Size: 101 KiB |
Before Width: | Height: | Size: 28 KiB After Width: | Height: | Size: 28 KiB |
Before Width: | Height: | Size: 57 KiB After Width: | Height: | Size: 57 KiB |
100
docs/user-manual/how-it-works.rst
Normal 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
|
11
docs/user-manual/index.rst
Normal file
@ -0,0 +1,11 @@
|
|||||||
|
.. _user_manual:
|
||||||
|
|
||||||
|
User manual
|
||||||
|
===========
|
||||||
|
|
||||||
|
.. toctree::
|
||||||
|
:maxdepth: 2
|
||||||
|
|
||||||
|
how-it-works
|
||||||
|
realloc-algorithm
|
||||||
|
thread-safety
|
323
docs/user-manual/realloc-algorithm.rst
Normal 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
|
30
docs/user-manual/thread-safety.rst
Normal 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
|