mirror of
https://github.com/Atmosphere-NX/Atmosphere
synced 2024-11-10 07:06:34 +00:00
scs: implement EventHandlerThread for shell
This commit is contained in:
parent
aa2dce7316
commit
1a1b1355ba
7 changed files with 377 additions and 5 deletions
|
@ -22,4 +22,10 @@ namespace ams::htc::tenv {
|
||||||
char str[0x40];
|
char str[0x40];
|
||||||
};
|
};
|
||||||
|
|
||||||
|
constexpr inline auto PathLengthMax = 0x300;
|
||||||
|
|
||||||
|
struct alignas(4) Path {
|
||||||
|
char str[PathLengthMax];
|
||||||
|
};
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -96,6 +96,27 @@ namespace ams::pm {
|
||||||
struct ProcessEventInfo {
|
struct ProcessEventInfo {
|
||||||
u32 event;
|
u32 event;
|
||||||
os::ProcessId process_id;
|
os::ProcessId process_id;
|
||||||
|
|
||||||
|
inline ProcessEvent GetProcessEvent() const {
|
||||||
|
if (hos::GetVersion() >= hos::Version_5_0_0) {
|
||||||
|
return static_cast<ProcessEvent>(this->event);
|
||||||
|
}
|
||||||
|
switch (static_cast<ProcessEventDeprecated>(event)) {
|
||||||
|
case ProcessEventDeprecated::None:
|
||||||
|
return ProcessEvent::None;
|
||||||
|
case ProcessEventDeprecated::Exited:
|
||||||
|
return ProcessEvent::Exited;
|
||||||
|
case ProcessEventDeprecated::Started:
|
||||||
|
return ProcessEvent::Started;
|
||||||
|
case ProcessEventDeprecated::Exception:
|
||||||
|
return ProcessEvent::Exception;
|
||||||
|
case ProcessEventDeprecated::DebugRunning:
|
||||||
|
return ProcessEvent::DebugRunning;
|
||||||
|
case ProcessEventDeprecated::DebugBreak:
|
||||||
|
return ProcessEvent::DebugBreak;
|
||||||
|
AMS_UNREACHABLE_DEFAULT_CASE();
|
||||||
|
}
|
||||||
|
}
|
||||||
};
|
};
|
||||||
static_assert(sizeof(ProcessEventInfo) == 0x10 && util::is_pod<ProcessEventInfo>::value, "ProcessEventInfo definition!");
|
static_assert(sizeof(ProcessEventInfo) == 0x10 && util::is_pod<ProcessEventInfo>::value, "ProcessEventInfo definition!");
|
||||||
|
|
||||||
|
|
|
@ -15,6 +15,7 @@
|
||||||
*/
|
*/
|
||||||
#include <stratosphere.hpp>
|
#include <stratosphere.hpp>
|
||||||
#include "impl/htc_tenv_allocator.hpp"
|
#include "impl/htc_tenv_allocator.hpp"
|
||||||
|
#include "impl/htc_tenv_impl.hpp"
|
||||||
|
|
||||||
namespace ams::htc::tenv {
|
namespace ams::htc::tenv {
|
||||||
|
|
||||||
|
@ -23,4 +24,8 @@ namespace ams::htc::tenv {
|
||||||
impl::InitializeAllocator(allocate, deallocate);
|
impl::InitializeAllocator(allocate, deallocate);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void UnregisterDefinitionFilePath(os::ProcessId process_id) {
|
||||||
|
return impl::UnregisterDefinitionFilePath(process_id.value);
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -0,0 +1,40 @@
|
||||||
|
/*
|
||||||
|
* Copyright (c) 2018-2020 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 <stratosphere.hpp>
|
||||||
|
#include "htc_tenv_allocator.hpp"
|
||||||
|
|
||||||
|
namespace ams::htc::tenv::impl {
|
||||||
|
|
||||||
|
struct DefinitionFileInfo : public util::IntrusiveListBaseNode<DefinitionFileInfo> {
|
||||||
|
u64 process_id;
|
||||||
|
Path path;
|
||||||
|
|
||||||
|
DefinitionFileInfo(u64 pid, Path *p) : process_id(pid) {
|
||||||
|
AMS_ASSERT(p != nullptr);
|
||||||
|
util::Strlcpy(this->path.str, p->str, PathLengthMax);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void *operator new(size_t size) {
|
||||||
|
return Allocate(size);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void operator delete(void *p, size_t size) {
|
||||||
|
Deallocate(p, size);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
}
|
|
@ -0,0 +1,81 @@
|
||||||
|
/*
|
||||||
|
* Copyright (c) 2018-2020 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 <stratosphere.hpp>
|
||||||
|
#include "htc_tenv_impl.hpp"
|
||||||
|
#include "htc_tenv_definition_file_info.hpp"
|
||||||
|
|
||||||
|
namespace ams::htc::tenv::impl {
|
||||||
|
|
||||||
|
namespace {
|
||||||
|
|
||||||
|
class DefinitionFileInfoManager {
|
||||||
|
private:
|
||||||
|
using DefinitionFileInfoList = util::IntrusiveListBaseTraits<DefinitionFileInfo>::ListType;
|
||||||
|
private:
|
||||||
|
DefinitionFileInfoList m_list;
|
||||||
|
os::SdkMutex m_mutex;
|
||||||
|
public:
|
||||||
|
constexpr DefinitionFileInfoManager() = default;
|
||||||
|
|
||||||
|
~DefinitionFileInfoManager() {
|
||||||
|
while (!m_list.empty()) {
|
||||||
|
auto *p = std::addressof(*m_list.rbegin());
|
||||||
|
m_list.erase(m_list.iterator_to(*p));
|
||||||
|
delete p;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void Remove(DefinitionFileInfo *info) {
|
||||||
|
std::scoped_lock lk(m_mutex);
|
||||||
|
|
||||||
|
m_list.erase(m_list.iterator_to(*info));
|
||||||
|
delete info;
|
||||||
|
}
|
||||||
|
|
||||||
|
DefinitionFileInfo *GetInfo(u64 process_id) {
|
||||||
|
std::scoped_lock lk(m_mutex);
|
||||||
|
|
||||||
|
for (auto &info : m_list) {
|
||||||
|
if (info.process_id == process_id) {
|
||||||
|
return std::addressof(info);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
constinit DefinitionFileInfoManager g_definition_file_info_manager;
|
||||||
|
|
||||||
|
ALWAYS_INLINE DefinitionFileInfoManager &GetDefinitionFileInfoManager() {
|
||||||
|
return g_definition_file_info_manager;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
void UnregisterDefinitionFilePath(u64 process_id) {
|
||||||
|
/* Require the process id to be valid. */
|
||||||
|
if (process_id == 0) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Remove the definition file info, if we have one. */
|
||||||
|
if (auto *info = GetDefinitionFileInfoManager().GetInfo(process_id); info != nullptr) {
|
||||||
|
GetDefinitionFileInfoManager().Remove(info);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -0,0 +1,23 @@
|
||||||
|
/*
|
||||||
|
* Copyright (c) 2018-2020 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 <stratosphere.hpp>
|
||||||
|
|
||||||
|
namespace ams::htc::tenv::impl {
|
||||||
|
|
||||||
|
void UnregisterDefinitionFilePath(u64 process_id);
|
||||||
|
|
||||||
|
}
|
|
@ -29,9 +29,9 @@ namespace ams::scs {
|
||||||
u64 id;
|
u64 id;
|
||||||
s32 socket;
|
s32 socket;
|
||||||
s32 info_id;
|
s32 info_id;
|
||||||
bool _18;
|
bool started;
|
||||||
bool _19;
|
bool jit_debug;
|
||||||
bool _1A;
|
bool launched_by_cs;
|
||||||
};
|
};
|
||||||
|
|
||||||
constexpr inline auto MaxSocketInfo = 2;
|
constexpr inline auto MaxSocketInfo = 2;
|
||||||
|
@ -84,6 +84,13 @@ namespace ams::scs {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void InvokeHandler(ProcessEventHandler handler, os::ProcessId process_id) {
|
||||||
|
/* Invoke the handler on all our sockets. */
|
||||||
|
for (auto i = 0; i < m_count; ++i) {
|
||||||
|
handler(m_infos[i].id, m_infos[i].socket, process_id);
|
||||||
|
}
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
class ProgramInfoManager {
|
class ProgramInfoManager {
|
||||||
|
@ -101,6 +108,74 @@ namespace ams::scs {
|
||||||
/* Clear our count. */
|
/* Clear our count. */
|
||||||
m_count = 0;
|
m_count = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const ProgramInfo *Find(os::ProcessId process_id) const {
|
||||||
|
/* Find a matching program. */
|
||||||
|
for (auto i = 0; i < m_count; ++i) {
|
||||||
|
if (m_infos[i].process_id == process_id) {
|
||||||
|
return std::addressof(m_infos[i]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool Register(os::ProcessId process_id) {
|
||||||
|
/* Allocate an info id. */
|
||||||
|
const auto info_id = m_next_info_id++;
|
||||||
|
|
||||||
|
/* Check that we have space for the program. */
|
||||||
|
if (m_count >= MaxProgramInfo) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Create the new program info. */
|
||||||
|
m_infos[m_count++] = {
|
||||||
|
.process_id = process_id,
|
||||||
|
.id = 0,
|
||||||
|
.socket = 0,
|
||||||
|
.info_id = info_id,
|
||||||
|
.started = false,
|
||||||
|
.jit_debug = false,
|
||||||
|
.launched_by_cs = false,
|
||||||
|
};
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
void Unregister(os::ProcessId process_id) {
|
||||||
|
/* Unregister the program, if it's registered. */
|
||||||
|
for (auto i = 0; i < m_count; ++i) {
|
||||||
|
if (m_infos[i].process_id == process_id) {
|
||||||
|
/* Ensure that the valid program infos remain in bounds. */
|
||||||
|
std::memcpy(m_infos + i, m_infos + i + 1, (m_count - (i + 1)) * sizeof(*m_infos));
|
||||||
|
|
||||||
|
/* Note that we now have one fewer program info. */
|
||||||
|
--m_count;
|
||||||
|
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void SetStarted(os::ProcessId process_id) {
|
||||||
|
/* Start the program. */
|
||||||
|
for (auto i = 0; i < m_count; ++i) {
|
||||||
|
if (m_infos[i].process_id == process_id) {
|
||||||
|
m_infos[i].started = true;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void SetJitDebug(os::ProcessId process_id) {
|
||||||
|
/* Set the program as jit debug. */
|
||||||
|
for (auto i = 0; i < m_count; ++i) {
|
||||||
|
if (m_infos[i].process_id == process_id) {
|
||||||
|
m_infos[i].jit_debug = true;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
alignas(os::ThreadStackAlignment) constinit u8 g_thread_stack[os::MemoryPageSize];
|
alignas(os::ThreadStackAlignment) constinit u8 g_thread_stack[os::MemoryPageSize];
|
||||||
|
@ -115,9 +190,130 @@ namespace ams::scs {
|
||||||
|
|
||||||
constinit os::SdkMutex g_manager_mutex;
|
constinit os::SdkMutex g_manager_mutex;
|
||||||
|
|
||||||
|
void ProcessExitEvent(const pm::ProcessEventInfo &event_info) {
|
||||||
|
/* Unregister the target environment definition. */
|
||||||
|
htc::tenv::UnregisterDefinitionFilePath(event_info.process_id);
|
||||||
|
|
||||||
|
/* Unregister program info. */
|
||||||
|
ProgramInfo program_info;
|
||||||
|
bool found = false;
|
||||||
|
{
|
||||||
|
std::scoped_lock lk(g_manager_mutex);
|
||||||
|
|
||||||
|
if (const ProgramInfo *pi = g_program_info_manager.Find(event_info.process_id); pi != nullptr) {
|
||||||
|
program_info = *pi;
|
||||||
|
found = true;
|
||||||
|
|
||||||
|
g_program_info_manager.Unregister(event_info.process_id);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* If we found the program, handle callbacks. */
|
||||||
|
if (found) {
|
||||||
|
/* Invoke the common exit handler. */
|
||||||
|
if (program_info.launched_by_cs) {
|
||||||
|
g_common_exit_handler(program_info.id, program_info.socket, program_info.process_id);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Notify the process event. */
|
||||||
|
if (program_info.started) {
|
||||||
|
std::scoped_lock lk(g_manager_mutex);
|
||||||
|
|
||||||
|
g_socket_info_manager.InvokeHandler(g_common_exit_handler, program_info.process_id);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void ProcessStartedEvent(const pm::ProcessEventInfo &event_info) {
|
||||||
|
/* Start the program (registering it, if needed). */
|
||||||
|
{
|
||||||
|
std::scoped_lock lk(g_manager_mutex);
|
||||||
|
|
||||||
|
if (g_program_info_manager.Find(event_info.process_id) == nullptr) {
|
||||||
|
AMS_ABORT_UNLESS(g_program_info_manager.Register(event_info.process_id));
|
||||||
|
}
|
||||||
|
|
||||||
|
g_program_info_manager.SetStarted(event_info.process_id);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Handle callbacks. */
|
||||||
|
{
|
||||||
|
std::scoped_lock lk(g_manager_mutex);
|
||||||
|
|
||||||
|
g_socket_info_manager.InvokeHandler(g_common_start_handler, event_info.process_id);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void ProcessExceptionEvent(const pm::ProcessEventInfo &event_info) {
|
||||||
|
/* Find the program info. */
|
||||||
|
ProgramInfo program_info;
|
||||||
|
bool found = false;
|
||||||
|
{
|
||||||
|
std::scoped_lock lk(g_manager_mutex);
|
||||||
|
|
||||||
|
if (const ProgramInfo *pi = g_program_info_manager.Find(event_info.process_id); pi != nullptr) {
|
||||||
|
program_info = *pi;
|
||||||
|
found = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Set the program as jit debug. */
|
||||||
|
g_program_info_manager.SetJitDebug(event_info.process_id);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* If we found the program, handle callbacks. */
|
||||||
|
if (found) {
|
||||||
|
/* Invoke the common exception handler. */
|
||||||
|
if (program_info.launched_by_cs) {
|
||||||
|
g_common_jit_debug_handler(program_info.id, program_info.socket, program_info.process_id);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Notify the process event. */
|
||||||
|
if (program_info.started) {
|
||||||
|
std::scoped_lock lk(g_manager_mutex);
|
||||||
|
|
||||||
|
g_socket_info_manager.InvokeHandler(g_common_jit_debug_handler, program_info.process_id);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
void EventHandlerThread(void *) {
|
void EventHandlerThread(void *) {
|
||||||
/* TODO */
|
/* Get event observer. */
|
||||||
AMS_ABORT("scs::EventHandlerThread");
|
pgl::EventObserver observer;
|
||||||
|
R_ABORT_UNLESS(pgl::GetEventObserver(std::addressof(observer)));
|
||||||
|
|
||||||
|
/* Get the observer's event. */
|
||||||
|
os::SystemEventType shell_event;
|
||||||
|
R_ABORT_UNLESS(observer.GetSystemEvent(std::addressof(shell_event)));
|
||||||
|
|
||||||
|
/* Loop handling events. */
|
||||||
|
while (true) {
|
||||||
|
/* Wait for an event to come in. */
|
||||||
|
os::WaitSystemEvent(std::addressof(shell_event));
|
||||||
|
|
||||||
|
/* Loop processing event infos. */
|
||||||
|
while (true) {
|
||||||
|
/* Get the next event info. */
|
||||||
|
pm::ProcessEventInfo event_info;
|
||||||
|
if (R_FAILED(observer.GetProcessEventInfo(std::addressof(event_info)))) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Process the event. */
|
||||||
|
switch (event_info.GetProcessEvent()) {
|
||||||
|
case pm::ProcessEvent::Exited:
|
||||||
|
ProcessExitEvent(event_info);
|
||||||
|
break;
|
||||||
|
case pm::ProcessEvent::Started:
|
||||||
|
ProcessStartedEvent(event_info);
|
||||||
|
break;
|
||||||
|
case pm::ProcessEvent::Exception:
|
||||||
|
ProcessExceptionEvent(event_info);
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void StartEventHandlerThread() {
|
void StartEventHandlerThread() {
|
||||||
|
|
Loading…
Reference in a new issue