diff options
author | Chenghan Zhou <chenghanzh@gmail.com> | 2020-06-18 15:42:06 -0400 |
---|---|---|
committer | CQ Bot Account <commit-bot@chromium.org> | 2020-07-17 18:14:27 +0000 |
commit | d4f44d2c50c16a3535c66b245427f02aeba2bd72 (patch) | |
tree | 5a905e06715100640cc0d7b4ef0ee58d236b764d | |
parent | 4b946c16a09b1d2cf1171d019591ffb2fedf213f (diff) | |
download | pigweed-d4f44d2c50c16a3535c66b245427f02aeba2bd72.tar.gz |
pw_allocator: replacing malloc()
Add pw_malloc module to replace libc malloc with self defined methods.
Add pw_malloc_freelist backend to provide wrapper functions for freelist
malloc.
Change-Id: I7b645206655068d6c08063d7a520aca62d955052
Reviewed-on: https://pigweed-review.googlesource.com/c/pigweed/pigweed/+/12601
Commit-Queue: Chenghan Zhou <chenghanzh@google.com>
Reviewed-by: Chenghan Zhou <chenghanzh@google.com>
Reviewed-by: Alexei Frolov <frolv@google.com>
-rw-r--r-- | BUILD.gn | 1 | ||||
-rw-r--r-- | modules.gni | 2 | ||||
-rw-r--r-- | pw_allocator/BUILD.gn | 4 | ||||
-rw-r--r-- | pw_allocator/freelist_heap.cc | 9 | ||||
-rw-r--r-- | pw_allocator/public/pw_allocator/freelist_heap.h | 12 | ||||
-rw-r--r-- | pw_malloc/BUILD | 50 | ||||
-rw-r--r-- | pw_malloc/BUILD.gn | 54 | ||||
-rw-r--r-- | pw_malloc/backend.gni | 18 | ||||
-rw-r--r-- | pw_malloc/docs.rst | 31 | ||||
-rw-r--r-- | pw_malloc/public/pw_malloc/malloc.h | 22 | ||||
-rw-r--r-- | pw_malloc_freelist/BUILD | 60 | ||||
-rw-r--r-- | pw_malloc_freelist/BUILD.gn | 55 | ||||
-rw-r--r-- | pw_malloc_freelist/docs.rst | 21 | ||||
-rw-r--r-- | pw_malloc_freelist/freelist_malloc.cc | 82 | ||||
-rw-r--r-- | pw_malloc_freelist/freelist_malloc_test.cc | 64 | ||||
-rw-r--r-- | pw_malloc_freelist/public/pw_malloc_freelist/freelist_malloc.h | 20 | ||||
-rw-r--r-- | pw_sys_io_baremetal_stm32f429/BUILD.gn | 9 | ||||
-rw-r--r-- | pw_sys_io_baremetal_stm32f429/early_boot.c | 7 | ||||
-rw-r--r-- | targets/stm32f429i-disc1/stm32f429i_executable.gni | 7 | ||||
-rw-r--r-- | targets/stm32f429i-disc1/target_toolchains.gni | 7 |
20 files changed, 529 insertions, 6 deletions
@@ -172,6 +172,7 @@ if (current_toolchain != default_toolchain) { "$dir_pw_fuzzer:tests", "$dir_pw_log:tests", "$dir_pw_log_tokenized:tests", + "$dir_pw_malloc_freelist:tests", "$dir_pw_polyfill:tests", "$dir_pw_preprocessor:tests", "$dir_pw_protobuf:tests", diff --git a/modules.gni b/modules.gni index 41e07316e..378ef6dd3 100644 --- a/modules.gni +++ b/modules.gni @@ -38,6 +38,8 @@ declare_args() { dir_pw_log = get_path_info("pw_log", "abspath") dir_pw_log_basic = get_path_info("pw_log_basic", "abspath") dir_pw_log_tokenized = get_path_info("pw_log_tokenized", "abspath") + dir_pw_malloc = get_path_info("pw_malloc", "abspath") + dir_pw_malloc_freelist = get_path_info("pw_malloc_freelist", "abspath") dir_pw_minimal_cpp_stdlib = get_path_info("pw_minimal_cpp_stdlib", "abspath") dir_pw_module = get_path_info("pw_module", "abspath") dir_pw_fuzzer = get_path_info("pw_fuzzer", "abspath") diff --git a/pw_allocator/BUILD.gn b/pw_allocator/BUILD.gn index 93b274ebe..529a6a5d3 100644 --- a/pw_allocator/BUILD.gn +++ b/pw_allocator/BUILD.gn @@ -23,7 +23,7 @@ config("default_config") { } group("pw_allocator") { - deps = [ + public_deps = [ ":block", ":freelist", ":freelist_heap", @@ -44,7 +44,7 @@ pw_source_set("freelist") { public_configs = [ ":default_config" ] public = [ "public/pw_allocator/freelist.h" ] public_deps = [ - "$dir_pw_containers", + "$dir_pw_containers:vector", "$dir_pw_span", "$dir_pw_status", ] diff --git a/pw_allocator/freelist_heap.cc b/pw_allocator/freelist_heap.cc index dfaba56bb..14f850dcc 100644 --- a/pw_allocator/freelist_heap.cc +++ b/pw_allocator/freelist_heap.cc @@ -19,7 +19,7 @@ namespace pw::allocator { FreeListHeap::FreeListHeap(std::span<std::byte> region, FreeList& freelist) - : freelist_(freelist) { + : freelist_(freelist), heap_stats_() { Block* block; Block::Init(region, &block); @@ -30,6 +30,7 @@ FreeListHeap::FreeListHeap(std::span<std::byte> region, FreeList& freelist) void* FreeListHeap::Allocate(size_t size) { // Find a chunk in the freelist. Split it if needed, then return + auto chunk = freelist_.FindChunk(size); if (chunk.data() == nullptr) { @@ -47,7 +48,8 @@ void* FreeListHeap::Allocate(size_t size) { } chunk_block->MarkUsed(); - + heap_stats_.bytes_allocated += size; + heap_stats_.cumulative_allocated += size; return chunk_block->UsableSpace(); } @@ -59,6 +61,7 @@ void FreeListHeap::Free(void* ptr) { } Block* chunk_block = Block::FromUsableSpace(bytes); + size_t size_freed = chunk_block->InnerSize(); // Ensure that the block is in-use if (!chunk_block->Used()) { return; @@ -87,6 +90,8 @@ void FreeListHeap::Free(void* ptr) { } // Add back to the freelist freelist_.AddChunk(BlockToSpan(chunk_block)); + heap_stats_.bytes_allocated -= size_freed; + heap_stats_.cumulative_freed += size_freed; } // Follows constract of the C standard realloc() function diff --git a/pw_allocator/public/pw_allocator/freelist_heap.h b/pw_allocator/public/pw_allocator/freelist_heap.h index cf44ffd47..73ff9d03b 100644 --- a/pw_allocator/public/pw_allocator/freelist_heap.h +++ b/pw_allocator/public/pw_allocator/freelist_heap.h @@ -24,6 +24,13 @@ namespace pw::allocator { class FreeListHeap { public: + template <size_t N> + friend class FreeListHeapBuffer; + struct HeapStats { + size_t bytes_allocated; + size_t cumulative_allocated; + size_t cumulative_freed; + }; FreeListHeap(std::span<std::byte> region, FreeList& freelist); void* Allocate(size_t size); @@ -38,6 +45,7 @@ class FreeListHeap { std::span<std::byte> region_; FreeList& freelist_; + HeapStats heap_stats_; }; template <size_t N = 6> @@ -54,6 +62,10 @@ class FreeListHeapBuffer { void* Realloc(void* ptr, size_t size) { return heap_.Realloc(ptr, size); } void* Calloc(size_t num, size_t size) { return heap_.Calloc(num, size); } + const FreeListHeap::HeapStats& heap_stats() const { + return heap_.heap_stats_; + }; + private: FreeListBuffer<N> freelist_; FreeListHeap heap_; diff --git a/pw_malloc/BUILD b/pw_malloc/BUILD new file mode 100644 index 000000000..f3ab4f3f5 --- /dev/null +++ b/pw_malloc/BUILD @@ -0,0 +1,50 @@ +# Copyright 2020 The Pigweed Authors +# +# Licensed under the Apache License, Version 2.0 (the "License"); you may not +# use this file except in compliance with the License. You may obtain a copy of +# the License at +# +# https://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT +# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the +# License for the specific language governing permissions and limitations under +# the License. + +load( + "//pw_build:pigweed.bzl", + "pw_cc_library", +) + +package(default_visibility = ["//visibility:public"]) + +licenses(["notice"]) # Apache License 2.0 +# TODO(pwbug/101): Need to add support for facades/backends to Bazel. +PW_MALLOC_BACKEND = "//pw_malloc_freelist" + +pw_cc_library( + name = "facade", + hdrs = [ + "public/pw_malloc/malloc.h", + ], + includes = ["public"], + deps = [ + PW_MALLOC_BACKEND + ":headers", + ], +) + +pw_cc_library( + name = "pw_malloc", + deps = [ + ":facade", + PW_MALLOC_BACKEND + ":headers", + ], +) + +pw_cc_library( + name = "backend", + deps = [ + PW_MALLOC_BACKEND, + ], +) diff --git a/pw_malloc/BUILD.gn b/pw_malloc/BUILD.gn new file mode 100644 index 000000000..f56a0fe97 --- /dev/null +++ b/pw_malloc/BUILD.gn @@ -0,0 +1,54 @@ +# Copyright 2020 The Pigweed Authors +# +# Licensed under the Apache License, Version 2.0 (the "License"); you may not +# use this file except in compliance with the License. You may obtain a copy of +# the License at +# +# https://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT +# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the +# License for the specific language governing permissions and limitations under +# the License. + +# gn-format disable +import("//build_overrides/pigweed.gni") + +import("$dir_pw_build/facade.gni") +import("$dir_pw_build/target_types.gni") +import("$dir_pw_docgen/docs.gni") +import("$dir_pw_malloc/backend.gni") +import("$dir_pw_unit_test/test.gni") +config("default_config") { + include_dirs = [ "public" ] +} + +config("pw_malloc_wrapper_config") { + # Link options that provides replace dynamic memory operations in standard + # library with the pigweed malloc. + ldflags = [ + # memory allocation -- these must be re-entrant and do locking + "-Wl,--wrap=malloc", + "-Wl,--wrap=free", + "-Wl,--wrap=realloc", + "-Wl,--wrap=calloc", + + # Wrap these in case internal newlib call them (e.g. strdup will) + # directly call _malloc_r) + "-Wl,--wrap=_malloc_r", + "-Wl,--wrap=_realloc_r", + "-Wl,--wrap=_free_r", + "-Wl,--wrap=_calloc_r", + ] +} + +pw_facade("pw_malloc") { + public_configs = [ ":default_config" ] + public = [ "public/pw_malloc/malloc.h" ] + backend = pw_malloc_BACKEND +} + +pw_doc_group("docs") { + sources = [ "docs.rst" ] +} diff --git a/pw_malloc/backend.gni b/pw_malloc/backend.gni new file mode 100644 index 000000000..e0d62a0b9 --- /dev/null +++ b/pw_malloc/backend.gni @@ -0,0 +1,18 @@ +# Copyright 2020 The Pigweed Authors +# +# Licensed under the Apache License, Version 2.0 (the "License"); you may not +# use this file except in compliance with the License. You may obtain a copy of +# the License at +# +# https://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT +# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the +# License for the specific language governing permissions and limitations under +# the License. + +declare_args() { + # Backends for the pw_malloc facade. + pw_malloc_BACKEND = "" +} diff --git a/pw_malloc/docs.rst b/pw_malloc/docs.rst new file mode 100644 index 000000000..7d552652c --- /dev/null +++ b/pw_malloc/docs.rst @@ -0,0 +1,31 @@ +.. _chapter-pw-malloc: + +.. default-domain:: cpp + +--------- +pw_malloc +--------- + +This module defines an interface for replacing the standard libc dynamic memory +operations. + +This facade doesn't implement any heap structure or dynamic memory methods. It +only requires that backends implements a ``void pw_MallocInit();`` method. +This function is called before static intialization, and is responsible for +initializing global data structures required by the malloc implementation. + +The intent of this module is to provide an interface for user-provided dynamic +memory operations that is compatible with different implementations. + +Setup +===== +This module requires the following setup: + + 1. Chose a ``pw_malloc`` backend, or write one yourself. + 2. If using GN build, Specify the ``pw_sys_io_BACKEND`` GN build arg to point + the library that provides a ``pw_malloc`` backend. + +Module usage +============ +See backend docs for how to interact with the underlying dynamic memory +operations implementation. diff --git a/pw_malloc/public/pw_malloc/malloc.h b/pw_malloc/public/pw_malloc/malloc.h new file mode 100644 index 000000000..c5e1f42e9 --- /dev/null +++ b/pw_malloc/public/pw_malloc/malloc.h @@ -0,0 +1,22 @@ +// Copyright 2020 The Pigweed Authors +// +// Licensed under the Apache License, Version 2.0 (the "License"); you may not +// use this file except in compliance with the License. You may obtain a copy of +// the License at +// +// https://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, WITHOUT +// WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the +// License for the specific language governing permissions and limitations under +// the License. +#pragma once + +#if __cplusplus +extern "C" { +#endif +void pw_MallocInit(); +#if __cplusplus +} +#endif diff --git a/pw_malloc_freelist/BUILD b/pw_malloc_freelist/BUILD new file mode 100644 index 000000000..1efbb300f --- /dev/null +++ b/pw_malloc_freelist/BUILD @@ -0,0 +1,60 @@ +# Copyright 2020 The Pigweed Authors +# +# Licensed under the Apache License, Version 2.0 (the "License"); you may not +# use this file except in compliance with the License. You may obtain a copy of +# the License at +# +# https://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT +# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the +# License for the specific language governing permissions and limitations under +# the License. + +load( + "//pw_build:pigweed.bzl", + "pw_cc_library", + "pw_cc_test", +) + +package(default_visibility = ["//visibility:public"]) + +licenses(["notice"]) # Apache License 2.0 + +pw_cc_library( + name = "headers", + hdrs = [ + "public/pw_malloc_freelist/freelist_malloc.h", + ], + includes = [ + "public", + ], +) + +pw_cc_library( + name = "pw_malloc_freelist", + srcs = [ + "freelist_malloc.cc", + ], + deps = [ + ":headers", + "//dir_pw_allocator:block", + "//dir_pw_allocator:freelist_heap", + "//dir_pw_boot_armv7m", + "//dir_pw_malloc:facade", + "//dir_pw_preprocessor", + "//dir_pw_span", + ], +) + +pw_cc_test( + name = "freelist_malloctest", + srcs = [ + "freelist_malloc_test.cc", + ], + deps = [ + ":headers", + "//pw_unit_test", + ], +) diff --git a/pw_malloc_freelist/BUILD.gn b/pw_malloc_freelist/BUILD.gn new file mode 100644 index 000000000..2479f8b2c --- /dev/null +++ b/pw_malloc_freelist/BUILD.gn @@ -0,0 +1,55 @@ +# Copyright 2020 The Pigweed Authors +# +# Licensed under the Apache License, Version 2.0 (the "License"); you may not +# use this file except in compliance with the License. You may obtain a copy of +# the License at +# +# https://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT +# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the +# License for the specific language governing permissions and limitations under +# the License. + +# gn-format disable +import("//build_overrides/pigweed.gni") +import("$dir_pw_malloc/backend.gni") + +import("$dir_pw_build/target_types.gni") +import("$dir_pw_docgen/docs.gni") +import("$dir_pw_unit_test/test.gni") +config("default_config") { + include_dirs = [ "public" ] +} + +pw_source_set("pw_malloc_freelist") { + public_configs = [ ":default_config" ] + public = [ "public/pw_malloc_freelist/freelist_malloc.h" ] + deps = [ + "$dir_pw_allocator:block", + "$dir_pw_allocator:freelist_heap", + "$dir_pw_boot_armv7m", + "$dir_pw_malloc:facade", + "$dir_pw_preprocessor", + "$dir_pw_span", + ] + sources = [ "freelist_malloc.cc" ] +} + +pw_test_group("tests") { + enable_if = pw_malloc_BACKEND == dir_pw_malloc_freelist + tests = [ ":freelist_malloc_test" ] +} + +pw_test("freelist_malloc_test") { + deps = [ + "$dir_pw_allocator", + "$dir_pw_malloc", + ] + sources = [ "freelist_malloc_test.cc" ] +} + +pw_doc_group("docs") { + sources = [ "docs.rst" ] +} diff --git a/pw_malloc_freelist/docs.rst b/pw_malloc_freelist/docs.rst new file mode 100644 index 000000000..928ac5b6f --- /dev/null +++ b/pw_malloc_freelist/docs.rst @@ -0,0 +1,21 @@ +.. _chapter-pw-malloc-freelist: + +.. default-domain:: cpp + +------------------ +pw_malloc_freelist +------------------ + +``pw_malloc_freelist`` implements the ``pw_malloc`` facade using a freelist +heap. + +``pw_malloc_freelist`` initializes a global ``FreeListHeapBuffer`` object to +organize heap usage. Implementation details are in the ``pw_allocator`` module. + +``pw_malloc_freelist`` provides wrapper functions for ``malloc``, ``free``, +``realloc`` and ``calloc`` that uses the freelist implementation of heap in +``pw_allocator``. In the GN build file, ``pw_malloc_freelist`` provides linker +options needed in ``public_configs``, which will be forwarded to the facade. In +the case of freelist, we specify the wrapper functions ``malloc, free, realloc, +calloc, _malloc_r, _free_r, _realloc_r, _calloc_r`` to replace the original libc +functions at linker time. diff --git a/pw_malloc_freelist/freelist_malloc.cc b/pw_malloc_freelist/freelist_malloc.cc new file mode 100644 index 000000000..b2285e5e4 --- /dev/null +++ b/pw_malloc_freelist/freelist_malloc.cc @@ -0,0 +1,82 @@ +// Copyright 2020 The Pigweed Authors +// +// Licensed under the Apache License, Version 2.0 (the "License"); you may not +// use this file except in compliance with the License. You may obtain a copy of +// the License at +// +// https://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, WITHOUT +// WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the +// License for the specific language governing permissions and limitations under +// the License. + +#include <span> + +#include "pw_allocator/freelist_heap.h" +#include "pw_boot_armv7m/boot.h" +#include "pw_malloc/malloc.h" +#include "pw_preprocessor/util.h" + +namespace { +std::aligned_storage_t<sizeof(pw::allocator::FreeListHeapBuffer<>), + alignof(pw::allocator::FreeListHeapBuffer<>)> + buf; +std::span<std::byte> pw_allocator_freelist_raw_heap; +} // namespace +pw::allocator::FreeListHeapBuffer<>* pw_freelist_heap; + +#if __cplusplus +extern "C" { +#endif +// Define the global heap variables. +void pw_MallocInit() { + // pw_heap_low_addr and pw_heap_high_addr specifies the heap region from + // the linker script in "pw_boot_armv7m". + std::span<std::byte> pw_allocator_freelist_raw_heap = + std::span(reinterpret_cast<std::byte*>(&pw_heap_low_addr), + &pw_heap_high_addr - &pw_heap_low_addr); + pw_freelist_heap = new (&buf) + pw::allocator::FreeListHeapBuffer(pw_allocator_freelist_raw_heap); +} + +// Wrapper functions for malloc, free, realloc and calloc. +// With linker options "-Wl --wrap=<function name>", linker will link +// "__wrap_<function name>" with "<function_name>", and calling +// "<function name>" will call "__wrap_<function name>" instead +// Linker options are set in a config in "pw_malloc:pw_malloc_config". +void* __wrap_malloc(size_t size) { return pw_freelist_heap->Allocate(size); } + +void __wrap_free(void* ptr) { pw_freelist_heap->Free(ptr); } + +void* __wrap_realloc(void* ptr, size_t size) { + return pw_freelist_heap->Realloc(ptr, size); +} + +void* __wrap_calloc(size_t num, size_t size) { + return pw_freelist_heap->Calloc(num, size); +} + +void* __wrap__malloc_r(struct _reent* r, size_t size) { + PW_UNUSED(r); + return pw_freelist_heap->Allocate(size); +} + +void __wrap__free_r(struct _reent* r, void* ptr) { + PW_UNUSED(r); + pw_freelist_heap->Free(ptr); +} + +void* __wrap__realloc_r(struct _reent* r, void* ptr, size_t size) { + PW_UNUSED(r); + return pw_freelist_heap->Realloc(ptr, size); +} + +void* __wrap__calloc_r(struct _reent* r, size_t num, size_t size) { + PW_UNUSED(r); + return pw_freelist_heap->Calloc(num, size); +} +#if __cplusplus +} +#endif diff --git a/pw_malloc_freelist/freelist_malloc_test.cc b/pw_malloc_freelist/freelist_malloc_test.cc new file mode 100644 index 000000000..1194230c0 --- /dev/null +++ b/pw_malloc_freelist/freelist_malloc_test.cc @@ -0,0 +1,64 @@ +// Copyright 2020 The Pigweed Authors +// +// Licensed under the Apache License, Version 2.0 (the "License"); you may not +// use this file except in compliance with the License. You may obtain a copy of +// the License at +// +// https://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, WITHOUT +// WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the +// License for the specific language governing permissions and limitations under +// the License. + +#include "pw_malloc_freelist/freelist_malloc.h" + +#include <span> + +#include "gtest/gtest.h" +#include "pw_allocator/freelist_heap.h" + +namespace pw::allocator { + +TEST(FreeListMalloc, ReplacingMalloc) { + constexpr size_t kAllocSize = 256; + constexpr size_t kReallocSize = 512; + constexpr size_t kCallocNum = 4; + constexpr size_t kCallocSize = 64; + constexpr size_t zero = 0; + + void* ptr1 = malloc(kAllocSize); + const FreeListHeap::HeapStats& freelist_heap_stats = + pw_freelist_heap->heap_stats(); + ASSERT_NE(ptr1, nullptr); + EXPECT_EQ(freelist_heap_stats.bytes_allocated, kAllocSize); + EXPECT_EQ(freelist_heap_stats.cumulative_allocated, kAllocSize); + EXPECT_EQ(freelist_heap_stats.cumulative_freed, zero); + void* ptr2 = realloc(ptr1, kReallocSize); + ASSERT_NE(ptr2, nullptr); + EXPECT_EQ(freelist_heap_stats.bytes_allocated, kReallocSize); + EXPECT_EQ(freelist_heap_stats.cumulative_allocated, + kAllocSize + kReallocSize); + EXPECT_EQ(freelist_heap_stats.cumulative_freed, kAllocSize); + void* ptr3 = calloc(kCallocNum, kCallocSize); + ASSERT_NE(ptr3, nullptr); + EXPECT_EQ(freelist_heap_stats.bytes_allocated, + kReallocSize + kCallocNum * kCallocSize); + EXPECT_EQ(freelist_heap_stats.cumulative_allocated, + kAllocSize + kReallocSize + kCallocNum * kCallocSize); + EXPECT_EQ(freelist_heap_stats.cumulative_freed, kAllocSize); + free(ptr2); + EXPECT_EQ(freelist_heap_stats.bytes_allocated, kCallocNum * kCallocSize); + EXPECT_EQ(freelist_heap_stats.cumulative_allocated, + kAllocSize + kReallocSize + kCallocNum * kCallocSize); + EXPECT_EQ(freelist_heap_stats.cumulative_freed, kAllocSize + kReallocSize); + free(ptr3); + EXPECT_EQ(freelist_heap_stats.bytes_allocated, zero); + EXPECT_EQ(freelist_heap_stats.cumulative_allocated, + kAllocSize + kReallocSize + kCallocNum * kCallocSize); + EXPECT_EQ(freelist_heap_stats.cumulative_freed, + kAllocSize + kReallocSize + kCallocNum * kCallocSize); +} + +} // namespace pw::allocator diff --git a/pw_malloc_freelist/public/pw_malloc_freelist/freelist_malloc.h b/pw_malloc_freelist/public/pw_malloc_freelist/freelist_malloc.h new file mode 100644 index 000000000..93599e9f6 --- /dev/null +++ b/pw_malloc_freelist/public/pw_malloc_freelist/freelist_malloc.h @@ -0,0 +1,20 @@ +// Copyright 2020 The Pigweed Authors +// +// Licensed under the Apache License, Version 2.0 (the "License"); you may not +// use this file except in compliance with the License. You may obtain a copy of +// the License at +// +// https://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, WITHOUT +// WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the +// License for the specific language governing permissions and limitations under +// the License. +#pragma once + +#include "pw_allocator/freelist_heap.h" +#include "pw_span/span.h" + +// Global variables to initialize a freelist heap. +extern pw::allocator::FreeListHeapBuffer<>* pw_freelist_heap; diff --git a/pw_sys_io_baremetal_stm32f429/BUILD.gn b/pw_sys_io_baremetal_stm32f429/BUILD.gn index cc232fca9..f4a652e40 100644 --- a/pw_sys_io_baremetal_stm32f429/BUILD.gn +++ b/pw_sys_io_baremetal_stm32f429/BUILD.gn @@ -17,9 +17,18 @@ import("//build_overrides/pigweed.gni") import("$dir_pw_build/target_types.gni") import("$dir_pw_docgen/docs.gni") +import("$dir_pw_malloc/backend.gni") +config("pw_malloc_active") { + if (pw_malloc_BACKEND != "") { + defines = [ "PW_MALLOC_ACTIVE=1" ] + } +} + pw_source_set("pw_sys_io_baremetal_stm32f429") { + configs = [ ":pw_malloc_active" ] public_deps = [ "$dir_pw_boot_armv7m" ] deps = [ + "$dir_pw_malloc", "$dir_pw_preprocessor", "$dir_pw_sys_io:default_putget_bytes", "$dir_pw_sys_io:facade", diff --git a/pw_sys_io_baremetal_stm32f429/early_boot.c b/pw_sys_io_baremetal_stm32f429/early_boot.c index afee255ea..e10a361e4 100644 --- a/pw_sys_io_baremetal_stm32f429/early_boot.c +++ b/pw_sys_io_baremetal_stm32f429/early_boot.c @@ -15,6 +15,7 @@ #include <inttypes.h> #include "pw_boot_armv7m/boot.h" +#include "pw_malloc/malloc.h" void pw_PreStaticConstructorInit() { // TODO(pwbug/17): Optionally enable Replace when Pigweed config system is @@ -29,4 +30,8 @@ void pw_PreStaticConstructorInit() { *arm_v7m_cpacr |= kFpuEnableMask; #endif // PW_ARMV7M_ENABLE_FPU -}
\ No newline at end of file + +#if PW_MALLOC_ACTIVE + pw_MallocInit(); +#endif // PW_MALLOC_ACTIVE +} diff --git a/targets/stm32f429i-disc1/stm32f429i_executable.gni b/targets/stm32f429i-disc1/stm32f429i_executable.gni index 160076115..5f336e2c3 100644 --- a/targets/stm32f429i-disc1/stm32f429i_executable.gni +++ b/targets/stm32f429i-disc1/stm32f429i_executable.gni @@ -14,6 +14,7 @@ # gn-format disable import("//build_overrides/pigweed.gni") +import("$dir_pw_malloc/backend.gni") # Executable wrapper that includes some baremetal startup code. template("stm32f429i_executable") { @@ -23,5 +24,11 @@ template("stm32f429i_executable") { deps = [] } deps += [ dir_pw_sys_io_baremetal_stm32f429 ] + if (pw_malloc_BACKEND != "") { + if (!defined(configs)) { + configs = [] + } + configs += [ "$dir_pw_malloc:pw_malloc_wrapper_config" ] + } } } diff --git a/targets/stm32f429i-disc1/target_toolchains.gni b/targets/stm32f429i-disc1/target_toolchains.gni index 70b1f6c5b..748be5ff6 100644 --- a/targets/stm32f429i-disc1/target_toolchains.gni +++ b/targets/stm32f429i-disc1/target_toolchains.gni @@ -48,11 +48,16 @@ _target_config = { pw_cpu_exception_SUPPORT_BACKEND = "$dir_pw_cpu_exception_armv7m:support" pw_log_BACKEND = dir_pw_log_basic pw_sys_io_BACKEND = dir_pw_sys_io_baremetal_stm32f429 + pw_malloc_BACKEND = dir_pw_malloc_freelist pw_boot_armv7m_LINK_CONFIG_DEFINES = [ "PW_BOOT_FLASH_BEGIN=0x08000200", "PW_BOOT_FLASH_SIZE=512K", - "PW_BOOT_HEAP_SIZE=0", + + # TODO(pwbug/219): Currently "pw_tokenizer/detokenize_test" requires at + # least 6K bytes in heap when using pw_malloc_freelist. The heap size + # required for tests should be investigated. + "PW_BOOT_HEAP_SIZE=6K", "PW_BOOT_MIN_STACK_SIZE=1K", "PW_BOOT_RAM_BEGIN=0x20000000", "PW_BOOT_RAM_SIZE=192K", |