Skip to content

Commit

Permalink
✨ Add initial APIs for allocation & termination
Browse files Browse the repository at this point in the history
  • Loading branch information
kammce committed Mar 6, 2024
1 parent 70f69f3 commit 2a6bd88
Show file tree
Hide file tree
Showing 19 changed files with 1,029 additions and 407 deletions.
9 changes: 9 additions & 0 deletions .clang-format
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
BasedOnStyle: Mozilla
Language: Cpp
UseTab: Never
AlwaysBreakAfterReturnType: None
AlwaysBreakAfterDefinitionReturnType: None
AllowShortFunctionsOnASingleLine: None
FixNamespaceComments: true
SpacesBeforeTrailingComments: 2
ColumnLimit: 80
11 changes: 11 additions & 0 deletions .github/workflows/0.0.1.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
name: 🚀 Deploy 0.0.1

on:
workflow_dispatch:

jobs:
deploy:
uses: libhal/ci/.github/workflows/[email protected]
with:
version: 0.0.1
secrets: inherit
39 changes: 39 additions & 0 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
# Copyright 2024 Khalil Estell
#
# 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
#
# http://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.

name: ✅ CI

on:
workflow_dispatch:
pull_request:
push:
branches:
- main
schedule:
- cron: "0 12 * * 0"

jobs:
ci:
uses: libhal/ci/.github/workflows/[email protected]
secrets: inherit

deploy_cortex-m4f_check:
uses: libhal/ci/.github/workflows/[email protected]
with:
arch: cortex-m4f
os: baremetal
compiler: gcc
compiler_version: 12.3
compiler_package: arm-gnu-toolchain
secrets: inherit
3 changes: 3 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -30,3 +30,6 @@
*.exe
*.out
*.app

