tma: Skeleton Service/Task/TaskList classes.

This commit is contained in:
Michael Scire 2018-12-05 02:11:20 -08:00
parent 2572ae8378
commit bb48e33074
11 changed files with 428 additions and 11 deletions

@ -1 +1 @@
Subproject commit 05015b9354d3df80e0836aa95d1d4dcfc2aef4b7 Subproject commit fa37b70b0eca93be04e18636db25c9443e00d03b

View file

@ -117,12 +117,12 @@ class TmaPacket {
return MaxPacketSize - this->offset; return MaxPacketSize - this->offset;
} }
void SetServiceId(TmaService srv) { void SetServiceId(TmaServiceId srv) {
GetHeader()->service_id = static_cast<u32>(srv); GetHeader()->service_id = static_cast<u32>(srv);
} }
TmaService GetServiceId() const { TmaServiceId GetServiceId() const {
return static_cast<TmaService>(GetHeader()->service_id); return static_cast<TmaServiceId>(GetHeader()->service_id);
} }
void SetTaskId(u32 id) { void SetTaskId(u32 id) {

View file

@ -32,7 +32,7 @@ static constexpr u32 HashServiceName(const char *name) {
return h ^ len; return h ^ len;
} }
enum class TmaService : u32 { enum class TmaServiceId : u32 {
Invalid = 0, Invalid = 0,
/* Special nodes, for facilitating connection over USB. */ /* 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. */ 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;
}

View file

@ -72,7 +72,6 @@ void TmaUsbConnection::SendThreadFunc(void *arg) {
void TmaUsbConnection::RecvThreadFunc(void *arg) { void TmaUsbConnection::RecvThreadFunc(void *arg) {
TmaUsbConnection *this_ptr = reinterpret_cast<TmaUsbConnection *>(arg); TmaUsbConnection *this_ptr = reinterpret_cast<TmaUsbConnection *>(arg);
TmaConnResult res = TmaConnResult::Success; TmaConnResult res = TmaConnResult::Success;
u64 i = 0;
this_ptr->SetConnected(true); this_ptr->SetConnected(true);
while (res == TmaConnResult::Success) { while (res == TmaConnResult::Success) {
@ -83,7 +82,7 @@ void TmaUsbConnection::RecvThreadFunc(void *arg) {
if (res == TmaConnResult::Success) { if (res == TmaConnResult::Success) {
switch (packet->GetServiceId()) { switch (packet->GetServiceId()) {
case TmaService::UsbQueryTarget: { case TmaServiceId::UsbQueryTarget: {
this_ptr->SetConnected(false); this_ptr->SetConnected(false);
res = this_ptr->SendQueryReply(packet); res = this_ptr->SendQueryReply(packet);
@ -93,7 +92,7 @@ void TmaUsbConnection::RecvThreadFunc(void *arg) {
} }
} }
break; break;
case TmaService::UsbSendHostInfo: { case TmaServiceId::UsbSendHostInfo: {
struct { struct {
u32 version; u32 version;
u32 sleeping; u32 sleeping;
@ -105,7 +104,7 @@ void TmaUsbConnection::RecvThreadFunc(void *arg) {
} }
} }
break; break;
case TmaService::UsbConnect: { case TmaServiceId::UsbConnect: {
res = this_ptr->SendQueryReply(packet); res = this_ptr->SendQueryReply(packet);
if (res == TmaConnResult::Success) { if (res == TmaConnResult::Success) {
@ -114,7 +113,7 @@ void TmaUsbConnection::RecvThreadFunc(void *arg) {
} }
} }
break; break;
case TmaService::UsbDisconnect: { case TmaServiceId::UsbDisconnect: {
this_ptr->SetConnected(false); this_ptr->SetConnected(false);
this_ptr->OnDisconnected(); this_ptr->OnDisconnected();

View file

@ -20,6 +20,7 @@
#include <malloc.h> #include <malloc.h>
#include <switch.h> #include <switch.h>
#include <atmosphere.h>
#include <stratosphere.hpp> #include <stratosphere.hpp>
#include "tma_conn_usb_connection.hpp" #include "tma_conn_usb_connection.hpp"
@ -64,7 +65,7 @@ void __appInit(void) {
fatalSimple(rc); fatalSimple(rc);
} }
CheckAtmosphereVersion(); CheckAtmosphereVersion(CURRENT_ATMOSPHERE_VERSION);
} }
void __appExit(void) { void __appExit(void) {

View 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. */
}

View 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; }
};

View 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;
}

View 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;
};

View 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);
}
}
}

View 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();
};