From 5577b5a6a83c57fac2a88a9ba8e107f1ba8674ee Mon Sep 17 00:00:00 2001 From: zetaPRIME Date: Wed, 3 May 2017 04:19:30 -0400 Subject: [PATCH] threads now end cleanly, and do so on exit --- libstarlight/source/starlight/Application.cpp | 12 ++++++++-- .../source/starlight/threading/Thread.cpp | 23 ++++++++++++++++++- .../source/starlight/threading/Thread.h | 2 ++ libstarlight/todo.txt | 3 ++- 4 files changed, 36 insertions(+), 4 deletions(-) diff --git a/libstarlight/source/starlight/Application.cpp b/libstarlight/source/starlight/Application.cpp index edeed83..506b9de 100644 --- a/libstarlight/source/starlight/Application.cpp +++ b/libstarlight/source/starlight/Application.cpp @@ -17,6 +17,9 @@ using starlight::ThemeManager; using starlight::InputManager; using starlight::gfx::RenderCore; +using starlight::threading::Thread; +using starlight::threading::ThreadState; + using starlight::ui::TouchScreenCanvas; using starlight::ui::TopScreenCanvas; @@ -83,6 +86,9 @@ void Application::_init() { void Application::_end() { End(); + for (auto& thread : threads) thread->Exit(); + threads.clear(); + //for (auto& f : forms) f->Close(); forms.clear(); // not sure why, but not doing this results in a data abort if any forms are active @@ -159,8 +165,10 @@ void Application::_mainLoop() { RenderCore::EndFrame(); while (!threads.empty() && frameTimer.GetSubframe() < 0.9) { - threads.front()->Resume(); - if (threads.size() > 1) threads.splice(threads.end(), threads, threads.begin()); // move to back of queue + auto thread = threads.front(); + thread->Resume(); + if (thread->state != ThreadState::Finished) threads.splice(threads.end(), threads, threads.begin()); // move to back of queue + else threads.pop_front(); // or just discard if already exited } } diff --git a/libstarlight/source/starlight/threading/Thread.cpp b/libstarlight/source/starlight/threading/Thread.cpp index 66adf77..cb40c04 100644 --- a/libstarlight/source/starlight/threading/Thread.cpp +++ b/libstarlight/source/starlight/threading/Thread.cpp @@ -37,6 +37,9 @@ void Thread::_FinishStart() { state = ThreadState::Running; Yield(); Body(); + state = ThreadState::Finished; + OnExit(); + threadExit(0); } void Thread::Yield() { @@ -45,12 +48,30 @@ void Thread::Yield() { svcWaitSynchronization(event, -1 /*U64_MAX*/); //svcWaitSynchronization(event, 65536); svcClearEvent(event); + if (state == ThreadState::Finished && OnExit()) { + threadExit(0); + } state = ThreadState::Running; } +void Thread::Exit() { + if (state == ThreadState::Idle) { // exited from outside + state = ThreadState::Finished; + Resume(); + threadJoin(static_cast(sthread), -1); + } else if (state == ThreadState::Running) { // exited self + state = ThreadState::Finished; + OnExit(); + threadExit(0); + } + +} + void Thread::Resume() { - if (state != ThreadState::Idle) return; // not applicable + if (state != ThreadState::Idle && state != ThreadState::Finished) return; // not applicable svcSignalEvent(event); } +bool Thread::OnExit() { return true; } // default to "trivial" (no cleanup necessary) + // diff --git a/libstarlight/source/starlight/threading/Thread.h b/libstarlight/source/starlight/threading/Thread.h index c950767..3fc6fc4 100644 --- a/libstarlight/source/starlight/threading/Thread.h +++ b/libstarlight/source/starlight/threading/Thread.h @@ -30,8 +30,10 @@ namespace starlight { void Enqueue(); void Yield(); void Resume(); + void Exit(); virtual void Body() = 0; + virtual bool OnExit(); }; } } diff --git a/libstarlight/todo.txt b/libstarlight/todo.txt index 402423a..50746aa 100644 --- a/libstarlight/todo.txt +++ b/libstarlight/todo.txt @@ -25,7 +25,8 @@ roadmap to v0.5.1 { ...and some mechanism for allowing it to opt out of the rest of the cycle Trackable sideclass for threads; float progress 0..1, etc. - MAKE THREADS END CLEANLY + - MAKE THREADS END CLEANLY + ^ observed a single instance of being stalled on redscreen, not really sure what that was about } } then by v0.5.5 { event propagation system of some sort; threadsafe to whatever extent is needed on 3DS