Skip to content

Commit

Permalink
[c++] Support fibers in static initialization guard
Browse files Browse the repository at this point in the history
  • Loading branch information
salkinium committed May 20, 2024
1 parent 5ae26a6 commit 848d730
Show file tree
Hide file tree
Showing 5 changed files with 157 additions and 3 deletions.
7 changes: 7 additions & 0 deletions ext/gcc/cxxabi.cpp.in
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,9 @@ void __cxa_deleted_virtual()

%% if with_threadsafe_statics
#include <atomic>
%% if with_fibers
#include <modm/processing/fiber.hpp>
%% endif
%% if is_avr
%#
// Even thought the actual guard size is uint64_t on AVR, we only need to access
Expand Down Expand Up @@ -71,6 +74,10 @@ __cxa_guard_acquire(guard_type *guard)
// We got called from inside an interrupt, but we cannot yield back
modm_assert(not is_in_irq, "stat.rec",
"Recursive initialization of a function static!", guard);
%% if with_fibers
// we're not in an interrupt, try to yield back to the initializing fiber
modm::this_fiber::yield();
%% endif
}
value = UNINITIALIZED;
}
Expand Down
1 change: 1 addition & 0 deletions ext/gcc/module_c++.lb
Original file line number Diff line number Diff line change
Expand Up @@ -92,6 +92,7 @@ def build(env):
"with_threadsafe_statics": with_threadsafe_statics,
"with_memory_traits": env.has_module(":architecture:memory"),
"with_heap": env.has_module(":platform:heap"),
"with_fibers": env.has_module(":processing:fiber"),
"is_avr": is_avr,
"is_cortex_m": is_cortex_m,
}
Expand Down
6 changes: 3 additions & 3 deletions test/modm/ext/cxa_guard_test.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -16,10 +16,10 @@
extern "C"
{

#ifdef MODM_CPU_ARM
using guard_t = uint32_t;
#ifdef MODM_CPU_CORTEX_M
using guard_t = int32_t;
#else
using guard_t = uint64_t;
using guard_t = int64_t;
#endif

int __cxa_guard_acquire(guard_t*);
Expand Down
118 changes: 118 additions & 0 deletions test/modm/processing/fiber/fiber_guard_test.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,118 @@
/*
* Copyright (c) 2023, Niklas Hauser
*
* This file is part of the modm project.
*
* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/.
*/
// ----------------------------------------------------------------------------

#include "fiber_guard_test.hpp"
#include "shared.hpp"
#include <modm/architecture/detect.hpp>

extern "C"
{

#ifdef MODM_CPU_CORTEX_M
using guard_t = int32_t;
#else
using guard_t = int64_t;
#endif

int __cxa_guard_acquire(guard_t*);
void __cxa_guard_release(guard_t*);
void __cxa_guard_abort(guard_t*);

static guard_t guard{0};

}

void
FiberGuardTest::setUp()
{
state = 0;
}

// ================================== GUARD ===================================
static void
f1()
{
TEST_ASSERT_EQUALS(state++, 0u);
TEST_ASSERT_EQUALS(guard, guard_t(0));

TEST_ASSERT_EQUALS(__cxa_guard_acquire(&guard), 1);
TEST_ASSERT_EQUALS(guard, guard_t(0x10));
// now while initializing yield to another fiber
modm::this_fiber::yield(); // goto 1

TEST_ASSERT_EQUALS(state++, 2u);
__cxa_guard_release(&guard);
TEST_ASSERT_EQUALS(guard, guard_t(1));
}

static void
f2()
{
TEST_ASSERT_EQUALS(state++, 1u);
TEST_ASSERT_EQUALS(guard, guard_t(0x10));
TEST_ASSERT_EQUALS(__cxa_guard_acquire(&guard), 0); // goto 2

TEST_ASSERT_EQUALS(state++, 3u);
TEST_ASSERT_EQUALS(guard, guard_t(1));
}


void
FiberGuardTest::testGuard()
{
#ifndef MODM_OS_HOSTED
modm::fiber::Task fiber1(stack1, f1), fiber2(stack2, f2);
modm::fiber::Scheduler::run();
#endif
}

// =============================== CONSTRUCTOR ================================
static uint8_t constructor_calls{0};
struct StaticClass
{
uint8_t counter{0};
StaticClass()
{
constructor_calls++;
}

void increment()
{
counter++;
}
};

static StaticClass& instance()
{
static StaticClass obj;
return obj;
}

void
FiberGuardTest::testConstructor()
{
TEST_ASSERT_EQUALS(constructor_calls, 0);

instance().increment();
TEST_ASSERT_EQUALS(constructor_calls, 1);
TEST_ASSERT_EQUALS(instance().counter, 1);
TEST_ASSERT_EQUALS(constructor_calls, 1);

instance().increment();
TEST_ASSERT_EQUALS(constructor_calls, 1);
TEST_ASSERT_EQUALS(instance().counter, 2);
TEST_ASSERT_EQUALS(constructor_calls, 1);

instance().increment();
TEST_ASSERT_EQUALS(constructor_calls, 1);
TEST_ASSERT_EQUALS(instance().counter, 3);
TEST_ASSERT_EQUALS(constructor_calls, 1);
}
28 changes: 28 additions & 0 deletions test/modm/processing/fiber/fiber_guard_test.hpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
/*
* Copyright (c) 2020, Erik Henriksson
*
* This file is part of the modm project.
*
* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/.
*/
// ----------------------------------------------------------------------------

#pragma once

#include <unittest/testsuite.hpp>

/// @ingroup modm_test_test_architecture
class FiberGuardTest : public unittest::TestSuite
{
public:
void
setUp();

void
testGuard();

void
testConstructor();
};

0 comments on commit 848d730

Please sign in to comment.