3
0
Fork 0
forked from suyu/suyu

Kernel: Make WaitObjects share ownership of Threads waiting on them

During normal operation, a thread waiting on an WaitObject and the
object hold mutual references to each other for the duration of the
wait.

If a process is forcefully terminated (The CTR kernel has a SVC to do
this, TerminateProcess, though no equivalent exists for threads.) its
threads would also be stopped and destroyed, leaving dangling pointers
in the WaitObjects.

The solution is to simply have the Thread remove itself from WaitObjects
when it is stopped. The vector of Threads in WaitObject has also been
changed to hold SharedPtrs, just in case. (Better to have a reference
cycle than a crash.)
This commit is contained in:
Yuri Kunde Schlesner 2015-01-31 23:26:16 -02:00
parent 7725256f64
commit 52f58e64ef
6 changed files with 17 additions and 12 deletions

View file

@ -20,10 +20,10 @@ SharedPtr<Thread> g_main_thread = nullptr;
HandleTable g_handle_table; HandleTable g_handle_table;
u64 g_program_id = 0; u64 g_program_id = 0;
void WaitObject::AddWaitingThread(Thread* thread) { void WaitObject::AddWaitingThread(SharedPtr<Thread> thread) {
auto itr = std::find(waiting_threads.begin(), waiting_threads.end(), thread); auto itr = std::find(waiting_threads.begin(), waiting_threads.end(), thread);
if (itr == waiting_threads.end()) if (itr == waiting_threads.end())
waiting_threads.push_back(thread); waiting_threads.push_back(std::move(thread));
} }
void WaitObject::RemoveWaitingThread(Thread* thread) { void WaitObject::RemoveWaitingThread(Thread* thread) {
@ -32,11 +32,11 @@ void WaitObject::RemoveWaitingThread(Thread* thread) {
waiting_threads.erase(itr); waiting_threads.erase(itr);
} }
Thread* WaitObject::WakeupNextThread() { SharedPtr<Thread> WaitObject::WakeupNextThread() {
if (waiting_threads.empty()) if (waiting_threads.empty())
return nullptr; return nullptr;
auto next_thread = waiting_threads.front(); auto next_thread = std::move(waiting_threads.front());
waiting_threads.erase(waiting_threads.begin()); waiting_threads.erase(waiting_threads.begin());
next_thread->ReleaseWaitObject(this); next_thread->ReleaseWaitObject(this);

View file

@ -136,25 +136,26 @@ public:
* Add a thread to wait on this object * Add a thread to wait on this object
* @param thread Pointer to thread to add * @param thread Pointer to thread to add
*/ */
void AddWaitingThread(Thread* thread); void AddWaitingThread(SharedPtr<Thread> thread);
/** /**
* Removes a thread from waiting on this object (e.g. if it was resumed already) * Removes a thread from waiting on this object (e.g. if it was resumed already)
* @param thread Pointer to thread to remove * @param thread Pointer to thread to remove
*/ */
void RemoveWaitingThread(Thread* thead); void RemoveWaitingThread(Thread* thread);
/** /**
* Wake up the next thread waiting on this object * Wake up the next thread waiting on this object
* @return Pointer to the thread that was resumed, nullptr if no threads are waiting * @return Pointer to the thread that was resumed, nullptr if no threads are waiting
*/ */
Thread* WakeupNextThread(); SharedPtr<Thread> WakeupNextThread();
/// Wake up all threads waiting on this object /// Wake up all threads waiting on this object
void WakeupAllWaitingThreads(); void WakeupAllWaitingThreads();
private: private:
std::vector<Thread*> waiting_threads; ///< Threads waiting for this object to become available /// Threads waiting for this object to become available
std::vector<SharedPtr<Thread>> waiting_threads;
}; };
/** /**
@ -275,7 +276,6 @@ private:
}; };
extern HandleTable g_handle_table; extern HandleTable g_handle_table;
extern SharedPtr<Thread> g_main_thread;
/// The ID code of the currently running game /// The ID code of the currently running game
/// TODO(Subv): This variable should not be here, /// TODO(Subv): This variable should not be here,

View file

@ -66,7 +66,7 @@ void Mutex::Acquire() {
Acquire(GetCurrentThread()); Acquire(GetCurrentThread());
} }
void Mutex::Acquire(Thread* thread) { void Mutex::Acquire(SharedPtr<Thread> thread) {
_assert_msg_(Kernel, !ShouldWait(), "object unavailable!"); _assert_msg_(Kernel, !ShouldWait(), "object unavailable!");
if (locked) if (locked)
return; return;
@ -74,7 +74,7 @@ void Mutex::Acquire(Thread* thread) {
locked = true; locked = true;
thread->held_mutexes.insert(this); thread->held_mutexes.insert(this);
holding_thread = thread; holding_thread = std::move(thread);
} }
void Mutex::Release() { void Mutex::Release() {

View file

@ -43,7 +43,7 @@ public:
* @param mutex Mutex that is to be acquired * @param mutex Mutex that is to be acquired
* @param thread Thread that will acquire the mutex * @param thread Thread that will acquire the mutex
*/ */
void Acquire(Thread* thread); void Acquire(SharedPtr<Thread> thread);
void Release(); void Release();
private: private:

View file

@ -110,6 +110,9 @@ void Thread::Stop(const char* reason) {
WakeupAllWaitingThreads(); WakeupAllWaitingThreads();
// Stopped threads are never waiting. // Stopped threads are never waiting.
for (auto& wait_object : wait_objects) {
wait_object->RemoveWaitingThread(this);
}
wait_objects.clear(); wait_objects.clear();
wait_address = 0; wait_address = 0;
} }

View file

@ -134,6 +134,8 @@ private:
Handle callback_handle; Handle callback_handle;
}; };
extern SharedPtr<Thread> g_main_thread;
/// Sets up the primary application thread /// Sets up the primary application thread
SharedPtr<Thread> SetupMainThread(s32 priority, u32 stack_size); SharedPtr<Thread> SetupMainThread(s32 priority, u32 stack_size);