mirror of
				https://github.com/Atmosphere-NX/Atmosphere.git
				synced 2025-10-31 03:05:48 +01:00 
			
		
		
		
	
		
			
				
	
	
		
			230 lines
		
	
	
		
			7.1 KiB
		
	
	
	
		
			C++
		
	
	
	
	
	
			
		
		
	
	
			230 lines
		
	
	
		
			7.1 KiB
		
	
	
	
		
			C++
		
	
	
	
	
	
| /*
 | |
|  * 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 "pm_process_manager.hpp"
 | |
| 
 | |
| namespace ams::pm::impl {
 | |
| 
 | |
|     class ProcessList;
 | |
| 
 | |
|     class ProcessInfo {
 | |
|         friend class ProcessList;
 | |
|         NON_COPYABLE(ProcessInfo);
 | |
|         NON_MOVEABLE(ProcessInfo);
 | |
|         private:
 | |
|             enum Flag : u32 {
 | |
|                 Flag_SignalOnExit           = (1 << 0),
 | |
|                 Flag_ExceptionOccurred      = (1 << 1),
 | |
|                 Flag_ExceptionWaitingAttach = (1 << 2),
 | |
|                 Flag_SignalOnDebugEvent     = (1 << 3),
 | |
|                 Flag_SuspendedStateChanged  = (1 << 4),
 | |
|                 Flag_Suspended              = (1 << 5),
 | |
|                 Flag_Application            = (1 << 6),
 | |
|                 Flag_SignalOnStart          = (1 << 7),
 | |
|                 Flag_StartedStateChanged    = (1 << 8),
 | |
|             };
 | |
|         private:
 | |
|             util::IntrusiveListNode list_node;
 | |
|             const os::ProcessId process_id;
 | |
|             const ldr::PinId pin_id;
 | |
|             const ncm::ProgramLocation loc;
 | |
|             const cfg::OverrideStatus status;
 | |
|             Handle handle;
 | |
|             svc::ProcessState state;
 | |
|             u32 flags;
 | |
|             os::WaitableHolderType waitable_holder;
 | |
|         private:
 | |
|             void SetFlag(Flag flag) {
 | |
|                 this->flags |= flag;
 | |
|             }
 | |
| 
 | |
|             void ClearFlag(Flag flag) {
 | |
|                 this->flags &= ~flag;
 | |
|             }
 | |
| 
 | |
|             bool HasFlag(Flag flag) const {
 | |
|                 return (this->flags & flag);
 | |
|             }
 | |
|         public:
 | |
|             ProcessInfo(Handle h, os::ProcessId pid, ldr::PinId pin, const ncm::ProgramLocation &l, const cfg::OverrideStatus &s);
 | |
|             ~ProcessInfo();
 | |
|             void Cleanup();
 | |
| 
 | |
|             void LinkToWaitableManager(os::WaitableManagerType &manager) {
 | |
|                 os::LinkWaitableHolder(std::addressof(manager), std::addressof(this->waitable_holder));
 | |
|             }
 | |
| 
 | |
|             Handle GetHandle() const {
 | |
|                 return this->handle;
 | |
|             }
 | |
| 
 | |
|             os::ProcessId GetProcessId() const {
 | |
|                 return this->process_id;
 | |
|             }
 | |
| 
 | |
|             ldr::PinId GetPinId() const {
 | |
|                 return this->pin_id;
 | |
|             }
 | |
| 
 | |
|             const ncm::ProgramLocation &GetProgramLocation() const {
 | |
|                 return this->loc;
 | |
|             }
 | |
| 
 | |
|             const cfg::OverrideStatus &GetOverrideStatus() const {
 | |
|                 return this->status;
 | |
|             }
 | |
| 
 | |
|             svc::ProcessState GetState() const {
 | |
|                 return this->state;
 | |
|             }
 | |
| 
 | |
|             void SetState(svc::ProcessState state) {
 | |
|                 this->state = state;
 | |
|             }
 | |
| 
 | |
|             bool HasStarted() const {
 | |
|                 return this->state != svc::ProcessState_Created && this->state != svc::ProcessState_CreatedAttached;
 | |
|             }
 | |
| 
 | |
|             bool HasTerminated() const {
 | |
|                 return this->state == svc::ProcessState_Terminated;
 | |
|             }
 | |
| 
 | |
| #define DEFINE_FLAG_SET(flag) \
 | |
|             void Set##flag() { \
 | |
|                 this->SetFlag(Flag_##flag); \
 | |
|             }
 | |
| 
 | |
| #define DEFINE_FLAG_GET(get, flag) \
 | |
|             bool get##flag() const { \
 | |
|                 return this->HasFlag(Flag_##flag); \
 | |
|             }
 | |
| 
 | |
| #define DEFINE_FLAG_CLEAR(flag) \
 | |
|             void Clear##flag() { \
 | |
|                 this->ClearFlag(Flag_##flag); \
 | |
|             }
 | |
| 
 | |
|             DEFINE_FLAG_SET(SignalOnExit)
 | |
|             DEFINE_FLAG_GET(Should, SignalOnExit)
 | |
| 
 | |
|             /* This needs a manual setter, because it sets two flags. */
 | |
