100 lines
2.8 KiB
C++
100 lines
2.8 KiB
C++
typedef void CoroutineFunction(mco_coro *co);
|
|
CCtx *_CoroutineContext = NULL;
|
|
|
|
CCtx *GetCoroutineContext() {
|
|
Assert(_CoroutineContext);
|
|
return _CoroutineContext;
|
|
}
|
|
|
|
void DestroyCoroutine(CCtx *n) {
|
|
mco_destroy(n->co);
|
|
Release(&n->arena);
|
|
}
|
|
|
|
void RemoveCoroutine(String name) {
|
|
IterRemove(ActiveCoroutines) {
|
|
IterRemovePrepare(ActiveCoroutines);
|
|
if (it.name == name) {
|
|
DestroyCoroutine(&it);
|
|
remove_item = true;
|
|
}
|
|
}
|
|
}
|
|
|
|
CCtx CreateCoroutine(CoroutineFunction *func, String name) {
|
|
mco_desc desc = mco_desc_init(func, 0);
|
|
mco_coro *coro = NULL;
|
|
mco_result ok = mco_create(&coro, &desc);
|
|
assert(ok == MCO_SUCCESS);
|
|
return {coro, name};
|
|
}
|
|
|
|
#define AddCoroutine(x) AddCoroutineEx(x, #x)
|
|
CCtx *AddCoroutineEx(CoroutineFunction *func, String name) {
|
|
CCtx coroutine = CreateCoroutine(func, name);
|
|
Add(&ActiveCoroutines, coroutine);
|
|
return GetLast(ActiveCoroutines);
|
|
}
|
|
|
|
void ResumeCoroutine(CCtx *dat) {
|
|
CCtx *prev_curr = _CoroutineContext;
|
|
_CoroutineContext = dat;
|
|
mco_result ok = mco_resume(dat->co);
|
|
Assert(ok == MCO_SUCCESS);
|
|
_CoroutineContext = prev_curr;
|
|
}
|
|
|
|
void UpdateCoroutines(Event *event) {
|
|
ProfileFunction();
|
|
double start = GetTimeSeconds();
|
|
for (;ActiveCoroutines.len;) {
|
|
IterRemove(ActiveCoroutines) {
|
|
IterRemovePrepare(ActiveCoroutines);
|
|
ProfileScopeEx(it.name);
|
|
|
|
mco_state status = mco_status(it.co);
|
|
if (status == MCO_DEAD) {
|
|
DestroyCoroutine(&it);
|
|
remove_item = true;
|
|
} else {
|
|
mco_push(it.co, &event, sizeof(Event *));
|
|
_CoroutineContext = ⁢
|
|
mco_result ok = mco_resume(it.co);
|
|
if (ok != MCO_SUCCESS) {
|
|
ReportErrorf("failed to resume coroutine %d", ok);
|
|
DestroyCoroutine(&it);
|
|
remove_item = true;
|
|
}
|
|
_CoroutineContext = NULL;
|
|
}
|
|
}
|
|
|
|
#if SLOW_BUILD
|
|
//:CoroutineLeakCheck
|
|
// Make sure we don't leak scratch arenas between coroutine boundaries.
|
|
// it leads to memory corruption! If you hit Assert here make sure you
|
|
// don't leak the scratch arena.
|
|
for (int i = 0; i < Lengthof(ScratchArenas); i += 1) {
|
|
Assert(ScratchArenas[i].refs == 0);
|
|
}
|
|
#endif
|
|
|
|
double took = GetTimeSeconds() - start;
|
|
bool dont_loop_on_coroutines_when_budget_is_ok_exit_immediately = Testing;
|
|
if (dont_loop_on_coroutines_when_budget_is_ok_exit_immediately || (took > (0.016666 / 3.0))) {
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
Event *Yield(mco_coro *co) {
|
|
mco_result ok = mco_yield(co);
|
|
Assert(ok == MCO_SUCCESS);
|
|
|
|
Event *event = NULL;
|
|
ok = mco_pop(co, &event, sizeof(Event *));
|
|
Assert(ok == MCO_SUCCESS);
|
|
|
|
return event;
|
|
}
|