From bf7dc84893023bd34250c6bb619d8b2508d35746 Mon Sep 17 00:00:00 2001 From: Michael Scire Date: Wed, 5 Dec 2018 04:16:48 -0800 Subject: [PATCH] tma: first pass at TmaServiceManager --- .../tma/source/tma_conn_connection.cpp | 20 +- .../tma/source/tma_conn_connection.hpp | 10 + stratosphere/tma/source/tma_conn_packet.hpp | 13 + .../tma/source/tma_conn_usb_connection.cpp | 6 +- stratosphere/tma/source/tma_service.cpp | 4 +- stratosphere/tma/source/tma_service.hpp | 8 +- .../tma/source/tma_service_manager.cpp | 402 ++++++++++++++++++ .../tma/source/tma_service_manager.hpp | 109 +++++ stratosphere/tma/source/tma_task.cpp | 7 +- stratosphere/tma/source/tma_task_list.cpp | 35 ++ stratosphere/tma/source/tma_task_list.hpp | 3 +- 11 files changed, 595 insertions(+), 22 deletions(-) create mode 100644 stratosphere/tma/source/tma_service_manager.cpp create mode 100644 stratosphere/tma/source/tma_service_manager.hpp diff --git a/stratosphere/tma/source/tma_conn_connection.cpp b/stratosphere/tma/source/tma_conn_connection.cpp index 23337b2b2..3cc571365 100644 --- a/stratosphere/tma/source/tma_conn_connection.cpp +++ b/stratosphere/tma/source/tma_conn_connection.cpp @@ -17,25 +17,23 @@ #include #include #include "tma_conn_connection.hpp" +#include "tma_service_manager.hpp" /* Packet management. */ TmaPacket *TmaConnection::AllocateSendPacket() { - /* TODO: Service Manager. */ - return new TmaPacket(); + return this->service_manager->AllocateSendPacket(); } TmaPacket *TmaConnection::AllocateRecvPacket() { - /* TODO: Service Manager. */ - return new TmaPacket(); + return this->service_manager->AllocateRecvPacket(); } void TmaConnection::FreePacket(TmaPacket *packet) { - /* TODO: Service Manager. */ - delete packet; + this->service_manager->FreePacket(packet); } void TmaConnection::OnReceivePacket(TmaPacket *packet) { - /* TODO: Service Manager. */ + this->service_manager->OnReceivePacket(packet); } void TmaConnection::OnDisconnected() { @@ -43,7 +41,9 @@ void TmaConnection::OnDisconnected() { std::abort(); } - /* TODO: Service Manager. */ + if (this->service_manager != nullptr) { + this->service_manager->OnDisconnect(); + } this->has_woken_up = false; this->OnConnectionEvent(ConnectionEvent::Disconnected); @@ -56,9 +56,9 @@ void TmaConnection::OnConnectionEvent(ConnectionEvent event) { } void TmaConnection::CancelTasks() { - /* TODO: Service Manager. */ + this->service_manager->CancelTasks(); } void TmaConnection::Tick() { - /* TODO: Service Manager. */ + this->service_manager->Tick(); } diff --git a/stratosphere/tma/source/tma_conn_connection.hpp b/stratosphere/tma/source/tma_conn_connection.hpp index 4cf3cabe3..3c5f39bcd 100644 --- a/stratosphere/tma/source/tma_conn_connection.hpp +++ b/stratosphere/tma/source/tma_conn_connection.hpp @@ -26,6 +26,9 @@ enum class ConnectionEvent : u32 { Disconnected }; + +class TmaServiceManager; + class TmaConnection { protected: HosMutex lock; @@ -33,6 +36,7 @@ class TmaConnection { void *connection_event_arg = nullptr; bool has_woken_up = false; bool is_initialized = false; + TmaServiceManager *service_manager = nullptr; protected: void OnReceivePacket(TmaPacket *packet); void OnDisconnected(); @@ -66,10 +70,16 @@ class TmaConnection { } } + void SetServiceManager(TmaServiceManager *manager) { this->service_manager = manager; } + /* Packet management. */ TmaPacket *AllocateSendPacket(); TmaPacket *AllocateRecvPacket(); void FreePacket(TmaPacket *packet); + + /* Sleep management. */ + bool HasWokenUp() const { return this->has_woken_up; } + void SetWokenUp(bool woke) { this->has_woken_up = woke; } /* For sub-interfaces to implement, connection management. */ virtual void StartListening() { } diff --git a/stratosphere/tma/source/tma_conn_packet.hpp b/stratosphere/tma/source/tma_conn_packet.hpp index 0b2593876..a3df7a3f3 100644 --- a/stratosphere/tma/source/tma_conn_packet.hpp +++ b/stratosphere/tma/source/tma_conn_packet.hpp @@ -43,6 +43,7 @@ class TmaPacket { private: std::unique_ptr buffer = std::make_unique(MaxPacketSize); u32 offset = 0; + HosMessageQueue *free_queue = nullptr; Header *GetHeader() const { return reinterpret_cast
(buffer.get()); @@ -95,6 +96,14 @@ class TmaPacket { } } + HosMessageQueue *GetFreeQueue() const { + return this->free_queue; + } + + void SetFreeQueue(HosMessageQueue *queue) { + this->free_queue = queue; + } + void SetChecksums() { Header *hdr = GetHeader(); if (hdr->body_len) { @@ -161,6 +170,10 @@ class TmaPacket { this->offset = 0; } + void SetBodyLength() { + GetHeader()->body_len = this->offset; + } + TmaConnResult Write(const void *data, size_t size) { if (size > GetBodyAvailableLength()) { return TmaConnResult::PacketOverflow; diff --git a/stratosphere/tma/source/tma_conn_usb_connection.cpp b/stratosphere/tma/source/tma_conn_usb_connection.cpp index ba6ecd349..ed7c2f707 100644 --- a/stratosphere/tma/source/tma_conn_usb_connection.cpp +++ b/stratosphere/tma/source/tma_conn_usb_connection.cpp @@ -88,7 +88,7 @@ void TmaUsbConnection::RecvThreadFunc(void *arg) { res = this_ptr->SendQueryReply(packet); if (!this_ptr->has_woken_up) { - /* TODO: Cancel background work. */ + this_ptr->CancelTasks(); } } break; @@ -100,7 +100,7 @@ void TmaUsbConnection::RecvThreadFunc(void *arg) { packet->Read(host_info); if (!this_ptr->has_woken_up || !host_info.sleeping) { - /* TODO: Cancel background work. */ + this_ptr->CancelTasks(); } } break; @@ -117,7 +117,7 @@ void TmaUsbConnection::RecvThreadFunc(void *arg) { this_ptr->SetConnected(false); this_ptr->OnDisconnected(); - /* TODO: Cancel background work. */ + this_ptr->CancelTasks(); } break; default: diff --git a/stratosphere/tma/source/tma_service.cpp b/stratosphere/tma/source/tma_service.cpp index 963d6e6d5..8a70701c8 100644 --- a/stratosphere/tma/source/tma_service.cpp +++ b/stratosphere/tma/source/tma_service.cpp @@ -17,10 +17,10 @@ #include #include #include "tma_service.hpp" +#include "tma_service_manager.hpp" u32 TmaService::GetNextTaskId() { - /* TODO: Service Manager */ - return 0; + return this->manager->GetNextTaskId(); } void TmaService::OnSleep() { diff --git a/stratosphere/tma/source/tma_service.hpp b/stratosphere/tma/source/tma_service.hpp index 17ab8215b..e9b0d53e3 100644 --- a/stratosphere/tma/source/tma_service.hpp +++ b/stratosphere/tma/source/tma_service.hpp @@ -31,13 +31,13 @@ class TmaService { const TmaServiceId id; protected: u32 GetNextTaskId(); - virtual TmaTask *NewTask(TmaPacket *packet) = 0; - - virtual void OnSleep(); - virtual void OnWake(); public: TmaService(TmaServiceManager *m, const char *n) : manager(m), service_name(n), id(static_cast(HashServiceName(this->service_name))) { } virtual ~TmaService() { } TmaServiceId GetServiceId() const { return this->id; } + + virtual TmaTask *NewTask(TmaPacket *packet) = 0; + virtual void OnSleep(); + virtual void OnWake(); }; diff --git a/stratosphere/tma/source/tma_service_manager.cpp b/stratosphere/tma/source/tma_service_manager.cpp new file mode 100644 index 000000000..0012944d8 --- /dev/null +++ b/stratosphere/tma/source/tma_service_manager.cpp @@ -0,0 +1,402 @@ +/* + * Copyright (c) 2018 Atmosphère-NX + * + * This program is free software; you can redistribute it and/or modify it + * under the terms and conditions of the GNU General Public License, + * version 2, as published by the Free Software Foundation. + * + * This program is distributed in the hope it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +#include +#include +#include "tma_service_manager.hpp" + +TmaServiceManager::TmaServiceManager() { + /* Set up queues */ + for (size_t i = 0; i < TmaServiceManager::PacketQueueDepth; i++) { + TmaPacket *packet = nullptr; + + packet = new TmaPacket(); + packet->SetFreeQueue(&this->free_send_packet_queue); + this->free_send_packet_queue.Send(reinterpret_cast(packet)); + packet = nullptr; + + packet = new TmaPacket(); + packet->SetFreeQueue(&this->free_recv_packet_queue); + this->free_recv_packet_queue.Send(reinterpret_cast(packet)); + packet = nullptr; + } + for (size_t i = 0; i < TmaServiceManager::WorkQueueDepth; i++) { + this->free_work_queue.Send(reinterpret_cast(new TmaWorkItem())); + } +} + +TmaServiceManager::~TmaServiceManager() { + /* Destroy queues. */ + TmaPacket *packet = nullptr; + while (this->free_send_packet_queue.TryReceive(reinterpret_cast(&packet))) { + delete packet; + packet = nullptr; + } + while (this->free_recv_packet_queue.TryReceive(reinterpret_cast(&packet))) { + delete packet; + packet = nullptr; + } + + TmaWorkItem *work_item = nullptr; + while (this->free_work_queue.TryReceive(reinterpret_cast(&work_item))) { + delete work_item; + work_item = nullptr; + } + while (this->work_queue.TryReceive(reinterpret_cast(&work_item))) { + delete work_item; + work_item = nullptr; + } +} + +void TmaServiceManager::Initialize() { + this->initialized = true; + this->work_thread.Initialize(TmaServiceManager::WorkThread, this, 0x4000, 0x26); + this->work_thread.Start(); +} + +void TmaServiceManager::Finalize() { + if (this->initialized) { + this->initialized = false; + if (this->connection && this->connection->IsConnected()) { + this->connection->Disconnect(); + } + + /* Signal to work thread to end. */ + this->work_queue.Send(reinterpret_cast(nullptr)); + this->work_thread.Join(); + + /* TODO: N tells services that they have no manager here. Do we want to do that? */ + } +} + +void TmaServiceManager::AddWork(TmaWorkType type, TmaTask *task, TmaPacket *packet) { + if (!this->initialized) { + std::abort(); + } + + TmaWorkItem *work_item = nullptr; + this->free_work_queue.Receive(reinterpret_cast(&work_item)); + + work_item->task = task; + work_item->packet = packet; + work_item->work_type = type; +} + +/* Packet management. */ +TmaConnResult TmaServiceManager::SendPacket(TmaPacket *packet) { + TmaConnResult res = TmaConnResult::Disconnected; + + if (this->connection != nullptr) { + res = this->connection->SendPacket(packet); + } + + return res; +} + + +void TmaServiceManager::OnReceivePacket(TmaPacket *packet) { + this->AddWork(TmaWorkType::ReceivePacket, nullptr, packet); +} + +TmaPacket *TmaServiceManager::AllocateSendPacket() { + if (!this->initialized) { + std::abort(); + } + + TmaPacket *packet = nullptr; + this->free_send_packet_queue.Receive(reinterpret_cast(&packet)); + + packet->ClearOffset(); + packet->SetBodyLength(); + + return packet; +} + +TmaPacket *TmaServiceManager::AllocateRecvPacket() { + if (!this->initialized) { + std::abort(); + } + + TmaPacket *packet = nullptr; + this->free_recv_packet_queue.Receive(reinterpret_cast(&packet)); + + packet->ClearOffset(); + + return packet; +} + +void TmaServiceManager::FreePacket(TmaPacket *packet) { + if (!this->initialized) { + std::abort(); + } + + if (packet != nullptr) { + packet->GetFreeQueue()->Send(reinterpret_cast(packet)); + } +} + + +/* Service/task management. */ +TmaService *TmaServiceManager::GetServiceById(TmaServiceId id) { + std::scoped_lock lk(this->lock); + + for (auto srv : this->services) { + if (srv->GetServiceId() == id) { + return srv; + } + } + + return nullptr; +} + +void TmaServiceManager::AddService(TmaService *service) { + std::scoped_lock lk(this->lock); + + this->services.push_back(service); +} + +void TmaServiceManager::AddTask(TmaTask *task, TmaPacket *packet) { + this->AddWork(TmaWorkType::NewTask, task, packet); +} + +void TmaServiceManager::FreeTask(TmaTask *task) { + this->AddWork(TmaWorkType::FreeTask, task, nullptr); +} + +void TmaServiceManager::CancelTask(u32 task_id) { + if (this->initialized) { + this->task_list.Cancel(task_id); + } +} + +void TmaServiceManager::CancelTasks() { + if (this->initialized) { + this->task_list.CancelAll(); + } +} + +u32 TmaServiceManager::GetNextTaskId() { + while (true) { + u32 id; + { + /* N only uses 16 bits for the task id. We'll use 24. */ + std::scoped_lock lk(this->lock); + id = (this->next_task_id++) & 0xFFFFFF; + } + + if (this->task_list.IsIdFree(id)) { + return id; + } + } +} + +/* Connection management. */ +void TmaServiceManager::Tick() { + this->AddWork(TmaWorkType::Tick, nullptr, nullptr); +} + +void TmaServiceManager::SetConnection(TmaConnection *conn) { + this->connection = conn; +} + +void TmaServiceManager::OnDisconnect() { + if (!this->initialized) { + std::abort(); + } + + if (!this->GetAsleep()) { + this->disconnect_signal.Reset(); + + this->AddWork(TmaWorkType::Disconnect, nullptr, nullptr); + + /* TODO: why does N wait with a timeout of zero here? */ + this->disconnect_signal.Wait(); + } +} + +void TmaServiceManager::Sleep() { + if (!this->initialized) { + std::abort(); + } + + if (!this->GetAsleep()) { + this->wake_signal.Reset(); + this->sleep_signal.Reset(); + + /* Tell the work thread to stall, wait for ACK. */ + this->AddWork(TmaWorkType::Sleep, nullptr, nullptr); + this->sleep_signal.Wait(); + + this->SetAsleep(true); + } +} + +void TmaServiceManager::Wake(TmaConnection *conn) { + if (this->connection != nullptr) { + std::abort(); + } + if (this->GetAsleep()) { + this->connection = conn; + this->connection->SetWokenUp(true); + this->connection->SetServiceManager(this); + /* Tell the work thread to resume. */ + this->wake_signal.Signal(); + } +} + +bool TmaServiceManager::GetConnected() const { + return this->connection != nullptr && this->connection->IsConnected(); +} + +/* Work thread. */ +void TmaServiceManager::WorkThread(void *_this) { + TmaServiceManager *this_ptr = reinterpret_cast(_this); + if (!this_ptr->initialized) { + std::abort(); + } + + while (true) { + /* Receive a work item. */ + TmaWorkItem *work_item = nullptr; + this_ptr->work_queue.Receive(reinterpret_cast(&work_item)); + + if (work_item == nullptr) { + /* We're done. */ + this_ptr->task_list.CancelAll(); + break; + } + + switch (work_item->work_type) { + case TmaWorkType::Tick: + /* HandleTickWork called unconditionally. */ + break; + case TmaWorkType::NewTask: + this_ptr->HandleNewTaskWork(work_item); + break; + case TmaWorkType::FreeTask: + this_ptr->HandleFreeTaskWork(work_item); + break; + case TmaWorkType::ReceivePacket: + this_ptr->HandleReceivePacketWork(work_item); + break; + case TmaWorkType::Disconnect: + this_ptr->HandleDisconnectWork(); + break; + case TmaWorkType::Sleep: + this_ptr->HandleSleepWork(); + break; + case TmaWorkType::None: + default: + std::abort(); + break; + } + + this_ptr->free_work_queue.Send(reinterpret_cast(work_item)); + this_ptr->HandleTickWork(); + } +} + +void TmaServiceManager::HandleNewTaskWork(TmaWorkItem *work_item) { + this->task_list.Add(work_item->task); + if (this->GetConnected()) { + if (work_item->packet != nullptr) { + this->SendPacket(work_item->packet); + } + } else { + work_item->task->Cancel(); + this->FreePacket(work_item->packet); + } +} + +void TmaServiceManager::HandleFreeTaskWork(TmaWorkItem *work_item) { + delete work_item->task; +} + +void TmaServiceManager::HandleReceivePacketWork(TmaWorkItem *work_item) { + /* Handle continuation packets. */ + if (work_item->packet->GetContinuation()) { + this->task_list.ReceivePacket(work_item->packet); + return; + } + + /* Make a new task for the packet. */ + TmaService *srv = this->GetServiceById(work_item->packet->GetServiceId()); + if (srv != nullptr) { + TmaTask *task = srv->NewTask(work_item->packet); + if (task != nullptr) { + this->task_list.Add(task); + } + } +} + +void TmaServiceManager::HandleTickWork() { + if (this->connection == nullptr) { + std::abort(); + } + + /* N does this kind of manual cleanup if send isn't called. */ + /* It's pretty gross, but in lieu of a better idea... */ + bool needs_manual_cleanup = true; + + TmaPacket *packet = nullptr; + + while (this->connection != nullptr && this->free_send_packet_queue.TryReceive(reinterpret_cast(&packet))) { + needs_manual_cleanup = false; + + if (this->task_list.SendPacket(this->GetConnected(), packet)) { + if (this->SendPacket(packet) != TmaConnResult::Success) { + break; + } + } else { + this->FreePacket(packet); + break; + } + } + + if (needs_manual_cleanup) { + this->task_list.CleanupDoneTasks(); + } +} + +void TmaServiceManager::HandleDisconnectWork() { + this->task_list.CancelAll(); + this->disconnect_signal.Signal(); +} + +void TmaServiceManager::HandleSleepWork() { + /* Put the task list to sleep. */ + this->task_list.Sleep(); + + /* Put services to sleep. */ + for (auto srv : this->services) { + srv->OnSleep(); + } + + /* Signal to main thread that we're sleeping. */ + this->sleep_signal.Signal(); + /* Wait for us to wake up. */ + this->wake_signal.Wait(); + + /* We're awake now... */ + + /* Wake up services. */ + for (auto srv : this->services) { + srv->OnWake(); + } + + /* Wake up the task list. */ + this->task_list.Wake(); +} diff --git a/stratosphere/tma/source/tma_service_manager.hpp b/stratosphere/tma/source/tma_service_manager.hpp new file mode 100644 index 000000000..ac6ccc5e3 --- /dev/null +++ b/stratosphere/tma/source/tma_service_manager.hpp @@ -0,0 +1,109 @@ +/* + * Copyright (c) 2018 Atmosphère-NX + * + * This program is free software; you can redistribute it and/or modify it + * under the terms and conditions of the GNU General Public License, + * version 2, as published by the Free Software Foundation. + * + * This program is distributed in the hope it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +#pragma once +#include +#include + +#include "tma_conn_service_ids.hpp" +#include "tma_conn_packet.hpp" +#include "tma_task.hpp" +#include "tma_service.hpp" +#include "tma_task_list.hpp" +#include "tma_conn_connection.hpp" + +enum class TmaWorkType : u32 { + None, + NewTask, + FreeTask, + ReceivePacket, + Tick, + Disconnect, + Sleep, +}; + +struct TmaWorkItem { + TmaTask *task; + TmaPacket *packet; + TmaWorkType work_type; +}; + +class TmaServiceManager { + public: + static constexpr size_t PacketQueueDepth = 0x8; + static constexpr size_t WorkQueueDepth = 0x80; + private: + HosMutex lock; + bool initialized = false; + TmaTaskList task_list; + HosThread work_thread; + std::vector services; + TmaConnection *connection = nullptr; + u32 next_task_id = 0; + + /* Work queues. */ + HosMessageQueue free_send_packet_queue = HosMessageQueue(PacketQueueDepth); + HosMessageQueue free_recv_packet_queue = HosMessageQueue(PacketQueueDepth); + HosMessageQueue work_queue = HosMessageQueue(WorkQueueDepth); + HosMessageQueue free_work_queue = HosMessageQueue(WorkQueueDepth); + + /* Sleep management. */ + HosSignal disconnect_signal; + HosSignal wake_signal; + HosSignal sleep_signal; + bool asleep = false; + private: + static void WorkThread(void *arg); + void AddWork(TmaWorkType type, TmaTask *task, TmaPacket *packet); + void HandleNewTaskWork(TmaWorkItem *work_item); + void HandleFreeTaskWork(TmaWorkItem *work_item); + void HandleReceivePacketWork(TmaWorkItem *work_item); + void HandleTickWork(); + void HandleDisconnectWork(); + void HandleSleepWork(); + + void SetAsleep(bool s) { this->asleep = s; } + public: + TmaServiceManager(); + virtual ~TmaServiceManager(); + void Initialize(); + void Finalize(); + + /* Packet management. */ + TmaConnResult SendPacket(TmaPacket *packet); + void OnReceivePacket(TmaPacket *packet); + TmaPacket *AllocateSendPacket(); + TmaPacket *AllocateRecvPacket(); + void FreePacket(TmaPacket *packet); + + /* Service/task management. */ + TmaService *GetServiceById(TmaServiceId id); + void AddService(TmaService *service); + void AddTask(TmaTask *task, TmaPacket *packet); + void FreeTask(TmaTask *task); + void CancelTask(u32 task_id); + void CancelTasks(); + u32 GetNextTaskId(); + + /* Connection management. */ + void Tick(); + void SetConnection(TmaConnection *conn); + void OnDisconnect(); + void Sleep(); + void Wake(TmaConnection *conn); + bool GetAsleep() const { return this->asleep; } + bool GetConnected() const; +}; diff --git a/stratosphere/tma/source/tma_task.cpp b/stratosphere/tma/source/tma_task.cpp index 5c9c863b6..a9450be76 100644 --- a/stratosphere/tma/source/tma_task.cpp +++ b/stratosphere/tma/source/tma_task.cpp @@ -17,13 +17,16 @@ #include #include #include "tma_task.hpp" +#include "tma_service_manager.hpp" void TmaTask::Complete() { - /* TODO: Service manager */ + /* TODO: Set packet state */ this->state = TmaTaskState::Complete; + this->manager->Tick(); } void TmaTask::Cancel() { - /* TODO: Service manager */ + /* TODO: Set packet state */ this->state = TmaTaskState::Canceled; + this->manager->Tick(); } \ No newline at end of file diff --git a/stratosphere/tma/source/tma_task_list.cpp b/stratosphere/tma/source/tma_task_list.cpp index 2c8ac5b48..2cb28b487 100644 --- a/stratosphere/tma/source/tma_task_list.cpp +++ b/stratosphere/tma/source/tma_task_list.cpp @@ -52,6 +52,11 @@ u32 TmaTaskList::GetNumSleepingTasks() const { return count; } +bool TmaTaskList::IsIdFree(u32 task_id) const { + std::scoped_lock lk(this->lock); + return GetById(task_id) == nullptr; +} + bool TmaTaskList::SendPacket(bool connected, TmaPacket *packet) { std::scoped_lock lk(this->lock); @@ -112,6 +117,36 @@ bool TmaTaskList::ReceivePacket(TmaPacket *packet) { return task != nullptr; } + +void TmaTaskList::CleanupDoneTasks() { + std::scoped_lock lk(this->lock); + + /* Clean up all tasks in Complete/Canceled state. */ + for (u32 i = 0; i < TmaTask::NumPriorities; i++) { + auto it = this->tasks[i].begin(); + while (it != this->tasks[i].end()) { + auto task = *it; + switch (task->GetState()) { + case TmaTaskState::InProgress: + it++; + break; + case TmaTaskState::Complete: + case TmaTaskState::Canceled: + it = this->tasks[i].erase(it); + if (task->GetOwnedByTaskList()) { + delete task; + } else { + task->Signal(); + } + break; + default: + /* TODO: Panic to fatal? */ + std::abort(); + } + } + } +} + void TmaTaskList::Add(TmaTask *task) { std::scoped_lock lk(this->lock); diff --git a/stratosphere/tma/source/tma_task_list.hpp b/stratosphere/tma/source/tma_task_list.hpp index bfad0e6ca..e29ddb274 100644 --- a/stratosphere/tma/source/tma_task_list.hpp +++ b/stratosphere/tma/source/tma_task_list.hpp @@ -36,10 +36,11 @@ class TmaTaskList { u32 GetNumTasks() const; u32 GetNumSleepingTasks() const; + bool IsIdFree(u32 task_id) const; bool SendPacket(bool connected, TmaPacket *packet); bool ReceivePacket(TmaPacket *packet); - + void CleanupDoneTasks(); void Add(TmaTask *task); void Cancel(u32 task_id); void CancelAll();