|             void SetExceptionOccurred() {
 | |
|                 this->SetFlag(Flag_ExceptionOccurred);
 | |
|                 this->SetFlag(Flag_ExceptionWaitingAttach);
 | |
|             }
 | |
| 
 | |
|             DEFINE_FLAG_GET(Has, ExceptionOccurred)
 | |
|             DEFINE_FLAG_GET(Has, ExceptionWaitingAttach)
 | |
|             DEFINE_FLAG_CLEAR(ExceptionOccurred)
 | |
|             DEFINE_FLAG_CLEAR(ExceptionWaitingAttach)
 | |
| 
 | |
|             DEFINE_FLAG_SET(SignalOnDebugEvent)
 | |
|             DEFINE_FLAG_GET(Should, SignalOnDebugEvent)
 | |
| 
 | |
|             DEFINE_FLAG_SET(SuspendedStateChanged)
 | |
|             DEFINE_FLAG_GET(Has, SuspendedStateChanged)
 | |
|             DEFINE_FLAG_CLEAR(SuspendedStateChanged)
 | |
| 
 | |
|             DEFINE_FLAG_SET(Suspended)
 | |
|             DEFINE_FLAG_GET(Is, Suspended)
 | |
|             DEFINE_FLAG_CLEAR(Suspended)
 | |
| 
 | |
|             DEFINE_FLAG_SET(Application)
 | |
|             DEFINE_FLAG_GET(Is, Application)
 | |
| 
 | |
|             DEFINE_FLAG_SET(SignalOnStart)
 | |
|             DEFINE_FLAG_GET(Should, SignalOnStart)
 | |
|             DEFINE_FLAG_CLEAR(SignalOnStart)
 | |
| 
 | |
|             DEFINE_FLAG_SET(StartedStateChanged)
 | |
|             DEFINE_FLAG_GET(Has, StartedStateChanged)
 | |
|             DEFINE_FLAG_CLEAR(StartedStateChanged)
 | |
| 
 | |
| #undef DEFINE_FLAG_SET
 | |
| #undef DEFINE_FLAG_GET
 | |
| #undef DEFINE_FLAG_CLEAR
 | |
|     };
 | |
| 
 | |
|     class ProcessList final : public util::IntrusiveListMemberTraits<&ProcessInfo::list_node>::ListType {
 | |
|         private:
 | |
|             os::Mutex lock;
 | |
|         public:
 | |
|             constexpr ProcessList() : lock(false) { /* ... */ }
 | |
| 
 | |
|             void Lock() {
 | |
|                 this->lock.Lock();
 | |
|             }
 | |
| 
 | |
|             void Unlock() {
 | |
|                 this->lock.Unlock();
 | |
|             }
 | |
| 
 | |
|             void Remove(ProcessInfo *process_info) {
 | |
|                 this->erase(this->iterator_to(*process_info));
 | |
|             }
 | |
| 
 | |
|             ProcessInfo *Find(os::ProcessId process_id) {
 | |
|                 for (auto it = this->begin(); it != this->end(); it++) {
 | |
|                     if ((*it).GetProcessId() == process_id) {
 | |
|                         return &*it;
 | |
|                     }
 | |
|                 }
 | |
|                 return nullptr;
 | |
|             }
 | |
| 
 | |
|             ProcessInfo *Find(ncm::ProgramId program_id) {
 | |
|                 for (auto it = this->begin(); it != this->end(); it++) {
 | |
|                     if ((*it).GetProgramLocation().program_id == program_id) {
 | |
|                         return &*it;
 | |
|                     }
 | |
|                 }
 | |
|                 return nullptr;
 | |
|             }
 | |
| 
 | |
|     };
 | |
| 
 | |
|     class ProcessListAccessor final {
 | |
|         private:
 | |
|             ProcessList &list;
 | |
|         public:
 | |
|             explicit ProcessListAccessor(ProcessList &l) : list(l) {
 | |
|                 this->list.Lock();
 | |
|             }
 | |
| 
 | |
|             ~ProcessListAccessor() {
 | |
|                 this->list.Unlock();
 | |
|             }
 | |
| 
 | |
|             ProcessList *operator->() {
 | |
|                 return &this->list;
 | |
|             }
 | |
| 
 | |
|             const ProcessList *operator->() const {
 | |
|                 return &this->list;
 | |
|             }
 | |
| 
 | |
|             ProcessList &operator*() {
 | |
|                 return this->list;
 | |
|             }
 | |
| 
 | |
|             const ProcessList &operator*() const {
 | |
|                 return this->list;
 | |
|             }
 | |
|     };
 | |
| 
 | |
| }
 |