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();
TRACE(tracing::TraceEvent::kAsyncTaskDone);
if (stuff->h.done()) {
stuff->h.destroy();
} // XXX: else??
{
InterruptLock lock;
work = stuff->next;

View File

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

View File

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

View File

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

View File

@ -84,7 +84,8 @@ void UartWriteCrash(std::span<const std::byte> data) {
}
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);
}

View File

@ -96,7 +96,8 @@ void UartWriteCrash(std::span<const std::byte> data) {
}
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);
}

View File

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