mirror of
https://github.com/Atmosphere-NX/Atmosphere.git
synced 2024-11-05 19:51:45 +00:00
tma: Skeleton Service/Task/TaskList classes.
This commit is contained in:
parent
2572ae8378
commit
bb48e33074
11 changed files with 428 additions and 11 deletions
|
@ -1 +1 @@
|
|||
Subproject commit 05015b9354d3df80e0836aa95d1d4dcfc2aef4b7
|
||||
Subproject commit fa37b70b0eca93be04e18636db25c9443e00d03b
|
|
@ -117,12 +117,12 @@ class TmaPacket {
|
|||
return MaxPacketSize - this->offset;
|
||||
}
|
||||
|
||||
void SetServiceId(TmaService srv) {
|
||||
void SetServiceId(TmaServiceId srv) {
|
||||
GetHeader()->service_id = static_cast<u32>(srv);
|
||||
}
|
||||
|
||||
TmaService GetServiceId() const {
|
||||
return static_cast<TmaService>(GetHeader()->service_id);
|
||||
TmaServiceId GetServiceId() const {
|
||||
return static_cast<TmaServiceId>(GetHeader()->service_id);
|
||||
}
|
||||
|
||||
void SetTaskId(u32 id) {
|
||||
|
|
|
@ -32,7 +32,7 @@ static constexpr u32 HashServiceName(const char *name) {
|
|||
return h ^ len;
|
||||
}
|
||||
|
||||
enum class TmaService : u32 {
|
||||
enum class TmaServiceId : u32 {
|
||||
Invalid = 0,
|
||||
|
||||
/* Special nodes, for facilitating connection over USB. */
|
||||
|
@ -44,3 +44,10 @@ enum class TmaService : u32 {
|
|||
|
||||
TestService = HashServiceName("AtmosphereTestService"), /* Temporary service, will be used to debug communications. */
|
||||
};
|
||||
|
||||
static constexpr bool IsMetaService(TmaServiceId id) {
|
||||
return id == TmaServiceId::UsbQueryTarget ||
|
||||
id == TmaServiceId::UsbSendHostInfo ||
|
||||
id == TmaServiceId::UsbConnect ||
|
||||
id == TmaServiceId::UsbDisconnect;
|
||||
}
|
||||
|
|
|
@ -72,7 +72,6 @@ void TmaUsbConnection::SendThreadFunc(void *arg) {
|
|||
void TmaUsbConnection::RecvThreadFunc(void *arg) {
|
||||
TmaUsbConnection *this_ptr = reinterpret_cast<TmaUsbConnection *>(arg);
|
||||
TmaConnResult res = TmaConnResult::Success;
|
||||
u64 i = 0;
|
||||
this_ptr->SetConnected(true);
|
||||
|
||||
while (res == TmaConnResult::Success) {
|
||||
|
@ -83,7 +82,7 @@ void TmaUsbConnection::RecvThreadFunc(void *arg) {
|
|||
|
||||
if (res == TmaConnResult::Success) {
|
||||
switch (packet->GetServiceId()) {
|
||||
case TmaService::UsbQueryTarget: {
|
||||
case TmaServiceId::UsbQueryTarget: {
|
||||
this_ptr->SetConnected(false);
|
||||
|
||||
res = this_ptr->SendQueryReply(packet);
|
||||
|
@ -93,7 +92,7 @@ void TmaUsbConnection::RecvThreadFunc(void *arg) {
|
|||
}
|
||||
}
|
||||
break;
|
||||
case TmaService::UsbSendHostInfo: {
|
||||
case TmaServiceId::UsbSendHostInfo: {
|
||||
struct {
|
||||
u32 version;
|
||||
u32 sleeping;
|
||||
|
@ -105,7 +104,7 @@ void TmaUsbConnection::RecvThreadFunc(void *arg) {
|
|||
}
|
||||
}
|
||||
break;
|
||||
case TmaService::UsbConnect: {
|
||||
case TmaServiceId::UsbConnect: {
|
||||
res = this_ptr->SendQueryReply(packet);
|
||||
|
||||
if (res == TmaConnResult::Success) {
|
||||
|
@ -114,7 +113,7 @@ void TmaUsbConnection::RecvThreadFunc(void *arg) {
|
|||
}
|
||||
}
|
||||
break;
|
||||
case TmaService::UsbDisconnect: {
|
||||
case TmaServiceId::UsbDisconnect: {
|
||||
this_ptr->SetConnected(false);
|
||||
this_ptr->OnDisconnected();
|
||||
|
||||
|
|
|
@ -20,6 +20,7 @@
|
|||
#include <malloc.h>
|
||||
|
||||
#include <switch.h>
|
||||
#include <atmosphere.h>
|
||||
#include <stratosphere.hpp>
|
||||
|
||||
#include "tma_conn_usb_connection.hpp"
|
||||
|
@ -64,7 +65,7 @@ void __appInit(void) {
|
|||
fatalSimple(rc);
|
||||
}
|
||||
|
||||
CheckAtmosphereVersion();
|
||||
CheckAtmosphereVersion(CURRENT_ATMOSPHERE_VERSION);
|
||||
}
|
||||
|
||||
void __appExit(void) {
|
||||
|
|
32
stratosphere/tma/source/tma_service.cpp
Normal file
32
stratosphere/tma/source/tma_service.cpp
Normal file
|
@ -0,0 +1,32 @@
|
|||
/*
|
||||
* 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 <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include <switch.h>
|
||||
#include <stratosphere.hpp>
|
||||
#include "tma_service.hpp"
|
||||
|
||||
u32 TmaService::GetNextTaskId() {
|
||||
/* TODO: Service Manager */
|
||||
return 0;
|
||||
}
|
||||
|
||||
void TmaService::OnSleep() {
|
||||
/* Default service does nothing here. */
|
||||
}
|
||||
|
||||
void TmaService::OnWake() {
|
||||
/* Default service does nothing here. */
|
||||
}
|
43
stratosphere/tma/source/tma_service.hpp
Normal file
43
stratosphere/tma/source/tma_service.hpp
Normal file
|
@ -0,0 +1,43 @@
|
|||
/*
|
||||
* 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 <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
#include <switch.h>
|
||||
#include <stratosphere.hpp>
|
||||
|
||||
#include "tma_conn_service_ids.hpp"
|
||||
#include "tma_conn_packet.hpp"
|
||||
#include "tma_task.hpp"
|
||||
|
||||
class TmaServiceManager;
|
||||
|
||||
class TmaService {
|
||||
protected:
|
||||
TmaServiceManager *manager;
|
||||
const char *service_name;
|
||||
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<TmaServiceId>(HashServiceName(this->service_name))) { }
|
||||
virtual ~TmaService() { }
|
||||
|
||||
TmaServiceId GetServiceId() const { return this->id; }
|
||||
};
|
29
stratosphere/tma/source/tma_task.cpp
Normal file
29
stratosphere/tma/source/tma_task.cpp
Normal file
|
@ -0,0 +1,29 @@
|
|||
/*
|
||||
* 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 <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include <switch.h>
|
||||
#include <stratosphere.hpp>
|
||||
#include "tma_task.hpp"
|
||||
|
||||
void TmaTask::Complete() {
|
||||
/* TODO: Service manager */
|
||||
this->state = TmaTaskState::Complete;
|
||||
}
|
||||
|
||||
void TmaTask::Cancel() {
|
||||
/* TODO: Service manager */
|
||||
this->state = TmaTaskState::Canceled;
|
||||
}
|
74
stratosphere/tma/source/tma_task.hpp
Normal file
74
stratosphere/tma/source/tma_task.hpp
Normal file
|
@ -0,0 +1,74 @@
|
|||
/*
|
||||
* 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 <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
#include <switch.h>
|
||||
#include <stratosphere.hpp>
|
||||
|
||||
#include "tma_conn_service_ids.hpp"
|
||||
#include "tma_conn_packet.hpp"
|
||||
|
||||
enum class TmaTaskState : u32 {
|
||||
InProgress,
|
||||
Complete,
|
||||
Canceled,
|
||||
};
|
||||
|
||||
class TmaServiceManager;
|
||||
|
||||
class TmaTask {
|
||||
public:
|
||||
static constexpr u32 MaxPriority = 15;
|
||||
static constexpr u32 NumPriorities = MaxPriority + 1;
|
||||
protected:
|
||||
TmaServiceManager *manager;
|
||||
u32 priority = 0;
|
||||
TmaServiceId service_id = TmaServiceId::Invalid;
|
||||
u32 task_id = 0;
|
||||
u32 command = 0;
|
||||
TmaTaskState state = TmaTaskState::InProgress;
|
||||
HosSignal signal;
|
||||
bool owned_by_task_list = true;
|
||||
bool sleep_allowed = true;
|
||||
public:
|
||||
TmaTask(TmaServiceManager *m) : manager(m) { }
|
||||
virtual ~TmaTask() { }
|
||||
|
||||
u32 GetPriority() const { return this->priority; }
|
||||
TmaServiceId GetServiceId() const { return this->service_id; }
|
||||
u32 GetTaskId() const { return this->task_id; }
|
||||
u32 GetCommand() const { return this->command; }
|
||||
TmaTaskState GetState() const { return this->state; }
|
||||
bool GetOwnedByTaskList() const { return this->owned_by_task_list; }
|
||||
bool GetSleepAllowed() const { return this->sleep_allowed; }
|
||||
|
||||
void SetPriority(u32 p) { this->priority = p; }
|
||||
void SetServiceId(TmaServiceId s) { this->service_id = s; }
|
||||
void SetTaskId(u32 i) { this->task_id = i; }
|
||||
void SetCommand(u32 c) { this->command = c; }
|
||||
void SetOwnedByTaskList(bool o) { this->owned_by_task_list = o; }
|
||||
void SetSleepAllowed(bool a) { this->sleep_allowed = a; }
|
||||
|
||||
void Signal() { this->signal.Signal(); }
|
||||
void ResetSignal() { this->signal.Reset(); }
|
||||
|
||||
void Complete();
|
||||
void Cancel();
|
||||
|
||||
virtual void OnStart(TmaPacket *packet) = 0;
|
||||
virtual void OnReceivePacket(TmaPacket *packet) = 0;
|
||||
virtual void OnSendPacket(TmaPacket *packet) = 0;
|
||||
};
|
183
stratosphere/tma/source/tma_task_list.cpp
Normal file
183
stratosphere/tma/source/tma_task_list.cpp
Normal file
|
@ -0,0 +1,183 @@
|
|||
/*
|
||||
* 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 <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
#include <algorithm>
|
||||
|
||||
#include <switch.h>
|
||||
#include <stratosphere.hpp>
|
||||
#include "tma_task_list.hpp"
|
||||
|
||||
TmaTask *TmaTaskList::GetById(u32 task_id) const {
|
||||
for (u32 i = 0 ; i < TmaTask::NumPriorities; i++) {
|
||||
for (auto task : this->tasks[i]) {
|
||||
if (task->GetTaskId() == task_id) {
|
||||
return task;
|
||||
}
|
||||
}
|
||||
}
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
u32 TmaTaskList::GetNumTasks() const {
|
||||
std::scoped_lock<HosMutex> lk(this->lock);
|
||||
u32 count = 0;
|
||||
|
||||
for (u32 i = 0 ; i < TmaTask::NumPriorities; i++) {
|
||||
count += this->tasks[i].size();
|
||||
}
|
||||
|
||||
return count;
|
||||
}
|
||||
|
||||
u32 TmaTaskList::GetNumSleepingTasks() const {
|
||||
std::scoped_lock<HosMutex> lk(this->lock);
|
||||
u32 count = 0;
|
||||
|
||||
for (u32 i = 0 ; i < TmaTask::NumPriorities; i++) {
|
||||
count += this->sleeping_tasks[i].size();
|
||||
}
|
||||
|
||||
return count;
|
||||
}
|
||||
|
||||
bool TmaTaskList::SendPacket(bool connected, TmaPacket *packet) {
|
||||
std::scoped_lock<HosMutex> lk(this->lock);
|
||||
|
||||
TmaTask *target_task = nullptr;
|
||||
|
||||
/* This loop both finds a target task, and cleans up finished tasks. */
|
||||
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++;
|
||||
if (target_task == nullptr) {
|
||||
if (connected || IsMetaService(task->GetServiceId())) {
|
||||
target_task = nullptr;
|
||||
}
|
||||
}
|
||||
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();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (target_task) {
|
||||
/* Setup packet. */
|
||||
packet->SetContinuation(true);
|
||||
packet->SetServiceId(target_task->GetServiceId());
|
||||
packet->SetTaskId(target_task->GetTaskId());
|
||||
packet->SetCommand(target_task->GetCommand());
|
||||
packet->ClearOffset();
|
||||
|
||||
/* Actually handle packet send. */
|
||||
target_task->OnSendPacket(packet);
|
||||
}
|
||||
|
||||
return target_task != nullptr;
|
||||
}
|
||||
|
||||
bool TmaTaskList::ReceivePacket(TmaPacket *packet) {
|
||||
std::scoped_lock<HosMutex> lk(this->lock);
|
||||
|
||||
auto task = this->GetById(packet->GetTaskId());
|
||||
if (task != nullptr) {
|
||||
task->OnReceivePacket(packet);
|
||||
}
|
||||
return task != nullptr;
|
||||
}
|
||||
|
||||
void TmaTaskList::Add(TmaTask *task) {
|
||||
std::scoped_lock<HosMutex> lk(this->lock);
|
||||
|
||||
this->tasks[task->GetPriority()].push_back(task);
|
||||
}
|
||||
|
||||
void TmaTaskList::Remove(TmaTask *task) {
|
||||
const auto priority = task->GetPriority();
|
||||
|
||||
/* Nintendo iterates over all lists instead of just the correct one. */
|
||||
/* TODO: Is there actually any reason to do that? */
|
||||
auto ind = std::find(this->tasks[priority].begin(), this->tasks[priority].end(), task);
|
||||
if (ind != this->tasks[priority].end()) {
|
||||
this->tasks[priority].erase(ind);
|
||||
return;
|
||||
}
|
||||
|
||||
/* TODO: Panic to fatal? */
|
||||
std::abort();
|
||||
}
|
||||
|
||||
void TmaTaskList::Cancel(u32 task_id) {
|
||||
std::scoped_lock<HosMutex> lk(this->lock);
|
||||
|
||||
auto task = this->GetById(task_id);
|
||||
if (task != nullptr) {
|
||||
task->Cancel();
|
||||
}
|
||||
}
|
||||
|
||||
void TmaTaskList::CancelAll() {
|
||||
std::scoped_lock<HosMutex> lk(this->lock);
|
||||
|
||||
for (u32 i = 0 ; i < TmaTask::NumPriorities; i++) {
|
||||
for (auto task : this->tasks[i]) {
|
||||
task->Cancel();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void TmaTaskList::Sleep() {
|
||||
std::scoped_lock<HosMutex> lk(this->lock);
|
||||
|
||||
for (u32 i = 0; i < TmaTask::NumPriorities; i++) {
|
||||
auto it = this->tasks[i].begin();
|
||||
while (it != this->tasks[i].end()) {
|
||||
auto task = *it;
|
||||
if (task->GetSleepAllowed()) {
|
||||
it = this->tasks[i].erase(it);
|
||||
this->sleeping_tasks[i].push_back(task);
|
||||
} else {
|
||||
it++;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void TmaTaskList::Wake() {
|
||||
std::scoped_lock<HosMutex> lk(this->lock);
|
||||
|
||||
for (u32 i = 0; i < TmaTask::NumPriorities; i++) {
|
||||
auto it = this->sleeping_tasks[i].begin();
|
||||
while (it != this->sleeping_tasks[i].end()) {
|
||||
auto task = *it;
|
||||
it = this->sleeping_tasks[i].erase(it);
|
||||
this->tasks[i].push_back(task);
|
||||
}
|
||||
}
|
||||
}
|
49
stratosphere/tma/source/tma_task_list.hpp
Normal file
49
stratosphere/tma/source/tma_task_list.hpp
Normal file
|
@ -0,0 +1,49 @@
|
|||
/*
|
||||
* 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 <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
#include <switch.h>
|
||||
#include <stratosphere.hpp>
|
||||
#include <vector>
|
||||
|
||||
#include "tma_conn_service_ids.hpp"
|
||||
#include "tma_task.hpp"
|
||||
|
||||
class TmaTaskList {
|
||||
private:
|
||||
mutable HosMutex lock;
|
||||
std::vector<TmaTask *> tasks[TmaTask::NumPriorities];
|
||||
std::vector<TmaTask *> sleeping_tasks[TmaTask::NumPriorities];
|
||||
private:
|
||||
void Remove(TmaTask *task);
|
||||
TmaTask *GetById(u32 task_id) const;
|
||||
public:
|
||||
TmaTaskList() { }
|
||||
virtual ~TmaTaskList() { }
|
||||
|
||||
u32 GetNumTasks() const;
|
||||
u32 GetNumSleepingTasks() const;
|
||||
|
||||
bool SendPacket(bool connected, TmaPacket *packet);
|
||||
bool ReceivePacket(TmaPacket *packet);
|
||||
|
||||
void Add(TmaTask *task);
|
||||
void Cancel(u32 task_id);
|
||||
void CancelAll();
|
||||
|
||||
void Sleep();
|
||||
void Wake();
|
||||
};
|
Loading…
Reference in a new issue