mirror of
https://github.com/Atmosphere-NX/Atmosphere
synced 2024-12-22 20:31:14 +00:00
Stratosphere: Add IWaitable, WaitableManager
This commit is contained in:
parent
8e25534912
commit
cbb0a084a6
8 changed files with 244 additions and 9 deletions
|
@ -3,5 +3,5 @@
|
|||
|
||||
class IServiceObject {
|
||||
public:
|
||||
virtual Result dispatch(IpcParsedCommand *r, u32 *cmd_buf, u32 cmd_id, u32 *in_rawdata, u32 in_rawdata_size, u32 *out_rawdata, u32 *out_raw_data_count);
|
||||
virtual Result dispatch(IpcParsedCommand *r, u32 *cmd_buf, u32 cmd_id, u32 *in_rawdata, u32 in_rawdata_size, u32 *out_rawdata, u32 *out_raw_data_count) = 0;
|
||||
};
|
32
stratosphere/loader/source/iwaitable.hpp
Normal file
32
stratosphere/loader/source/iwaitable.hpp
Normal file
|
@ -0,0 +1,32 @@
|
|||
#pragma once
|
||||
|
||||
#include <switch.h>
|
||||
|
||||
class IWaitable {
|
||||
u64 wait_priority = 0;
|
||||
IWaitable *parent_waitable;
|
||||
public:
|
||||
virtual ~IWaitable();
|
||||
virtual unsigned int get_num_waitables() = 0;
|
||||
virtual void get_waitables(IWaitable **dst) = 0;
|
||||
virtual void delete_child(IWaitable *child) = 0;
|
||||
virtual Handle get_handle() = 0;
|
||||
virtual Result handle_signaled() = 0;
|
||||
|
||||
bool has_parent() {
|
||||
return this->parent_waitable != NULL;
|
||||
}
|
||||
|
||||
IWaitable *get_parent() {
|
||||
return this->parent_waitable;
|
||||
}
|
||||
|
||||
void update_priority() {
|
||||
static u64 g_cur_priority = 0;
|
||||
this->wait_priority = g_cur_priority++;
|
||||
}
|
||||
|
||||
static bool compare(IWaitable *a, IWaitable *b) {
|
||||
return (a->wait_priority < b->wait_priority);
|
||||
}
|
||||
};
|
|
@ -11,6 +11,7 @@ ServiceServer<T>::ServiceServer(const char *service_name, unsigned int max_s) :
|
|||
for (unsigned int i = 0; i < this->max_sessions; i++) {
|
||||
this->sessions[i] = NULL;
|
||||
}
|
||||
this->num_sessions = 0;
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
|
@ -28,8 +29,71 @@ ServiceServer<T>::~ServiceServer() {
|
|||
}
|
||||
}
|
||||
|
||||
/* IWaitable functions. */
|
||||
template <typename T>
|
||||
Result ServiceServer<T>::process() {
|
||||
/* TODO */
|
||||
return 0;
|
||||
unsigned int ServiceServer<T>::get_num_waitables() {
|
||||
unsigned int n = 1;
|
||||
for (unsigned int i = 0; i < this->max_sessions; i++) {
|
||||
if (this->sessions[i]) {
|
||||
n += this->sessions[i]->get_num_waitables();
|
||||
}
|
||||
}
|
||||
return n;
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
void ServiceServer<T>::get_waitables(IWaitable **dst) {
|
||||
dst[0] = this;
|
||||
unsigned int n = 0;
|
||||
for (unsigned int i = 0; i < this->max_sessions; i++) {
|
||||
if (this->sessions[i]) {
|
||||
this->sessions[i]->get_waitables(&dst[1 + n]);
|
||||
n += this->sessions[i]->get_num_waitables();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
void ServiceSession<T>::delete_child(IWaitable *child) {
|
||||
unsigned int i;
|
||||
for (i = 0; i < this->max_sessions; i++) {
|
||||
if (this->sessions[i] == child) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (i == this->max_sessions) {
|
||||
/* TODO: Panic, because this isn't our child. */
|
||||
} else {
|
||||
delete this->sessions[i];
|
||||
this->sessions[i] = NULL;
|
||||
this->num_sessions--;
|
||||
}
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
Handle ServiceServer<T>::get_handle() {
|
||||
return this->port_handle;
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
Result ServiceServer<T>::handle_signaled() {
|
||||
/* If this server's port was signaled, accept a new session. */
|
||||
Handle session_h;
|
||||
svcAcceptSession(&session_h, this->port_handle);
|
||||
|
||||
if (this->num_sessions >= this->max_sessions) {
|
||||
svcCloseHandle(session_h);
|
||||
return 0x10601;
|
||||
}
|
||||
|
||||
unsigned int i;
|
||||
for (i = 0; i < this->max_sessions; i++) {
|
||||
if (this->sessions[i] = NULL) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
this->sessions[i] = new ServiceSession<T>(this, session_h, 0);
|
||||
this->num_sessions++;
|
||||
}
|
|
@ -3,22 +3,29 @@
|
|||
#include <type_traits>
|
||||
|
||||
#include "iserviceobject.hpp"
|
||||
#include "iwaitable.hpp"
|
||||
#include "servicesession.hpp"
|
||||
|
||||
template <typename T>
|
||||
class ServiceSession;
|
||||
|
||||
template <typename T>
|
||||
class ServiceServer {
|
||||
class ServiceServer : IWaitable {
|
||||
static_assert(std::is_base_of<IServiceObject, T>::value, "Service Objects must derive from IServiceObject");
|
||||
|
||||
Handle port_handle;
|
||||
unsigned int max_sessions;
|
||||
unsigned int num_sessions;
|
||||
ServiceSession<T> **sessions;
|
||||
|
||||
public:
|
||||
ServiceServer(const char *service_name, unsigned int max_s);
|
||||
~ServiceServer();
|
||||
Result process();
|
||||
virtual ~ServiceServer();
|
||||
|
||||
/* IWaitable */
|
||||
virtual unsigned int get_num_waitables();
|
||||
virtual void get_waitables(IWaitable **dst);
|
||||
virtual void delete_child(IWaitable *child);
|
||||
virtual Handle get_handle();
|
||||
virtual Result handle_signaled();
|
||||
};
|
|
@ -2,3 +2,29 @@
|
|||
|
||||
#include "servicesession.hpp"
|
||||
|
||||
/* IWaitable functions. */
|
||||
template <typename T>
|
||||
unsigned int ServiceSession<T>::get_num_waitables() {
|
||||
return 1;
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
void ServiceSession<T>::get_waitables(IWaitable **dst) {
|
||||
dst[0] = this;
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
void ServiceSession<T>::delete_child(IWaitable *child) {
|
||||
/* TODO: Panic, because we can never have any children. */
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
Handle ServiceSession<T>::get_handle() {
|
||||
return this->server_handle;
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
Result ServiceSession<T>::handle_signaled() {
|
||||
/* TODO */
|
||||
return 0;
|
||||
}
|
|
@ -3,13 +3,14 @@
|
|||
#include <type_traits>
|
||||
|
||||
#include "iserviceobject.hpp"
|
||||
#include "iwaitable.hpp"
|
||||
#include "serviceserver.hpp"
|
||||
|
||||
template <typename T>
|
||||
class ServiceServer;
|
||||
|
||||
template <typename T>
|
||||
class ServiceSession {
|
||||
class ServiceSession : IWaitable {
|
||||
static_assert(std::is_base_of<IServiceObject, T>::value, "Service Objects must derive from IServiceObject");
|
||||
|
||||
T *service_object;
|
||||
|
@ -21,7 +22,7 @@ class ServiceSession {
|
|||
this->service_object = new T();
|
||||
}
|
||||
|
||||
~ServiceSession() {
|
||||
virtual ~ServiceSession() {
|
||||
delete this->service_object;
|
||||
if (server_handle) {
|
||||
svcCloseHandle(server_handle);
|
||||
|
@ -34,4 +35,11 @@ class ServiceSession {
|
|||
T *get_service_object() { return this->service_object; }
|
||||
Handle get_server_handle() { return this->server_handle; }
|
||||
Handle get_client_handle() { return this->client_handle; }
|
||||
|
||||
/* IWaitable */
|
||||
virtual unsigned int get_num_waitables();
|
||||
virtual void get_waitables(IWaitable **dst);
|
||||
virtual void delete_child(IWaitable *child);
|
||||
virtual Handle get_handle();
|
||||
virtual Result handle_signaled();
|
||||
};
|
72
stratosphere/loader/source/waitablemanager.cpp
Normal file
72
stratosphere/loader/source/waitablemanager.cpp
Normal file
|
@ -0,0 +1,72 @@
|
|||
#include <switch.h>
|
||||
|
||||
#include <algorithm>
|
||||
|
||||
#include "waitablemanager.hpp"
|
||||
|
||||
|
||||
unsigned int WaitableManager::get_num_signalable() {
|
||||
unsigned int n = 0;
|
||||
for (auto & waitable : this->waitables) {
|
||||
n += waitable->get_num_waitables();
|
||||
}
|
||||
return n;
|
||||
}
|
||||
|
||||
void WaitableManager::add_waitable(IWaitable *waitable) {
|
||||
this->waitables.push_back(waitable);
|
||||
}
|
||||
|
||||
void WaitableManager::process() {
|
||||
std::vector<IWaitable *> signalables;
|
||||
std::vector<Handle> handles;
|
||||
|
||||
int handle_index = 0;
|
||||
Result rc;
|
||||
|
||||
while (1) {
|
||||
/* Create vector of signalable items. */
|
||||
signalables.resize(this->get_num_signalable(), NULL);
|
||||
unsigned int n = 0;
|
||||
for (auto & waitable : this->waitables) {
|
||||
waitable->get_waitables(signalables.data() + n);
|
||||
n += waitable->get_num_waitables();
|
||||
}
|
||||
|
||||
/* Sort signalables by priority. */
|
||||
std::sort(signalables.begin(), signalables.end(), IWaitable::compare);
|
||||
|
||||
/* Copy out handles. */
|
||||
handles.resize(signalables.size());
|
||||
std::transform(signalables.begin(), signalables.end(), handles.begin(), [](IWaitable *w) { return w->get_handle(); });
|
||||
|
||||
rc = svcWaitSynchronization(&handle_index, handles.data(), handles.size(), this->timeout);
|
||||
if (R_SUCCEEDED(rc)) {
|
||||
/* Handle a signaled waitable. */
|
||||
/* TODO: What should be done with the result here? */
|
||||
signalables[handle_index]->handle_signaled();
|
||||
} else if (rc == 0xEA01) {
|
||||
/* Timeout. */
|
||||
for (auto & waitable : signalables) {
|
||||
waitable->update_priority();
|
||||
}
|
||||
} else if (rc == 0xF601) {
|
||||
/* handles[handle_index] was closed! */
|
||||
|
||||
/* Close the handle. */
|
||||
svcCloseHandle(handles[handle_index]);
|
||||
|
||||
/* If relevant, remove from waitables. */
|
||||
this->waitables.erase(std::remove(this->waitables.begin(), this->waitables.end(), signalables[handle_index]), this->waitables.end());
|
||||
|
||||
/* Delete it. */
|
||||
if (signalables[handle_index]->has_parent()) {
|
||||
signalables[handle_index]->get_parent()->delete_child(signalables[handle_index]);
|
||||
} else {
|
||||
delete signalables[handle_index];
|
||||
}
|
||||
} else {
|
||||
/* TODO: Panic. When can this happen? */
|
||||
}
|
||||
}
|
||||
}
|
26
stratosphere/loader/source/waitablemanager.hpp
Normal file
26
stratosphere/loader/source/waitablemanager.hpp
Normal file
|
@ -0,0 +1,26 @@
|
|||
#pragma once
|
||||
#include <switch.h>
|
||||
#include <vector>
|
||||
|
||||
#include "iwaitable.hpp"
|
||||
|
||||
class WaitableManager {
|
||||
std::vector<IWaitable *> waitables;
|
||||
|
||||
u64 timeout;
|
||||
|
||||
public:
|
||||
WaitableManager(u64 t) : waitables(0), timeout(t) { }
|
||||
~WaitableManager() {
|
||||
/* This should call the destructor for every waitable. */
|
||||
for (auto & waitable : waitables) {
|
||||
delete waitable;
|
||||
}
|
||||
waitables.clear();
|
||||
}
|
||||
|
||||
unsigned int get_num_signalable();
|
||||
void add_waitable(IWaitable *waitable);
|
||||
void delete_waitable(IWaitable *waitable);
|
||||
void process();
|
||||
};
|
Loading…
Reference in a new issue