Skip to content

Commit 848d730

Browse files
committed
[c++] Support fibers in static initialization guard
1 parent 5ae26a6 commit 848d730

File tree

5 files changed

+157
-3
lines changed

5 files changed

+157
-3
lines changed

ext/gcc/cxxabi.cpp.in

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,9 @@ void __cxa_deleted_virtual()
2727

2828
%% if with_threadsafe_statics
2929
#include <atomic>
30+
%% if with_fibers
31+
#include <modm/processing/fiber.hpp>
32+
%% endif
3033
%% if is_avr
3134
%#
3235
// Even thought the actual guard size is uint64_t on AVR, we only need to access
@@ -71,6 +74,10 @@ __cxa_guard_acquire(guard_type *guard)
7174
// We got called from inside an interrupt, but we cannot yield back
7275
modm_assert(not is_in_irq, "stat.rec",
7376
"Recursive initialization of a function static!", guard);
77+
%% if with_fibers
78+
// we're not in an interrupt, try to yield back to the initializing fiber
79+
modm::this_fiber::yield();
80+
%% endif
7481
}
7582
value = UNINITIALIZED;
7683
}

ext/gcc/module_c++.lb

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -92,6 +92,7 @@ def build(env):
9292
"with_threadsafe_statics": with_threadsafe_statics,
9393
"with_memory_traits": env.has_module(":architecture:memory"),
9494
"with_heap": env.has_module(":platform:heap"),
95+
"with_fibers": env.has_module(":processing:fiber"),
9596
"is_avr": is_avr,
9697
"is_cortex_m": is_cortex_m,
9798
}

test/modm/ext/cxa_guard_test.cpp

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -16,10 +16,10 @@
1616
extern "C"
1717
{
1818

19-
#ifdef MODM_CPU_ARM
20-
using guard_t = uint32_t;
19+
#ifdef MODM_CPU_CORTEX_M
20+
using guard_t = int32_t;
2121
#else
22-
using guard_t = uint64_t;
22+
using guard_t = int64_t;
2323
#endif
2424

2525
int __cxa_guard_acquire(guard_t*);
Lines changed: 118 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,118 @@
1+
/*
2+
* Copyright (c) 2023, Niklas Hauser
3+
*
4+
* This file is part of the modm project.
5+
*
6+
* This Source Code Form is subject to the terms of the Mozilla Public
7+
* License, v. 2.0. If a copy of the MPL was not distributed with this
8+
* file, You can obtain one at http://mozilla.org/MPL/2.0/.
9+
*/
10+
// ----------------------------------------------------------------------------
11+
12+
#include "fiber_guard_test.hpp"
13+
#include "shared.hpp"
14+
#include <modm/architecture/detect.hpp>
15+
16+
extern "C"
17+
{
18+
19+
#ifdef MODM_CPU_CORTEX_M
20+
using guard_t = int32_t;
21+
#else
22+
using guard_t = int64_t;
23+
#endif
24+
25+
int __cxa_guard_acquire(guard_t*);
26+
void __cxa_guard_release(guard_t*);
27+
void __cxa_guard_abort(guard_t*);
28+
29+
static guard_t guard{0};
30+
31+
}
32+
33+
void
34+
FiberGuardTest::setUp()
35+
{
36+
state = 0;
37+
}
38+
39+
// ================================== GUARD ===================================
40+
static void
41+
f1()
42+
{
43+
TEST_ASSERT_EQUALS(state++, 0u);
44+
TEST_ASSERT_EQUALS(guard, guard_t(0));
45+
46+
TEST_ASSERT_EQUALS(__cxa_guard_acquire(&guard), 1);
47+
TEST_ASSERT_EQUALS(guard, guard_t(0x10));
48+
// now while initializing yield to another fiber
49+
modm::this_fiber::yield(); // goto 1
50+
51+
TEST_ASSERT_EQUALS(state++, 2u);
52+
__cxa_guard_release(&guard);
53+
TEST_ASSERT_EQUALS(guard, guard_t(1));
54+
}
55+
56+
static void
57+
f2()
58+
{
59+
TEST_ASSERT_EQUALS(state++, 1u);
60+
TEST_ASSERT_EQUALS(guard, guard_t(0x10));
61+
TEST_ASSERT_EQUALS(__cxa_guard_acquire(&guard), 0); // goto 2
62+
63+
TEST_ASSERT_EQUALS(state++, 3u);
64+
TEST_ASSERT_EQUALS(guard, guard_t(1));
65+
}
66+
67+
68+
void
69+
FiberGuardTest::testGuard()
70+
{
71+
#ifndef MODM_OS_HOSTED
72+
modm::fiber::Task fiber1(stack1, f1), fiber2(stack2, f2);
73+
modm::fiber::Scheduler::run();
74+
#endif
75+
}
76+
77+
// =============================== CONSTRUCTOR ================================
78+
static uint8_t constructor_calls{0};
79+
struct StaticClass
80+
{
81+
uint8_t counter{0};
82+
StaticClass()
83+
{
84+
constructor_calls++;
85+
}
86+
87+
void increment()
88+
{
89+
counter++;
90+
}
91+
};
92+
93+
static StaticClass& instance()
94+
{
95+
static StaticClass obj;
96+
return obj;
97+
}
98+
99+
void
100+
FiberGuardTest::testConstructor()
101+
{
102+
TEST_ASSERT_EQUALS(constructor_calls, 0);
103+
104+
instance().increment();
105+
TEST_ASSERT_EQUALS(constructor_calls, 1);
106+
TEST_ASSERT_EQUALS(instance().counter, 1);
107+
TEST_ASSERT_EQUALS(constructor_calls, 1);
108+
109+
instance().increment();
110+
TEST_ASSERT_EQUALS(constructor_calls, 1);
111+
TEST_ASSERT_EQUALS(instance().counter, 2);
112+
TEST_ASSERT_EQUALS(constructor_calls, 1);
113+
114+
instance().increment();
115+
TEST_ASSERT_EQUALS(constructor_calls, 1);
116+
TEST_ASSERT_EQUALS(instance().counter, 3);
117+
TEST_ASSERT_EQUALS(constructor_calls, 1);
118+
}
Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
/*
2+
* Copyright (c) 2020, Erik Henriksson
3+
*
4+
* This file is part of the modm project.
5+
*
6+
* This Source Code Form is subject to the terms of the Mozilla Public
7+
* License, v. 2.0. If a copy of the MPL was not distributed with this
8+
* file, You can obtain one at http://mozilla.org/MPL/2.0/.
9+
*/
10+
// ----------------------------------------------------------------------------
11+
12+
#pragma once
13+
14+
#include <unittest/testsuite.hpp>
15+
16+
/// @ingroup modm_test_test_architecture
17+
class FiberGuardTest : public unittest::TestSuite
18+
{
19+
public:
20+
void
21+
setUp();
22+
23+
void
24+
testGuard();
25+
26+
void
27+
testConstructor();
28+
};

0 commit comments

Comments
 (0)