build/**
CMakeUserPresets.json
48 changes: 48 additions & 0 deletions CMakeLists.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
# Copyright 2024 Khalil Estell
#
# 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
#
# http://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.

cmake_minimum_required(VERSION 3.15)

project(libhal-exceptions LANGUAGES CXX)


if("${RUNTIME}" STREQUAL "ARM_CORTEX_GCC")
set(SOURCE_LIST src/builtin/gcc/impl.cpp)
elseif("${RUNTIME}" STREQUAL "ARM_CORTEX_ESTELL")
set(SOURCE_LIST
src/arm_cortex/estell/exception.cpp
src/arm_cortex/estell/wrappers.cpp
)
else()
message(FATAL "Invalid Exception RUNTIME: '${RUNTIME}' provided!")
endif()

libhal_make_library(
LIBRARY_NAME libhal-exceptions

SOURCES
src/control.cpp
${SOURCE_LIST}
)

if(NOT ${CMAKE_CROSSCOMPILING})
libhal_unit_test(
LIBRARY_NAME libhal-exceptions

SOURCES
src/control.cpp
tests/main.test.cpp
${SOURCE_LIST}
)
endif()
120 changes: 120 additions & 0 deletions conanfile.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,120 @@
# Copyright 2024 Khalil Estell
#
# 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
#
# http://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.

from conan import ConanFile
from conan.tools.cmake import CMake, CMakeDeps, CMakeToolchain, cmake_layout
from conan.tools.files import copy
from conan.tools.build import check_min_cppstd
from conan.errors import ConanInvalidConfiguration
import os

required_conan_version = ">=2.0.14"


class libhal_exceptions_conan(ConanFile):
name = "libhal-exceptions"
license = "Apache-2.0"
url = "https://github.com/conan-io/conan-center-index"
homepage = "https://github.com/libhal/libhal-exceptions"
description = (
"Exception handling runtime support for the libhal ecosystem.")
topics = ("exceptions", "error", "terminate", "unexpected")
settings = "compiler", "build_type", "os", "arch"
generators = "CMakeDeps", "CMakeToolchain", "VirtualBuildEnv"
exports_sources = ("include/*", "tests/*", "LICENSE",
"CMakeLists.txt", "src/*")
options = {
"default_allocator": [True, False],
"runtime": [
"builtin",
"estell",
]
}
default_options = {
"default_allocator": True,
"runtime": "builtin",
}

@property
def _min_cppstd(self):
return "20"

@property
def _compilers_minimum_version(self):
return {
"gcc": "11",
"clang": "14",
}

@property
def _is_arm_cortex(self):
return str(self.settings.arch).startswith("cortex-")

@property
def _runtime_select(self):
if self._is_arm_cortex() and self.options.runtime == "builtin":
return "ARM_CORTEX_GCC"
elif self._is_arm_cortex() and self.options.runtime == "estell":
return "ARM_CORTEX_ESTELL"

def validate(self):
if self.settings.get_safe("compiler.cppstd"):
check_min_cppstd(self, self._min_cppstd)

# Remove this when Estell impl is ready for beta testing
if self.options.runtime != "builtin":
raise ConanInvalidConfiguration(
"Only the 'builtin' exception runtime is supported currently")

def layout(self):
cmake_layout(self)

def build_requirements(self):
self.tool_requires("cmake/3.27.1")
self.tool_requires("libhal-cmake-util/[^4.0.3]")
self.test_requires("boost-ext-ut/1.1.9")

def build(self):
cmake = CMake(self)
cmake.configure(variables={"RUNTIME": "ARM_CORTEX_GCC"})
cmake.build()

def package(self):
copy(self,
"LICENSE",
dst=os.path.join(self.package_folder, "licenses"),
src=self.source_folder)
copy(self,
"*.h",
dst=os.path.join(self.package_folder, "include"),
src=os.path.join(self.source_folder, "include"))
copy(self,
"*.hpp",
dst=os.path.join(self.package_folder, "include"),
src=os.path.join(self.source_folder, "include"))

cmake = CMake(self)
cmake.install()

def package_info(self):
self.cpp_info.libs = ["libhal-exceptions"]
self.cpp_info.set_property("cmake_target_name", "libhal::exceptions")

# Keep this for now, will update this for the runtime select
if self._is_arm_cortex:
self.cpp_info.exelinkflags = [
"-Wl,--wrap=__cxa_allocate_exception",
"-Wl,--wrap=__cxa_free_exception",
"-Wl,--wrap=__cxa_call_unexpected",
]
1 change: 0 additions & 1 deletion include/exceptions.hpp

This file was deleted.

119 changes: 119 additions & 0 deletions include/libhal-exceptions/control.hpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,119 @@
// Copyright 2024 Khalil Estell
//
// 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
//
// http://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 <cstddef>
#include <cstdint>
#include <exception>
#include <span>

namespace hal {
/**
* @brief Interface for an object that allocates memory specifically for
* exceptions
*
*/
class exception_allocator
{
public:
/**
* @brief Allocate/retrieve memory for the exception object allocation
*
* If memory has run out, this function must return an empty span.
*
* @param p_size - Amount of memory to be allocated
* @return std::span<std::uint8_t> - block of memory equal to or greater than
* the size of p_size or and empty span if no memory is available.
*/
std::span<std::uint8_t> allocate(std::size_t p_size) noexcept
{
return do_allocate(p_size);
}

/**
* @brief Deallocate the memory for the exception object
*
* @param p_exception_object - pointer to the allocated exception object
*/
void deallocate(void* p_exception_object) noexcept
{
do_deallocate(p_exception_object);
}

virtual ~exception_allocator() = default;

private:
virtual std::span<std::uint8_t> do_allocate(std::size_t p_size) noexcept = 0;
virtual void do_deallocate(void* p_exception_object) noexcept = 0;
};

/**
* @brief Set the global exception allocator function
*
* More details on how you should use this API to come in the future.
*
* @param p_allocator - exception memory allocator implementation
*/
void set_exception_allocator(exception_allocator& p_allocator) noexcept;

/**
* @brief Set the terminate handler
*
* @param p_terminate_handler - new global terminate handler
*/
std::terminate_handler set_terminate(
std::terminate_handler p_terminate_handler) noexcept;

/**
* @brief Get the terminate handler
*
* @return std::terminate_handler - the currently set terminate handler
*/
std::terminate_handler get_terminate() noexcept;

/**
* @brief Simple single threaded exception allocator
*
* @tparam size - size of the exception object memory buffer. If this is set too
* small (less than 128 bytes), then it is likely that the memory will not be
* enough for any exception runtime and will result in terminate being called.
*/
template<size_t size>
class single_thread_exception_allocator : public exception_allocator
{
public:
single_thread_exception_allocator() = default;
~single_thread_exception_allocator() override = default;

private:
std::span<std::uint8_t> do_allocate(std::size_t p_size) noexcept override
{
if (m_allocated || p_size > m_buffer.size()) {
return {};
}
m_allocated = true;
return m_buffer;
}

void do_deallocate(
[[maybe_unused]] void* p_exception_object) noexcept override
{
m_allocated = false;
}

std::array<std::uint8_t, size> m_buffer{};
bool m_allocated = false;
};
} // namespace hal
Loading

0 comments on commit 2a6bd88

Please sign in to comment.