mbv: async debugging in progres...

This commit is contained in:
Paul Mathieu 2025-07-21 10:06:12 +02:00
parent f0f26af791
commit dd51b5d610
7 changed files with 78 additions and 88 deletions

View File

@ -84,10 +84,6 @@ void step() {
stuff->h(); stuff->h();
TRACE(tracing::TraceEvent::kAsyncTaskDone); TRACE(tracing::TraceEvent::kAsyncTaskDone);
if (stuff->h.done()) {
stuff->h.destroy();
} // XXX: else??
{ {
InterruptLock lock; InterruptLock lock;
work = stuff->next; work = stuff->next;

View File

@ -8,22 +8,12 @@
namespace async { namespace async {
struct task_final_suspend { struct continuation : std::suspend_always {
bool await_ready() noexcept(true) { return false; } void await_suspend(std::coroutine_handle<>) noexcept {
void await_suspend(std::coroutine_handle<> h) noexcept(true) {
if (parent) { if (parent) {
TRACE(tracing::TraceEvent::kAsyncCallParent); parent.resume();
parent();
TRACE(tracing::TraceEvent::kAsyncCallParentDone);
if (parent && parent.done()) {
TRACE(tracing::TraceEvent::kAsyncDestroy);
parent.destroy();
}
} }
} }
void await_resume() noexcept(true) {}
std::coroutine_handle<> parent; std::coroutine_handle<> parent;
}; };
@ -35,40 +25,37 @@ struct task<void> {
struct promise_type; struct promise_type;
using handle_type = std::coroutine_handle<promise_type>; using handle_type = std::coroutine_handle<promise_type>;
~task() {
if (h) {
h.destroy();
}
}
struct promise_type { struct promise_type {
task get_return_object() { task get_return_object() {
return {.h = handle_type::from_promise(*this)}; return {.h = handle_type::from_promise(*this)};
} }
std::suspend_always initial_suspend() noexcept { return {}; } std::suspend_always initial_suspend() noexcept { return {}; }
task_final_suspend final_suspend() noexcept { continuation final_suspend() noexcept { return {.parent = parent}; }
return {.parent = parent};
}
void return_void() {} void return_void() {}
void unhandled_exception() { void unhandled_exception() {}
TRACE(tracing::TraceEvent::kAsyncException);
}
std::coroutine_handle<> parent; std::coroutine_handle<> parent;
}; };
// awaitable // awaitable
bool await_ready() { bool await_ready() {
TRACE(tracing::TraceEvent::kAsyncCoAwait); h.promise().parent = {};
h(); h.resume();
if (h.done()) { if (h.done()) {
TRACE(tracing::TraceEvent::kAsyncDestroy);
h.destroy();
return true; return true;
} }
return false; return false;
} }
void await_suspend(std::coroutine_handle<> ha) { void await_suspend(std::coroutine_handle<> ha) { h.promise().parent = ha; }
TRACE(tracing::TraceEvent::kAsyncSuspend);
h.promise().parent = ha;
}
void await_resume() {} void await_resume() {}
std::coroutine_handle<promise_type> h; handle_type h;
}; };
template <typename T> template <typename T>
@ -76,20 +63,22 @@ struct task {
struct promise_type; struct promise_type;
using handle_type = std::coroutine_handle<promise_type>; using handle_type = std::coroutine_handle<promise_type>;
~task() {
if (h) {
h.destroy();
}
}
struct promise_type { struct promise_type {
task get_return_object() { task get_return_object() {
return {.h = handle_type::from_promise(*this)}; return {.h = handle_type::from_promise(*this)};
} }
std::suspend_always initial_suspend() noexcept { return {}; } std::suspend_always initial_suspend() noexcept { return {}; }
task_final_suspend final_suspend() noexcept { continuation final_suspend() noexcept { return {.parent = parent}; }
return {.parent = parent};
}
void return_value(T&& value) { ret_value = std::move(value); } void return_value(T&& value) { ret_value = std::move(value); }
void unhandled_exception() { void unhandled_exception() {}
TRACE(tracing::TraceEvent::kAsyncException);
}
template <std::convertible_to<T> From> template <std::convertible_to<T> From>
task_final_suspend yield_value(From&& value) { continuation yield_value(From&& value) {
ret_value = std::forward<From>(value); ret_value = std::forward<From>(value);
result_ready = true; result_ready = true;
return {.parent = parent}; return {.parent = parent};
@ -103,34 +92,18 @@ struct task {
// awaitable // awaitable
bool await_ready() { bool await_ready() {
h.promise().parent = {}; h.promise().parent = {};
TRACE(tracing::TraceEvent::kAsyncCoAwait); h.resume();
h(); if (h.promise().result_ready || h.done()) {
if (h.promise().result_ready) {
return true;
}
if (h.done()) {
destroyed = true;
ret_value = std::move(h.promise().ret_value);
TRACE(tracing::TraceEvent::kAsyncDestroy);
h.destroy();
return true; return true;
} }
return false; return false;
} }
void await_suspend(std::coroutine_handle<> ha) { void await_suspend(std::coroutine_handle<> ha) { h.promise().parent = ha; }
TRACE(tracing::TraceEvent::kAsyncSuspend);
h.promise().parent = ha;
}
T await_resume() { T await_resume() {
if (!destroyed) { h.promise().result_ready = false;
h.promise().result_ready = false; return std::move(h.promise().ret_value);
return std::move(h.promise().ret_value);
}
return std::move(ret_value);
} }
bool destroyed = false;
T ret_value;
std::coroutine_handle<promise_type> h; std::coroutine_handle<promise_type> h;
}; };
@ -181,12 +154,11 @@ struct gimme {
ha = h; ha = h;
waiting = true; waiting = true;
TRACE(tracing::TraceEvent::kAsyncGimmeWaiting); TRACE(tracing::TraceEvent::kAsyncGimmeWaiting);
if (suspended) { if (parent) {
schedule(parent); schedule(parent);
} }
} }
T await_resume() { T await_resume() {
suspended = false;
waiting = false; waiting = false;
TRACE(tracing::TraceEvent::kAsyncGimmeResume); TRACE(tracing::TraceEvent::kAsyncGimmeResume);
return std::move(stuff); return std::move(stuff);
@ -196,18 +168,14 @@ struct gimme {
auto feed(T&& s) { auto feed(T&& s) {
struct awaitable { struct awaitable {
bool await_ready() { bool await_ready() {
g->ha.resume(); g.parent = {};
if (!g->waiting) { g.ha.resume();
g->suspended = true; return g.waiting;
}
return !g->suspended;
} }
void await_suspend(std::coroutine_handle<> h) { void await_suspend(std::coroutine_handle<> h) { g.parent = h; }
g->parent = h; void await_resume() {}
}
void await_resume() { }
gimme<T>* g; gimme<T>& g;
}; };
if (!waiting) { if (!waiting) {
@ -216,11 +184,10 @@ struct gimme {
if (!ha) { if (!ha) {
__builtin_trap(); __builtin_trap();
} }
stuff = s; stuff = std::move(s);
return awaitable{.g = this}; return awaitable{.g = *this};
} }
bool suspended = false;
bool waiting = false; bool waiting = false;
std::coroutine_handle<> ha; std::coroutine_handle<> ha;
std::coroutine_handle<> parent; std::coroutine_handle<> parent;

View File

@ -11,14 +11,28 @@
namespace { namespace {
Timer* timer0; constexpr uint32_t kTicksPerSecond = 100'000'000;
constexpr uint32_t kTicksPerMicrosecond = 100;
constexpr uint32_t kOverflowSeconds = (1ULL << 32) / kTicksPerSecond;
constexpr uint32_t kOverflowMicroseconds =
((1ULL << 32) % kTicksPerSecond) / kTicksPerMicrosecond;
void Uart0Isr() { Timer* timer0;
HandleUartIsr(); volatile uint32_t t1overflowsecs = 0;
} volatile uint32_t t1overflowusecs = 0;
void Uart0Isr() { HandleUartIsr(); }
void Timer0Isr() { void Timer0Isr() {
if (timer0->HasT1Overflowed()) {
UartWriteCrash("t1 overflow\r\n");
t1overflowsecs += kOverflowSeconds;
t1overflowusecs += kOverflowMicroseconds;
timer0->ClearT1Overflow();
return;
}
SetLed(6); SetLed(6);
UartWriteCrash("blarg\r\n");
__builtin_trap(); __builtin_trap();
} }
@ -63,6 +77,8 @@ async::task<> blink() {
co_await async::delay(500); co_await async::delay(500);
ToggleLed(0); ToggleLed(0);
timer0->Pet(); timer0->Pet();
co_await UartWrite(".");
} }
} }
@ -77,12 +93,16 @@ int main() {
gpio0->data = 0; gpio0->data = 0;
SetupInterrupts(); SetupInterrupts();
async::schedule(echo().h); auto e = echo();
async::schedule(blink().h); auto b = blink();
async::schedule(e.h);
async::schedule(b.h);
UartWriteBlocking("init done. starting main loop\r\n"); UartWriteBlocking("init done. starting main loop\r\n");
async::main_loop(nullptr); async::main_loop([]() {
return false;
});
// should never get here // should never get here
} }
@ -111,8 +131,9 @@ extern "C" void* _sbrk(int increment) {
extern "C" int _gettimeofday(struct timeval* tv, void* tzvp) { extern "C" int _gettimeofday(struct timeval* tv, void* tzvp) {
(void)tzvp; (void)tzvp;
uint32_t ticks = timer0->GetT1Ticks(); uint32_t ticks = timer0->GetT1Ticks();
tv->tv_sec = ticks / 100000000; tv->tv_sec = ticks / kTicksPerSecond + t1overflowsecs;
tv->tv_usec = (ticks % 100000000) / 100; tv->tv_usec =
(ticks % kTicksPerSecond) / kTicksPerMicrosecond + t1overflowusecs;
return 0; return 0;
} }

View File

@ -12,7 +12,7 @@ namespace {
Timer* timer0; Timer* timer0;
void Uart0Isr() { void Uart0Isr() {
// ToggleLed(7); // ToggleLed(7);
HandleUartIsr(); HandleUartIsr();
} }
@ -30,7 +30,7 @@ void SetupUart() {
void SetupTimer() { void SetupTimer() {
timer0 = Timer::Instance(TIMER0_BASE); timer0 = Timer::Instance(TIMER0_BASE);
// timer0->SetupAsWdt(100'000 * 1000); // timer0->SetupAsWdt(100'000 * 1000);
timer0->EnableT1(); timer0->EnableT1();
intc::SetIsr(TIMER0_IRQN, Timer0Isr); intc::SetIsr(TIMER0_IRQN, Timer0Isr);

View File

@ -84,7 +84,8 @@ void UartWriteCrash(std::span<const std::byte> data) {
} }
while (XUartLite_IsSending(uart0)) { while (XUartLite_IsSending(uart0)) {
} }
XUartLite_Send(uart0, nullptr, 0); // reset buffer before enabling interrupts XUartLite_Send(uart0, nullptr,
0); // reset buffer before enabling interrupts
XUartLite_EnableInterrupt(uart0); XUartLite_EnableInterrupt(uart0);
} }

View File

@ -96,7 +96,8 @@ void UartWriteCrash(std::span<const std::byte> data) {
} }
while (XUartLite_IsSending(uart0)) { while (XUartLite_IsSending(uart0)) {
} }
XUartLite_Send(uart0, nullptr, 0); // reset buffer before enabling interrupts XUartLite_Send(uart0, nullptr,
0); // reset buffer before enabling interrupts
XUartLite_EnableInterrupt(uart0); XUartLite_EnableInterrupt(uart0);
} }

View File

@ -37,11 +37,15 @@ struct Timer {
void EnableT1() { void EnableT1() {
TCSR1.ARHT0 = 1; TCSR1.ARHT0 = 1;
TCSR1.ENIT0 = 1; // enable interrupt for overflows
TCSR1.ENT0 = 1; TCSR1.ENT0 = 1;
} }
uint32_t GetT1Ticks() { return TCR1; } uint32_t GetT1Ticks() { return TCR1; }
bool HasT1Overflowed() { return TCSR1.T0INT; }
void ClearT1Overflow() { TCSR1.T0INT = 1; }
void SetupAsWdt(uint32_t timeout_ticks) { void SetupAsWdt(uint32_t timeout_ticks) {
TLR0 = timeout_ticks; TLR0 = timeout_ticks;
TCSR0.LOAD0 = 1; // reset counter TCSR0.LOAD0 = 1; // reset counter