CoroutineLeakCheck

This commit is contained in:
Krzosa Karol
2026-01-19 09:08:26 +01:00
parent 372287f557
commit 1ce128a5d5
5 changed files with 65 additions and 32 deletions

View File

@@ -47,6 +47,7 @@ struct BlockArena {
U8 *end; U8 *end;
BlockArenaNode *blocks; BlockArenaNode *blocks;
Allocator allocator; Allocator allocator;
int refs; // :CoroutineLeakCheck
operator Allocator() { return {BlockArenaAllocatorProc, this}; } operator Allocator() { return {BlockArenaAllocatorProc, this}; }
}; };
@@ -66,6 +67,7 @@ struct VirtualArena {
size_t reserve; size_t reserve;
size_t commit; size_t commit;
size_t align; size_t align;
int refs; // :CoroutineLeakCheck
operator Allocator() { operator Allocator() {
void *ArenaAllocatorProc(void *object, int kind, void *p, size_t size); void *ArenaAllocatorProc(void *object, int kind, void *p, size_t size);
@@ -112,28 +114,32 @@ API VirtualArena *GetScratchEx(VirtualArena **conflicts, int conflict_count);
struct Scratch { struct Scratch {
VirtualArena *arena; VirtualArena *arena;
U64 p; U64 p;
Scratch() {arena = &ScratchArenas[0]; p = arena->len;} Scratch() {arena = &ScratchArenas[0]; p = arena->len; arena->refs += 1;}
Scratch(VirtualArena *conflict) { Scratch(VirtualArena *conflict) {
VirtualArena *conf[] = {conflict}; VirtualArena *conf[] = {conflict};
arena = GetScratchEx(conf, Lengthof(conf)); arena = GetScratchEx(conf, Lengthof(conf));
p = arena->len; p = arena->len;
arena->refs += 1;
} }
Scratch(VirtualArena *c1, VirtualArena *c2) { Scratch(VirtualArena *c1, VirtualArena *c2) {
VirtualArena *conf[] = {c1, c2}; VirtualArena *conf[] = {c1, c2};
arena = GetScratchEx(conf, Lengthof(conf)); arena = GetScratchEx(conf, Lengthof(conf));
p = arena->len; p = arena->len;
arena->refs += 1;
} }
Scratch(Allocator conflict) { Scratch(Allocator conflict) {
VirtualArena *conf[] = {(VirtualArena *)conflict.object}; VirtualArena *conf[] = {(VirtualArena *)conflict.object};
arena = GetScratchEx(conf, Lengthof(conf)); arena = GetScratchEx(conf, Lengthof(conf));
p = arena->len; p = arena->len;
arena->refs += 1;
} }
Scratch(Allocator c1, Allocator c2) { Scratch(Allocator c1, Allocator c2) {
VirtualArena *conf[] = {(VirtualArena *)c1.object, (VirtualArena *)c2.object}; VirtualArena *conf[] = {(VirtualArena *)c1.object, (VirtualArena *)c2.object};
arena = GetScratchEx(conf, Lengthof(conf)); arena = GetScratchEx(conf, Lengthof(conf));
p = arena->len; p = arena->len;
arena->refs += 1;
} }
~Scratch() { SetLen(arena, p); } ~Scratch() { SetLen(arena, p); arena->refs -= 1; }
operator VirtualArena *() { return arena; } operator VirtualArena *() { return arena; }
operator Allocator() { return *arena; } operator Allocator() { return *arena; }

View File

@@ -62,6 +62,16 @@ void CoUpdate(Event *event) {
} }
} }
#if DEBUG_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; double took = GetTimeSeconds() - start;
if (took > (0.016666 / 3.0)) { if (took > (0.016666 / 3.0)) {
break; break;

View File

@@ -472,35 +472,32 @@ inline void AddEvent(Array<Event> *events, Event ev) {
Add(events, ev); Add(events, ev);
} }
Array<Event> GetEventsForFrame(Allocator allocator) { void GetEventsForFrame(Array<Event> *events) {
ProfileFunction(); ProfileFunction();
Array<Event> result = {allocator}; For (EventPlayback) {
if (EventPlayback.len) { Add(events, it);
result = TightCopy(allocator, EventPlayback);
EventPlayback.len = 0;
} }
SDL_Event event; SDL_Event event;
if (WaitForEventsState) { if (WaitForEventsState) {
SDL_WaitEvent(&event); SDL_WaitEvent(&event);
Event ev = TranslateSDLEvent(&event); Event ev = TranslateSDLEvent(&event);
AddEvent(&result, ev); AddEvent(events, ev);
} }
while (SDL_PollEvent(&event)) { while (SDL_PollEvent(&event)) {
Event ev = TranslateSDLEvent(&event); Event ev = TranslateSDLEvent(&event);
AddEvent(&result, ev); AddEvent(events, ev);
} }
if (result.len == 0) { if (events->len == 0) {
Event event = {}; Event event = {};
FillEventWithBasicData(&event); FillEventWithBasicData(&event);
event.kind = EVENT_UPDATE; event.kind = EVENT_UPDATE;
Add(&result, event); Add(events, event);
} }
Assert(result.len); Assert(events->len);
return result;
} }

View File

@@ -67,4 +67,18 @@ void CMD_SetProjectHere() {
} }
} }
#endif #endif
} RegisterCommand(CMD_SetProjectHere, "", "Sets the project directory, opens the project file etc."); } RegisterCommand(CMD_SetProjectHere, "", "Sets the project directory, opens the project file etc.");
void CO_CreateProject(mco_coro *co) {
String16 project_name16 = QueryUserString(co, "Please tell me, how would you like to name your project?");
String directory = GetPrimaryDirectory();
{
Scratch scratch;
String project_name = ToString(scratch, project_name16);
String name = Format(scratch, "%S/%S", directory, project_name);
MakeDir(name);
Open(name);
}
} RegisterCoroutineCommand(CO_CreateProject, "", "Creates a project in current buffer directory with template files and all that, asks user for input etc.");

