mirror of
https://github.com/Atmosphere-NX/Atmosphere.git
synced 2024-11-05 19:51:45 +00:00
libstratosphere: Add thread primitive, WaitableManager->RequestStop()
This commit is contained in:
parent
e65bee0d6a
commit
9b1a2451b0
3 changed files with 109 additions and 50 deletions
|
@ -186,3 +186,30 @@ class TimeoutHelper {
|
|||
return armGetSystemTick() >= this->end_tick;
|
||||
}
|
||||
};
|
||||
|
||||
class HosThread {
|
||||
private:
|
||||
Thread thr = {0};
|
||||
public:
|
||||
HosThread() {}
|
||||
|
||||
Result Initialize(ThreadFunc entry, void *arg, size_t stack_sz, int prio, int cpuid = -2) {
|
||||
return threadCreate(&this->thr, entry, arg, stack_sz, prio, cpuid);
|
||||
}
|
||||
|
||||
Handle GetHandle() const {
|
||||
return this->thr.handle;
|
||||
}
|
||||
|
||||
Result Start() {
|
||||
return threadStart(&this->thr);
|
||||
}
|
||||
|
||||
Result Join() {
|
||||
Result rc = threadWaitForExit(&this->thr);
|
||||
if (R_SUCCEEDED(rc)) {
|
||||
rc = threadClose(&this->thr);
|
||||
}
|
||||
return rc;
|
||||
}
|
||||
};
|
|
@ -56,30 +56,34 @@ class WaitableManager : public SessionManagerBase {
|
|||
std::vector<IWaitable *> to_add_waitables;
|
||||
std::vector<IWaitable *> waitables;
|
||||
std::vector<IWaitable *> deferred_waitables;
|
||||
u32 num_threads;
|
||||
Thread *threads;
|
||||
|
||||
u32 num_extra_threads = 0;
|
||||
HosThread *threads = nullptr;
|
||||
|
||||
HosMutex process_lock;
|
||||
HosMutex signal_lock;
|
||||
HosMutex add_lock;
|
||||
HosMutex cur_thread_lock;
|
||||
HosMutex deferred_lock;
|
||||
bool has_new_waitables = false;
|
||||
std::atomic<bool> should_stop = false;
|
||||
|
||||
IWaitable *next_signaled = nullptr;
|
||||
Handle main_thread_handle = INVALID_HANDLE;
|
||||
Handle cur_thread_handle = INVALID_HANDLE;
|
||||
public:
|
||||
WaitableManager(u32 n, u32 ss = 0x8000) : num_threads(n-1) {
|
||||
WaitableManager(u32 n, u32 ss = 0x8000) : num_extra_threads(n-1) {
|
||||
u32 prio;
|
||||
u32 cpuid = svcGetCurrentProcessorNumber();
|
||||
Result rc;
|
||||
threads = new Thread[num_threads];
|
||||
if (num_threads) {
|
||||
if (num_extra_threads) {
|
||||
threads = new HosThread[num_extra_threads];
|
||||
if (R_FAILED((rc = svcGetThreadPriority(&prio, CUR_THREAD_HANDLE)))) {
|
||||
fatalSimple(rc);
|
||||
}
|
||||
for (unsigned int i = 0; i < num_threads; i++) {
|
||||
threads[i] = {0};
|
||||
threadCreate(&threads[i], &WaitableManager::ProcessLoop, this, ss, prio, cpuid);
|
||||
for (unsigned int i = 0; i < num_extra_threads; i++) {
|
||||
if (R_FAILED(threads[i].Initialize(&WaitableManager::ProcessLoop, this, ss, prio))) {
|
||||
std::abort();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -90,7 +94,7 @@ class WaitableManager : public SessionManagerBase {
|
|||
std::for_each(waitables.begin(), waitables.end(), std::default_delete<IWaitable>{});
|
||||
std::for_each(deferred_waitables.begin(), deferred_waitables.end(), std::default_delete<IWaitable>{});
|
||||
|
||||
/* TODO: Exit the threads? */
|
||||
/* If we've reached here, we should already have exited the threads. */
|
||||
}
|
||||
|
||||
virtual void AddWaitable(IWaitable *w) override {
|
||||
|
@ -101,6 +105,11 @@ class WaitableManager : public SessionManagerBase {
|
|||
this->CancelSynchronization();
|
||||
}
|
||||
|
||||
virtual void RequestStop() {
|
||||
this->should_stop = true;
|
||||
this->CancelSynchronization();
|
||||
}
|
||||
|
||||
virtual void CancelSynchronization() {
|
||||
svcCancelSynchronization(GetProcessingThreadHandle());
|
||||
}
|
||||
|
@ -117,9 +126,12 @@ class WaitableManager : public SessionManagerBase {
|
|||
/* Add initial set of waitables. */
|
||||
AddWaitablesInternal();
|
||||
|
||||
/* Set main thread handle. */
|
||||
this->main_thread_handle = GetCurrentThreadHandle();
|
||||
|
||||
Result rc;
|
||||
for (unsigned int i = 0; i < num_threads; i++) {
|
||||
if (R_FAILED((rc = threadStart(&threads[i])))) {
|
||||
for (unsigned int i = 0; i < num_extra_threads; i++) {
|
||||
if (R_FAILED((rc = threads[i].Start()))) {
|
||||
fatalSimple(rc);
|
||||
}
|
||||
}
|
||||
|
@ -141,6 +153,17 @@ class WaitableManager : public SessionManagerBase {
|
|||
WaitableManager *this_ptr = (WaitableManager *)t;
|
||||
while (true) {
|
||||
IWaitable *w = this_ptr->GetWaitable();
|
||||
if (this_ptr->should_stop) {
|
||||
if (GetCurrentThreadHandle() == this_ptr->main_thread_handle) {
|
||||
/* Join all threads but the main one. */
|
||||
for (unsigned int i = 0; i < this_ptr->num_extra_threads; i++) {
|
||||
this_ptr->threads[i].Join();
|
||||
}
|
||||
break;
|
||||
} else {
|
||||
svcExitThread();
|
||||
}
|
||||
}
|
||||
if (w) {
|
||||
Result rc = w->HandleSignaled(0);
|
||||
if (rc == 0xF601) {
|
||||
|
@ -195,6 +218,10 @@ class WaitableManager : public SessionManagerBase {
|
|||
this->next_signaled = nullptr;
|
||||
IWaitable *result = nullptr;
|
||||
|
||||
if (this->should_stop) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
/* Add new waitables, if any. */
|
||||
AddWaitablesInternal();
|
||||
|
||||
|
@ -238,6 +265,10 @@ class WaitableManager : public SessionManagerBase {
|
|||
/* Wait forever. */
|
||||
rc = svcWaitSynchronization(&handle_index, handles.data(), num_handles, U64_MAX);
|
||||
|
||||
if (this->should_stop) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
if (R_SUCCEEDED(rc)) {
|
||||
IWaitable *w = wait_list[handle_index];
|
||||
size_t w_ind = std::distance(this->waitables.begin(), std::find(this->waitables.begin(), this->waitables.end(), w));
|
||||
|
|
|
@ -32,6 +32,7 @@ class WaitableManagerBase {
|
|||
virtual void AddWaitable(IWaitable *w) = 0;
|
||||
virtual void NotifySignaled(IWaitable *w) = 0;
|
||||
|
||||
virtual void RequestStop() = 0;
|
||||
virtual void Process() = 0;
|
||||
};
|
||||
|
||||
|
|
Loading…
Reference in a new issue