aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorChenghan Zhou <chenghanzh@gmail.com>2020-06-18 15:42:06 -0400
committerCQ Bot Account <commit-bot@chromium.org>2020-07-17 18:14:27 +0000
commitd4f44d2c50c16a3535c66b245427f02aeba2bd72 (patch)
tree5a905e06715100640cc0d7b4ef0ee58d236b764d
parent4b946c16a09b1d2cf1171d019591ffb2fedf213f (diff)
downloadpigweed-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.gn1
-rw-r--r--modules.gni2
-rw-r--r--pw_allocator/BUILD.gn4
-rw-r--r--pw_allocator/freelist_heap.cc9
-rw-r--r--pw_allocator/public/pw_allocator/freelist_heap.h12
-rw-r--r--pw_malloc/BUILD50
-rw-r--r--pw_malloc/BUILD.gn54
-rw-r--r--pw_malloc/backend.gni18
-rw-r--r--pw_malloc/docs.rst31
-rw-r--r--pw_malloc/public/pw_malloc/malloc.h22
-rw-r--r--pw_malloc_freelist/BUILD60
-rw-r--r--pw_malloc_freelist/BUILD.gn55
-rw-r--r--pw_malloc_freelist/docs.rst21
-rw-r--r--pw_malloc_freelist/freelist_malloc.cc82
-rw-r--r--pw_malloc_freelist/freelist_malloc_test.cc64
-rw-r--r--pw_malloc_freelist/public/pw_malloc_freelist/freelist_malloc.h20
-rw-r--r--pw_sys_io_baremetal_stm32f429/BUILD.gn9
-rw-r--r--pw_sys_io_baremetal_stm32f429/early_boot.c7
-rw-r--r--targets/stm32f429i-disc1/stm32f429i_executable.gni7
-rw-r--r--targets/stm32f429i-disc1/target_toolchains.gni7
20 files changed, 529 insertions, 6 deletions
diff --git a/BUILD.gn b/BUILD.gn
index 30ba175fb..f4c55a995 100644
--- a/BUILD.gn
+++ b/BUILD.gn
@@ -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",