View File

@@ -626,15 +626,17 @@ void Update(Event event) {
ProfileFunction(); ProfileFunction();
LayoutWindows(event.xwindow, event.ywindow); LayoutWindows(event.xwindow, event.ywindow);
Scratch scratch; {
Array<Window *> order = GetWindowZOrder(scratch); Scratch scratch;
For(order) { Array<Window *> order = GetWindowZOrder(scratch);
if (!it->visible) { For(order) {
continue; if (!it->visible) {
continue;
}
View *view = GetView(it->active_view);
view->main_caret_on_begin_frame = view->carets[0];
view->update_scroll = true;
} }
View *view = GetView(it->active_view);
view->main_caret_on_begin_frame = view->carets[0];
view->update_scroll = true;
} }
For (Windows) { For (Windows) {
@@ -670,7 +672,7 @@ void Update(Event event) {
CoUpdate(&event); CoUpdate(&event);
For(IterateInReverse(&order)) { For (Windows) {
if (!it->visible) continue; if (!it->visible) continue;
View *view = GetView(it->active_view); View *view = GetView(it->active_view);
UpdateScroll(it, !AreEqual(view->main_caret_on_begin_frame, view->carets[0]) && view->update_scroll); UpdateScroll(it, !AreEqual(view->main_caret_on_begin_frame, view->carets[0]) && view->update_scroll);
@@ -783,13 +785,13 @@ void Update(Event event) {
GarbageCollect(); GarbageCollect();
} }
Array<Event> FrameEvents;
void MainLoop() { void MainLoop() {
ProfileFunction(); ProfileFunction();
Scratch scratch;
FrameID += 1; FrameID += 1;
Array<Event> frame_events = GetEventsForFrame(scratch); FrameEvents.len = 0;
For(frame_events) { GetEventsForFrame(&FrameEvents);
For (FrameEvents) {
#if PLUGIN_RECORD_EVENTS #if PLUGIN_RECORD_EVENTS
if (it.kind != EVENT_UPDATE && !Testing) { if (it.kind != EVENT_UPDATE && !Testing) {
Serialize(EventBuffer, &it); Serialize(EventBuffer, &it);
@@ -823,6 +825,7 @@ void MainLoop() {
// This shouldn't matter to the state of the program, only appearance for // This shouldn't matter to the state of the program, only appearance for
// the user // the user
{ {
Scratch scratch;
ProfileScope(SetWindowTitle); ProfileScope(SetWindowTitle);
Window *window = GetActiveWind(); Window *window = GetActiveWind();
View *view = GetView(window->active_view); View *view = GetView(window->active_view);
@@ -832,15 +835,18 @@ void MainLoop() {
SDL_SetWindowTitle(SDLWindow, string.data); SDL_SetWindowTitle(SDLWindow, string.data);
} }
Event *event = GetLast(frame_events); Event *event = GetLast(FrameEvents);
SetMouseCursor(*event); SetMouseCursor(*event);
LayoutWindows(event->xwindow, event->ywindow); // This is here to render changes in title bar size without a frame of delay LayoutWindows(event->xwindow, event->ywindow); // This is here to render changes in title bar size without a frame of delay
BeginFrameRender(event->xwindow, event->ywindow); BeginFrameRender(event->xwindow, event->ywindow);
Array<Window *> order = GetWindowZOrder(scratch); {
For(IterateInReverse(&order)) { Scratch scratch;
if (!it->visible) continue; Array<Window *> order = GetWindowZOrder(scratch);
DrawWindow(it, *GetLast(frame_events)); For(IterateInReverse(&order)) {
if (!it->visible) continue;
DrawWindow(it, *GetLast(FrameEvents));
}
} }
EndFrameRender(event->xwindow, event->ywindow, BackgroundColor); EndFrameRender(event->xwindow, event->ywindow, BackgroundColor);
SDL_GL_SwapWindow(SDLWindow); SDL_GL_SwapWindow(SDLWindow);