Skip to content

Commit 06d10d0

Browse files
committed
[io] Implement blocking IODevice for fibers
1 parent 33f2255 commit 06d10d0

File tree

2 files changed

+45
-10
lines changed

2 files changed

+45
-10
lines changed

src/modm/io/iodevice_wrapper.hpp renamed to src/modm/io/iodevice_wrapper.hpp.in

Lines changed: 42 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,10 @@
1616
#define MODM_IODEVICE_WRAPPER_HPP
1717

1818
#include <stdint.h>
19-
19+
%% if with_fiber
20+
#include <modm/processing/fiber.hpp>
21+
%% endif
22+
%#
2023
#include "iodevice.hpp"
2124

2225
namespace modm
@@ -39,19 +42,34 @@ IOBuffer
3942
template< class Device, IOBuffer behavior >
4043
class IODeviceWrapper : public IODevice
4144
{
45+
%% if with_fiber
46+
static constexpr fiber::id NoOwner{fiber::id(-1)};
47+
static inline fiber::id id{NoOwner};
48+
%% endif
4249
public:
4350
IODeviceWrapper() = default;
4451
using IODevice::write;
4552

4653
void
4754
write(char c) override
4855
{
49-
bool written;
50-
do
56+
if constexpr (behavior == IOBuffer::BlockIfFull)
57+
%% if with_fiber
5158
{
52-
written = Device::write(uint8_t(c));
59+
// lock this device to one fiber until a newline is received
60+
const auto me = modm::this_fiber::get_id();
61+
modm::this_fiber::poll([&]{ return id == NoOwner or id == me; });
62+
id = me;
63+
64+
modm::this_fiber::poll([&]{ return Device::write(uint8_t(c)); });
65+
66+
if (c == '\n') id = NoOwner;
67+
modm::this_fiber::yield();
5368
}
54-
while(behavior == IOBuffer::BlockIfFull and not written);
69+
%% else
70+
while (not Device::write(uint8_t(c))) ;
71+
%% endif
72+
else Device::write(uint8_t(c));
5573
}
5674

5775
void
@@ -71,6 +89,10 @@ class IODeviceWrapper : public IODevice
7189
template< class Device, IOBuffer behavior >
7290
class IODeviceObjectWrapper : public IODevice
7391
{
92+
%% if with_fiber
93+
static constexpr fiber::id NoOwner{fiber::id(-1)};
94+
fiber::id id{NoOwner};
95+
%% endif
7496
Device &device;
7597
public:
7698
IODeviceObjectWrapper(Device& device) : device{device} {}
@@ -79,12 +101,23 @@ class IODeviceObjectWrapper : public IODevice
79101
void
80102
write(char c) override
81103
{
82-
bool written;
83-
do
104+
if constexpr (behavior == IOBuffer::BlockIfFull)
105+
%% if with_fiber
84106
{
85-
written = device.write(uint8_t(c));
107+
// lock this device to one fiber until a newline is received
108+
const auto me = modm::this_fiber::get_id();
109+
modm::this_fiber::poll([&]{ return id == NoOwner or id == me; });
110+
id = me;
111+
112+
modm::this_fiber::poll([&]{ return device.write(uint8_t(c)); });
113+
114+
if (c == '\n') id = NoOwner;
115+
modm::this_fiber::yield();
86116
}
87-
while(behavior == IOBuffer::BlockIfFull and not written);
117+
%% else
118+
while (not device.write(uint8_t(c))) ;
119+
%% endif
120+
else device.write(uint8_t(c));
88121
}
89122

90123
void

src/modm/io/module.lb

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@ def init(module):
1818
def prepare(module, options):
1919
module.depends(
2020
":architecture:accessor",
21+
":architecture:fiber",
2122
":math:utils")
2223

2324
is_avr = options[":target"].identifier.platform in ["avr"]
@@ -45,12 +46,13 @@ def build(env):
4546
env.substitutions = {
4647
"is_hosted": target.platform == "hosted",
4748
"is_avr": target.platform == "avr",
49+
"with_fiber": env.has_module(":processing:fiber"),
4850
"family": target.family,
4951
"core": core,
5052
}
5153
env.outbasepath = "modm/src/modm/io"
5254
env.copy("iodevice.hpp")
53-
env.copy("iodevice_wrapper.hpp")
55+
env.template("iodevice_wrapper.hpp.in")
5456
env.template("iostream_printf.cpp.in")
5557
env.template("iostream.hpp.in")
5658
env.template("iostream_chrono.hpp.in")

0 commit comments

Comments
 (0)