mirror of
				https://git.zaroz.cloud/nintendo-back-up/yuzu/yuzu.git
				synced 2025-05-12 00:45:25 +00:00 
			
		
		
		
	Merge pull request #523 from yuriks/kernel-lifetime5
Kernel Lifetime Reform Pt. 5: The Reckoning
This commit is contained in:
		
						commit
						7f730ed158
					
				
							
								
								
									
										2
									
								
								externals/boost
									
									
									
									
										vendored
									
									
								
							
							
								
								
								
								
								
								
							
						
						
									
										2
									
								
								externals/boost
									
									
									
									
										vendored
									
									
								
							| @ -1 +1 @@ | |||||||
| Subproject commit a1afc91d3aaa3da06bdbc13c78613e1466653405 | Subproject commit 728a4d7d1c8b28355544ae829df9c4b5f28373c5 | ||||||
| @ -26,6 +26,7 @@ set(SRCS | |||||||
|             hle/kernel/kernel.cpp |             hle/kernel/kernel.cpp | ||||||
|             hle/kernel/mutex.cpp |             hle/kernel/mutex.cpp | ||||||
|             hle/kernel/semaphore.cpp |             hle/kernel/semaphore.cpp | ||||||
|  |             hle/kernel/session.cpp | ||||||
|             hle/kernel/shared_memory.cpp |             hle/kernel/shared_memory.cpp | ||||||
|             hle/kernel/timer.cpp |             hle/kernel/timer.cpp | ||||||
|             hle/kernel/thread.cpp |             hle/kernel/thread.cpp | ||||||
|  | |||||||
| @ -15,14 +15,15 @@ | |||||||
| 
 | 
 | ||||||
| namespace Kernel { | namespace Kernel { | ||||||
| 
 | 
 | ||||||
| ResultVal<SharedPtr<AddressArbiter>> AddressArbiter::Create(std::string name) { | AddressArbiter::AddressArbiter() {} | ||||||
|  | AddressArbiter::~AddressArbiter() {} | ||||||
|  | 
 | ||||||
|  | SharedPtr<AddressArbiter> AddressArbiter::Create(std::string name) { | ||||||
|     SharedPtr<AddressArbiter> address_arbiter(new AddressArbiter); |     SharedPtr<AddressArbiter> address_arbiter(new AddressArbiter); | ||||||
|     // TOOD(yuriks): Don't create Handle (see Thread::Create())
 |  | ||||||
|     CASCADE_RESULT(auto unused, Kernel::g_handle_table.Create(address_arbiter)); |  | ||||||
| 
 | 
 | ||||||
|     address_arbiter->name = std::move(name); |     address_arbiter->name = std::move(name); | ||||||
| 
 | 
 | ||||||
|     return MakeResult<SharedPtr<AddressArbiter>>(std::move(address_arbiter)); |     return address_arbiter; | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| ResultCode AddressArbiter::ArbitrateAddress(ArbitrationType type, VAddr address, s32 value, | ResultCode AddressArbiter::ArbitrateAddress(ArbitrationType type, VAddr address, s32 value, | ||||||
| @ -51,7 +52,7 @@ ResultCode AddressArbiter::ArbitrateAddress(ArbitrationType type, VAddr address, | |||||||
|     case ArbitrationType::WaitIfLessThanWithTimeout: |     case ArbitrationType::WaitIfLessThanWithTimeout: | ||||||
|         if ((s32)Memory::Read32(address) <= value) { |         if ((s32)Memory::Read32(address) <= value) { | ||||||
|             Kernel::WaitCurrentThread_ArbitrateAddress(address); |             Kernel::WaitCurrentThread_ArbitrateAddress(address); | ||||||
|             Kernel::WakeThreadAfterDelay(GetCurrentThread(), nanoseconds); |             GetCurrentThread()->WakeAfterDelay(nanoseconds); | ||||||
|             HLE::Reschedule(__func__); |             HLE::Reschedule(__func__); | ||||||
|         } |         } | ||||||
|         break; |         break; | ||||||
| @ -71,7 +72,7 @@ ResultCode AddressArbiter::ArbitrateAddress(ArbitrationType type, VAddr address, | |||||||
|         Memory::Write32(address, memory_value); |         Memory::Write32(address, memory_value); | ||||||
|         if (memory_value <= value) { |         if (memory_value <= value) { | ||||||
|             Kernel::WaitCurrentThread_ArbitrateAddress(address); |             Kernel::WaitCurrentThread_ArbitrateAddress(address); | ||||||
|             Kernel::WakeThreadAfterDelay(GetCurrentThread(), nanoseconds); |             GetCurrentThread()->WakeAfterDelay(nanoseconds); | ||||||
|             HLE::Reschedule(__func__); |             HLE::Reschedule(__func__); | ||||||
|         } |         } | ||||||
|         break; |         break; | ||||||
|  | |||||||
| @ -34,7 +34,7 @@ public: | |||||||
|      * @param name Optional name used for debugging. |      * @param name Optional name used for debugging. | ||||||
|      * @returns The created AddressArbiter. |      * @returns The created AddressArbiter. | ||||||
|      */ |      */ | ||||||
|     static ResultVal<SharedPtr<AddressArbiter>> Create(std::string name = "Unknown"); |     static SharedPtr<AddressArbiter> Create(std::string name = "Unknown"); | ||||||
| 
 | 
 | ||||||
|     std::string GetTypeName() const override { return "Arbiter"; } |     std::string GetTypeName() const override { return "Arbiter"; } | ||||||
|     std::string GetName() const override { return name; } |     std::string GetName() const override { return name; } | ||||||
| @ -47,7 +47,8 @@ public: | |||||||
|     ResultCode ArbitrateAddress(ArbitrationType type, VAddr address, s32 value, u64 nanoseconds); |     ResultCode ArbitrateAddress(ArbitrationType type, VAddr address, s32 value, u64 nanoseconds); | ||||||
| 
 | 
 | ||||||
| private: | private: | ||||||
|     AddressArbiter() = default; |     AddressArbiter(); | ||||||
|  |     ~AddressArbiter() override; | ||||||
| }; | }; | ||||||
| 
 | 
 | ||||||
| } // namespace FileSys
 | } // namespace FileSys
 | ||||||
|  | |||||||
| @ -14,16 +14,17 @@ | |||||||
| 
 | 
 | ||||||
| namespace Kernel { | namespace Kernel { | ||||||
| 
 | 
 | ||||||
| ResultVal<SharedPtr<Event>> Event::Create(ResetType reset_type, std::string name) { | Event::Event() {} | ||||||
|  | Event::~Event() {} | ||||||
|  | 
 | ||||||
|  | SharedPtr<Event> Event::Create(ResetType reset_type, std::string name) { | ||||||
|     SharedPtr<Event> evt(new Event); |     SharedPtr<Event> evt(new Event); | ||||||
|     // TOOD(yuriks): Don't create Handle (see Thread::Create())
 |  | ||||||
|     CASCADE_RESULT(auto unused, Kernel::g_handle_table.Create(evt)); |  | ||||||
| 
 | 
 | ||||||
|     evt->signaled = false; |     evt->signaled = false; | ||||||
|     evt->reset_type = evt->intitial_reset_type = reset_type; |     evt->reset_type = evt->intitial_reset_type = reset_type; | ||||||
|     evt->name = std::move(name); |     evt->name = std::move(name); | ||||||
| 
 | 
 | ||||||
|     return MakeResult<SharedPtr<Event>>(evt); |     return evt; | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| bool Event::ShouldWait() { | bool Event::ShouldWait() { | ||||||
|  | |||||||
| @ -18,7 +18,7 @@ public: | |||||||
|      * @param reset_type ResetType describing how to create event |      * @param reset_type ResetType describing how to create event | ||||||
|      * @param name Optional name of event |      * @param name Optional name of event | ||||||
|      */ |      */ | ||||||
|     static ResultVal<SharedPtr<Event>> Create(ResetType reset_type, std::string name = "Unknown"); |     static SharedPtr<Event> Create(ResetType reset_type, std::string name = "Unknown"); | ||||||
| 
 | 
 | ||||||
|     std::string GetTypeName() const override { return "Event"; } |     std::string GetTypeName() const override { return "Event"; } | ||||||
|     std::string GetName() const override { return name; } |     std::string GetName() const override { return name; } | ||||||
| @ -39,7 +39,8 @@ public: | |||||||
|     void Clear(); |     void Clear(); | ||||||
| 
 | 
 | ||||||
| private: | private: | ||||||
|     Event() = default; |     Event(); | ||||||
|  |     ~Event() override; | ||||||
| }; | }; | ||||||
| 
 | 
 | ||||||
| } // namespace
 | } // namespace
 | ||||||
|  | |||||||
| @ -14,14 +14,16 @@ | |||||||
| 
 | 
 | ||||||
| namespace Kernel { | namespace Kernel { | ||||||
| 
 | 
 | ||||||
|  | unsigned int Object::next_object_id = 0; | ||||||
|  | 
 | ||||||
| SharedPtr<Thread> g_main_thread = nullptr; | SharedPtr<Thread> g_main_thread = nullptr; | ||||||
| HandleTable g_handle_table; | HandleTable g_handle_table; | ||||||
| u64 g_program_id = 0; | u64 g_program_id = 0; | ||||||
| 
 | 
 | ||||||
| void WaitObject::AddWaitingThread(Thread* thread) { | void WaitObject::AddWaitingThread(SharedPtr<Thread> thread) { | ||||||
|     auto itr = std::find(waiting_threads.begin(), waiting_threads.end(), thread); |     auto itr = std::find(waiting_threads.begin(), waiting_threads.end(), thread); | ||||||
|     if (itr == waiting_threads.end()) |     if (itr == waiting_threads.end()) | ||||||
|         waiting_threads.push_back(thread); |         waiting_threads.push_back(std::move(thread)); | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| void WaitObject::RemoveWaitingThread(Thread* thread) { | void WaitObject::RemoveWaitingThread(Thread* thread) { | ||||||
| @ -30,11 +32,11 @@ void WaitObject::RemoveWaitingThread(Thread* thread) { | |||||||
|         waiting_threads.erase(itr); |         waiting_threads.erase(itr); | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| Thread* WaitObject::WakeupNextThread() { | SharedPtr<Thread> WaitObject::WakeupNextThread() { | ||||||
|     if (waiting_threads.empty()) |     if (waiting_threads.empty()) | ||||||
|         return nullptr; |         return nullptr; | ||||||
| 
 | 
 | ||||||
|     auto next_thread = waiting_threads.front(); |     auto next_thread = std::move(waiting_threads.front()); | ||||||
|     waiting_threads.erase(waiting_threads.begin()); |     waiting_threads.erase(waiting_threads.begin()); | ||||||
| 
 | 
 | ||||||
|     next_thread->ReleaseWaitObject(this); |     next_thread->ReleaseWaitObject(this); | ||||||
| @ -74,13 +76,10 @@ ResultVal<Handle> HandleTable::Create(SharedPtr<Object> obj) { | |||||||
|     // CTR-OS doesn't use generation 0, so skip straight to 1.
 |     // CTR-OS doesn't use generation 0, so skip straight to 1.
 | ||||||
|     if (next_generation >= (1 << 15)) next_generation = 1; |     if (next_generation >= (1 << 15)) next_generation = 1; | ||||||
| 
 | 
 | ||||||
|     Handle handle = generation | (slot << 15); |  | ||||||
|     if (obj->handle == INVALID_HANDLE) |  | ||||||
|         obj->handle = handle; |  | ||||||
| 
 |  | ||||||
|     generations[slot] = generation; |     generations[slot] = generation; | ||||||
|     objects[slot] = std::move(obj); |     objects[slot] = std::move(obj); | ||||||
| 
 | 
 | ||||||
|  |     Handle handle = generation | (slot << 15); | ||||||
|     return MakeResult<Handle>(handle); |     return MakeResult<Handle>(handle); | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| @ -102,7 +101,7 @@ ResultCode HandleTable::Close(Handle handle) { | |||||||
| 
 | 
 | ||||||
|     objects[slot] = nullptr; |     objects[slot] = nullptr; | ||||||
| 
 | 
 | ||||||
|     generations[generation] = next_free_slot; |     generations[slot] = next_free_slot; | ||||||
|     next_free_slot = slot; |     next_free_slot = slot; | ||||||
|     return RESULT_SUCCESS; |     return RESULT_SUCCESS; | ||||||
| } | } | ||||||
|  | |||||||
| @ -58,14 +58,12 @@ enum { | |||||||
|     DEFAULT_STACK_SIZE  = 0x4000, |     DEFAULT_STACK_SIZE  = 0x4000, | ||||||
| }; | }; | ||||||
| 
 | 
 | ||||||
| class HandleTable; |  | ||||||
| 
 |  | ||||||
| class Object : NonCopyable { | class Object : NonCopyable { | ||||||
|     friend class HandleTable; |  | ||||||
|     u32 handle = INVALID_HANDLE; |  | ||||||
| public: | public: | ||||||
|     virtual ~Object() {} |     virtual ~Object() {} | ||||||
|     Handle GetHandle() const { return handle; } | 
 | ||||||
|  |     /// Returns a unique identifier for the object. For debugging purposes only.
 | ||||||
|  |     unsigned int GetObjectId() const { return object_id; } | ||||||
| 
 | 
 | ||||||
|     virtual std::string GetTypeName() const { return "[BAD KERNEL OBJECT TYPE]"; } |     virtual std::string GetTypeName() const { return "[BAD KERNEL OBJECT TYPE]"; } | ||||||
|     virtual std::string GetName() const { return "[UNKNOWN KERNEL OBJECT]"; } |     virtual std::string GetName() const { return "[UNKNOWN KERNEL OBJECT]"; } | ||||||
| @ -101,7 +99,10 @@ private: | |||||||
|     friend void intrusive_ptr_add_ref(Object*); |     friend void intrusive_ptr_add_ref(Object*); | ||||||
|     friend void intrusive_ptr_release(Object*); |     friend void intrusive_ptr_release(Object*); | ||||||
| 
 | 
 | ||||||
|  |     static unsigned int next_object_id; | ||||||
|  | 
 | ||||||
|     unsigned int ref_count = 0; |     unsigned int ref_count = 0; | ||||||
|  |     unsigned int object_id = next_object_id++; | ||||||
| }; | }; | ||||||
| 
 | 
 | ||||||
| // Special functions used by boost::instrusive_ptr to do automatic ref-counting
 | // Special functions used by boost::instrusive_ptr to do automatic ref-counting
 | ||||||
| @ -135,25 +136,26 @@ public: | |||||||
|      * Add a thread to wait on this object |      * Add a thread to wait on this object | ||||||
|      * @param thread Pointer to thread to add |      * @param thread Pointer to thread to add | ||||||
|      */ |      */ | ||||||
|     void AddWaitingThread(Thread* thread); |     void AddWaitingThread(SharedPtr<Thread> thread); | ||||||
| 
 | 
 | ||||||
|     /**
 |     /**
 | ||||||
|      * Removes a thread from waiting on this object (e.g. if it was resumed already) |      * Removes a thread from waiting on this object (e.g. if it was resumed already) | ||||||
|      * @param thread Pointer to thread to remove |      * @param thread Pointer to thread to remove | ||||||
|      */ |      */ | ||||||
|     void RemoveWaitingThread(Thread* thead); |     void RemoveWaitingThread(Thread* thread); | ||||||
| 
 | 
 | ||||||
|     /**
 |     /**
 | ||||||
|      * Wake up the next thread waiting on this object |      * Wake up the next thread waiting on this object | ||||||
|      * @return Pointer to the thread that was resumed, nullptr if no threads are waiting |      * @return Pointer to the thread that was resumed, nullptr if no threads are waiting | ||||||
|      */ |      */ | ||||||
|     Thread* WakeupNextThread(); |     SharedPtr<Thread> WakeupNextThread(); | ||||||
| 
 | 
 | ||||||
|     /// Wake up all threads waiting on this object
 |     /// Wake up all threads waiting on this object
 | ||||||
|     void WakeupAllWaitingThreads(); |     void WakeupAllWaitingThreads(); | ||||||
| 
 | 
 | ||||||
| private: | private: | ||||||
|     std::vector<Thread*> waiting_threads; ///< Threads waiting for this object to become available
 |     /// Threads waiting for this object to become available
 | ||||||
|  |     std::vector<SharedPtr<Thread>> waiting_threads; | ||||||
| }; | }; | ||||||
| 
 | 
 | ||||||
| /**
 | /**
 | ||||||
| @ -274,7 +276,6 @@ private: | |||||||
| }; | }; | ||||||
| 
 | 
 | ||||||
| extern HandleTable g_handle_table; | extern HandleTable g_handle_table; | ||||||
| extern SharedPtr<Thread> g_main_thread; |  | ||||||
| 
 | 
 | ||||||
| /// The ID code of the currently running game
 | /// The ID code of the currently running game
 | ||||||
| /// TODO(Subv): This variable should not be here, 
 | /// TODO(Subv): This variable should not be here, 
 | ||||||
|  | |||||||
| @ -5,6 +5,8 @@ | |||||||
| #include <map> | #include <map> | ||||||
| #include <vector> | #include <vector> | ||||||
| 
 | 
 | ||||||
|  | #include <boost/range/algorithm_ext/erase.hpp> | ||||||
|  | 
 | ||||||
| #include "common/common.h" | #include "common/common.h" | ||||||
| 
 | 
 | ||||||
| #include "core/hle/kernel/kernel.h" | #include "core/hle/kernel/kernel.h" | ||||||
| @ -13,9 +15,6 @@ | |||||||
| 
 | 
 | ||||||
| namespace Kernel { | namespace Kernel { | ||||||
| 
 | 
 | ||||||
| typedef std::multimap<SharedPtr<Thread>, SharedPtr<Mutex>> MutexMap; |  | ||||||
| static MutexMap g_mutex_held_locks; |  | ||||||
| 
 |  | ||||||
| /**
 | /**
 | ||||||
|  * Resumes a thread waiting for the specified mutex |  * Resumes a thread waiting for the specified mutex | ||||||
|  * @param mutex The mutex that some thread is waiting on |  * @param mutex The mutex that some thread is waiting on | ||||||
| @ -33,21 +32,17 @@ static void ResumeWaitingThread(Mutex* mutex) { | |||||||
| } | } | ||||||
| 
 | 
 | ||||||
| void ReleaseThreadMutexes(Thread* thread) { | void ReleaseThreadMutexes(Thread* thread) { | ||||||
|     auto locked_range = g_mutex_held_locks.equal_range(thread); |     for (auto& mtx : thread->held_mutexes) { | ||||||
|      |         ResumeWaitingThread(mtx.get()); | ||||||
|     // Release every mutex that the thread holds, and resume execution on the waiting threads
 |     } | ||||||
|     for (auto iter = locked_range.first; iter != locked_range.second; ++iter) { |     thread->held_mutexes.clear(); | ||||||
|         ResumeWaitingThread(iter->second.get()); |  | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
|     // Erase all the locks that this thread holds
 | Mutex::Mutex() {} | ||||||
|     g_mutex_held_locks.erase(thread); | Mutex::~Mutex() {} | ||||||
| } |  | ||||||
| 
 | 
 | ||||||
| ResultVal<SharedPtr<Mutex>> Mutex::Create(bool initial_locked, std::string name) { | SharedPtr<Mutex> Mutex::Create(bool initial_locked, std::string name) { | ||||||
|     SharedPtr<Mutex> mutex(new Mutex); |     SharedPtr<Mutex> mutex(new Mutex); | ||||||
|     // TOOD(yuriks): Don't create Handle (see Thread::Create())
 |  | ||||||
|     CASCADE_RESULT(auto unused, Kernel::g_handle_table.Create(mutex)); |  | ||||||
| 
 | 
 | ||||||
|     mutex->initial_locked = initial_locked; |     mutex->initial_locked = initial_locked; | ||||||
|     mutex->locked = false; |     mutex->locked = false; | ||||||
| @ -58,7 +53,7 @@ ResultVal<SharedPtr<Mutex>> Mutex::Create(bool initial_locked, std::string name) | |||||||
|     if (initial_locked) |     if (initial_locked) | ||||||
|         mutex->Acquire(); |         mutex->Acquire(); | ||||||
| 
 | 
 | ||||||
|     return MakeResult<SharedPtr<Mutex>>(mutex); |     return mutex; | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| bool Mutex::ShouldWait() { | bool Mutex::ShouldWait() { | ||||||
| @ -69,30 +64,22 @@ void Mutex::Acquire() { | |||||||
|     Acquire(GetCurrentThread()); |     Acquire(GetCurrentThread()); | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| void Mutex::Acquire(Thread* thread) { | void Mutex::Acquire(SharedPtr<Thread> thread) { | ||||||
|     _assert_msg_(Kernel, !ShouldWait(), "object unavailable!"); |     _assert_msg_(Kernel, !ShouldWait(), "object unavailable!"); | ||||||
|     if (locked) |     if (locked) | ||||||
|         return; |         return; | ||||||
| 
 | 
 | ||||||
|     locked = true; |     locked = true; | ||||||
| 
 | 
 | ||||||
|     g_mutex_held_locks.insert(std::make_pair(thread, this)); |     thread->held_mutexes.insert(this); | ||||||
|     holding_thread = thread; |     holding_thread = std::move(thread); | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| void Mutex::Release() { | void Mutex::Release() { | ||||||
|     if (!locked) |     if (!locked) | ||||||
|         return; |         return; | ||||||
| 
 | 
 | ||||||
|     auto locked_range = g_mutex_held_locks.equal_range(holding_thread); |     holding_thread->held_mutexes.erase(this); | ||||||
| 
 |  | ||||||
|     for (MutexMap::iterator iter = locked_range.first; iter != locked_range.second; ++iter) { |  | ||||||
|         if (iter->second == this) { |  | ||||||
|             g_mutex_held_locks.erase(iter); |  | ||||||
|             break; |  | ||||||
|         } |  | ||||||
|     } |  | ||||||
| 
 |  | ||||||
|     ResumeWaitingThread(this); |     ResumeWaitingThread(this); | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
|  | |||||||
| @ -22,7 +22,7 @@ public: | |||||||
|      * @param name Optional name of mutex |      * @param name Optional name of mutex | ||||||
|      * @return Pointer to new Mutex object |      * @return Pointer to new Mutex object | ||||||
|      */ |      */ | ||||||
|     static ResultVal<SharedPtr<Mutex>> Create(bool initial_locked, std::string name = "Unknown"); |     static SharedPtr<Mutex> Create(bool initial_locked, std::string name = "Unknown"); | ||||||
| 
 | 
 | ||||||
|     std::string GetTypeName() const override { return "Mutex"; } |     std::string GetTypeName() const override { return "Mutex"; } | ||||||
|     std::string GetName() const override { return name; } |     std::string GetName() const override { return name; } | ||||||
| @ -43,11 +43,12 @@ public: | |||||||
|     * @param mutex Mutex that is to be acquired |     * @param mutex Mutex that is to be acquired | ||||||
|     * @param thread Thread that will acquire the mutex |     * @param thread Thread that will acquire the mutex | ||||||
|     */ |     */ | ||||||
|     void Acquire(Thread* thread); |     void Acquire(SharedPtr<Thread> thread); | ||||||
|     void Release(); |     void Release(); | ||||||
| 
 | 
 | ||||||
| private: | private: | ||||||
|     Mutex() = default; |     Mutex(); | ||||||
|  |     ~Mutex() override; | ||||||
| }; | }; | ||||||
| 
 | 
 | ||||||
| /**
 | /**
 | ||||||
|  | |||||||
| @ -10,6 +10,9 @@ | |||||||
| 
 | 
 | ||||||
| namespace Kernel { | namespace Kernel { | ||||||
| 
 | 
 | ||||||
|  | Semaphore::Semaphore() {} | ||||||
|  | Semaphore::~Semaphore() {} | ||||||
|  | 
 | ||||||
| ResultVal<SharedPtr<Semaphore>> Semaphore::Create(s32 initial_count, s32 max_count, | ResultVal<SharedPtr<Semaphore>> Semaphore::Create(s32 initial_count, s32 max_count, | ||||||
|         std::string name) { |         std::string name) { | ||||||
| 
 | 
 | ||||||
| @ -18,8 +21,6 @@ ResultVal<SharedPtr<Semaphore>> Semaphore::Create(s32 initial_count, s32 max_cou | |||||||
|                           ErrorSummary::WrongArgument, ErrorLevel::Permanent); |                           ErrorSummary::WrongArgument, ErrorLevel::Permanent); | ||||||
| 
 | 
 | ||||||
|     SharedPtr<Semaphore> semaphore(new Semaphore); |     SharedPtr<Semaphore> semaphore(new Semaphore); | ||||||
|     // TOOD(yuriks): Don't create Handle (see Thread::Create())
 |  | ||||||
|     CASCADE_RESULT(auto unused, Kernel::g_handle_table.Create(semaphore)); |  | ||||||
| 
 | 
 | ||||||
|     // When the semaphore is created, some slots are reserved for other threads,
 |     // When the semaphore is created, some slots are reserved for other threads,
 | ||||||
|     // and the rest is reserved for the caller thread
 |     // and the rest is reserved for the caller thread
 | ||||||
|  | |||||||
| @ -47,7 +47,8 @@ public: | |||||||
|     ResultVal<s32> Release(s32 release_count); |     ResultVal<s32> Release(s32 release_count); | ||||||
| 
 | 
 | ||||||
| private: | private: | ||||||
|     Semaphore() = default; |     Semaphore(); | ||||||
|  |     ~Semaphore() override; | ||||||
| }; | }; | ||||||
| 
 | 
 | ||||||
| } // namespace
 | } // namespace
 | ||||||
|  | |||||||
							
								
								
									
										13
									
								
								src/core/hle/kernel/session.cpp
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										13
									
								
								src/core/hle/kernel/session.cpp
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,13 @@ | |||||||
|  | // Copyright 2015 Citra Emulator Project
 | ||||||
|  | // Licensed under GPLv2 or any later version
 | ||||||
|  | // Refer to the license.txt file included.
 | ||||||
|  | 
 | ||||||
|  | #include "core/hle/kernel/session.h" | ||||||
|  | #include "core/hle/kernel/thread.h" | ||||||
|  | 
 | ||||||
|  | namespace Kernel { | ||||||
|  | 
 | ||||||
|  | Session::Session() {} | ||||||
|  | Session::~Session() {} | ||||||
|  | 
 | ||||||
|  | } | ||||||
| @ -5,6 +5,7 @@ | |||||||
| #pragma once | #pragma once | ||||||
| 
 | 
 | ||||||
| #include "core/hle/kernel/kernel.h" | #include "core/hle/kernel/kernel.h" | ||||||
|  | #include "core/mem_map.h" | ||||||
| 
 | 
 | ||||||
| namespace Kernel { | namespace Kernel { | ||||||
| 
 | 
 | ||||||
| @ -43,6 +44,9 @@ inline static u32* GetCommandBuffer(const int offset=0) { | |||||||
|  */ |  */ | ||||||
| class Session : public WaitObject { | class Session : public WaitObject { | ||||||
| public: | public: | ||||||
|  |     Session(); | ||||||
|  |     ~Session() override; | ||||||
|  | 
 | ||||||
|     std::string GetTypeName() const override { return "Session"; } |     std::string GetTypeName() const override { return "Session"; } | ||||||
| 
 | 
 | ||||||
|     static const HandleType HANDLE_TYPE = HandleType::Session; |     static const HandleType HANDLE_TYPE = HandleType::Session; | ||||||
|  | |||||||
| @ -9,22 +9,23 @@ | |||||||
| 
 | 
 | ||||||
| namespace Kernel { | namespace Kernel { | ||||||
| 
 | 
 | ||||||
| ResultVal<SharedPtr<SharedMemory>> SharedMemory::Create(std::string name) { | SharedMemory::SharedMemory() {} | ||||||
|  | SharedMemory::~SharedMemory() {} | ||||||
|  | 
 | ||||||
|  | SharedPtr<SharedMemory> SharedMemory::Create(std::string name) { | ||||||
|     SharedPtr<SharedMemory> shared_memory(new SharedMemory); |     SharedPtr<SharedMemory> shared_memory(new SharedMemory); | ||||||
| 
 | 
 | ||||||
|     // TOOD(yuriks): Don't create Handle (see Thread::Create())
 |  | ||||||
|     CASCADE_RESULT(auto unused, Kernel::g_handle_table.Create(shared_memory)); |  | ||||||
| 
 |  | ||||||
|     shared_memory->name = std::move(name); |     shared_memory->name = std::move(name); | ||||||
|     return MakeResult<SharedPtr<SharedMemory>>(std::move(shared_memory)); | 
 | ||||||
|  |     return shared_memory; | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| ResultCode SharedMemory::Map(VAddr address, MemoryPermission permissions, | ResultCode SharedMemory::Map(VAddr address, MemoryPermission permissions, | ||||||
|         MemoryPermission other_permissions) { |         MemoryPermission other_permissions) { | ||||||
| 
 | 
 | ||||||
|     if (address < Memory::SHARED_MEMORY_VADDR || address >= Memory::SHARED_MEMORY_VADDR_END) { |     if (address < Memory::SHARED_MEMORY_VADDR || address >= Memory::SHARED_MEMORY_VADDR_END) { | ||||||
|         LOG_ERROR(Kernel, "cannot map handle=0x%08X, address=0x%08X outside of shared mem bounds!", |         LOG_ERROR(Kernel, "cannot map id=%u, address=0x%08X outside of shared mem bounds!", | ||||||
|                 GetHandle(), address); |                 GetObjectId(), address); | ||||||
|         // TODO: Verify error code with hardware
 |         // TODO: Verify error code with hardware
 | ||||||
|         return ResultCode(ErrorDescription::InvalidAddress, ErrorModule::Kernel, |         return ResultCode(ErrorDescription::InvalidAddress, ErrorModule::Kernel, | ||||||
|                 ErrorSummary::InvalidArgument, ErrorLevel::Permanent); |                 ErrorSummary::InvalidArgument, ErrorLevel::Permanent); | ||||||
| @ -41,7 +42,7 @@ ResultVal<u8*> SharedMemory::GetPointer(u32 offset) { | |||||||
|     if (base_address != 0) |     if (base_address != 0) | ||||||
|         return MakeResult<u8*>(Memory::GetPointer(base_address + offset)); |         return MakeResult<u8*>(Memory::GetPointer(base_address + offset)); | ||||||
| 
 | 
 | ||||||
|     LOG_ERROR(Kernel_SVC, "memory block handle=0x%08X not mapped!", GetHandle()); |     LOG_ERROR(Kernel_SVC, "memory block id=%u not mapped!", GetObjectId()); | ||||||
|     // TODO(yuriks): Verify error code.
 |     // TODO(yuriks): Verify error code.
 | ||||||
|     return ResultCode(ErrorDescription::InvalidAddress, ErrorModule::Kernel, |     return ResultCode(ErrorDescription::InvalidAddress, ErrorModule::Kernel, | ||||||
|             ErrorSummary::InvalidState, ErrorLevel::Permanent); |             ErrorSummary::InvalidState, ErrorLevel::Permanent); | ||||||
|  | |||||||
| @ -29,7 +29,7 @@ public: | |||||||
|      * Creates a shared memory object |      * Creates a shared memory object | ||||||
|      * @param name Optional object name, used only for debugging purposes. |      * @param name Optional object name, used only for debugging purposes. | ||||||
|      */ |      */ | ||||||
|     static ResultVal<SharedPtr<SharedMemory>> Create(std::string name = "Unknown"); |     static SharedPtr<SharedMemory> Create(std::string name = "Unknown"); | ||||||
| 
 | 
 | ||||||
|     std::string GetTypeName() const override { return "SharedMemory"; } |     std::string GetTypeName() const override { return "SharedMemory"; } | ||||||
| 
 | 
 | ||||||
| @ -57,7 +57,8 @@ public: | |||||||
|     std::string name;                   ///< Name of shared memory object (optional)
 |     std::string name;                   ///< Name of shared memory object (optional)
 | ||||||
| 
 | 
 | ||||||
| private: | private: | ||||||
|     SharedMemory() = default; |     SharedMemory(); | ||||||
|  |     ~SharedMemory() override; | ||||||
| }; | }; | ||||||
| 
 | 
 | ||||||
| } // namespace
 | } // namespace
 | ||||||
|  | |||||||
| @ -4,7 +4,6 @@ | |||||||
| 
 | 
 | ||||||
| #include <algorithm> | #include <algorithm> | ||||||
| #include <list> | #include <list> | ||||||
| #include <map> |  | ||||||
| #include <vector> | #include <vector> | ||||||
| 
 | 
 | ||||||
| #include "common/common.h" | #include "common/common.h" | ||||||
| @ -41,6 +40,9 @@ static Thread* current_thread; | |||||||
| static const u32 INITIAL_THREAD_ID = 1; ///< The first available thread id at startup
 | static const u32 INITIAL_THREAD_ID = 1; ///< The first available thread id at startup
 | ||||||
| static u32 next_thread_id; ///< The next available thread id
 | static u32 next_thread_id; ///< The next available thread id
 | ||||||
| 
 | 
 | ||||||
|  | Thread::Thread() {} | ||||||
|  | Thread::~Thread() {} | ||||||
|  | 
 | ||||||
| Thread* GetCurrentThread() { | Thread* GetCurrentThread() { | ||||||
|     return current_thread; |     return current_thread; | ||||||
| } | } | ||||||
| @ -108,6 +110,9 @@ void Thread::Stop(const char* reason) { | |||||||
|     WakeupAllWaitingThreads(); |     WakeupAllWaitingThreads(); | ||||||
| 
 | 
 | ||||||
|     // Stopped threads are never waiting.
 |     // Stopped threads are never waiting.
 | ||||||
|  |     for (auto& wait_object : wait_objects) { | ||||||
|  |         wait_object->RemoveWaitingThread(this); | ||||||
|  |     } | ||||||
|     wait_objects.clear(); |     wait_objects.clear(); | ||||||
|     wait_address = 0; |     wait_address = 0; | ||||||
| } | } | ||||||
| @ -228,13 +233,15 @@ void WaitCurrentThread_ArbitrateAddress(VAddr wait_address) { | |||||||
| 
 | 
 | ||||||
| /// Event type for the thread wake up event
 | /// Event type for the thread wake up event
 | ||||||
| static int ThreadWakeupEventType = -1; | static int ThreadWakeupEventType = -1; | ||||||
|  | // TODO(yuriks): This can be removed if Thread objects are explicitly pooled in the future, allowing
 | ||||||
|  | //               us to simply use a pool index or similar.
 | ||||||
|  | static Kernel::HandleTable wakeup_callback_handle_table; | ||||||
| 
 | 
 | ||||||
| /// Callback that will wake up the thread it was scheduled for
 | /// Callback that will wake up the thread it was scheduled for
 | ||||||
| static void ThreadWakeupCallback(u64 parameter, int cycles_late) { | static void ThreadWakeupCallback(u64 thread_handle, int cycles_late) { | ||||||
|     Handle handle = static_cast<Handle>(parameter); |     SharedPtr<Thread> thread = wakeup_callback_handle_table.Get<Thread>((Handle)thread_handle); | ||||||
|     SharedPtr<Thread> thread = Kernel::g_handle_table.Get<Thread>(handle); |  | ||||||
|     if (thread == nullptr) { |     if (thread == nullptr) { | ||||||
|         LOG_ERROR(Kernel, "Thread doesn't exist %u", handle); |         LOG_CRITICAL(Kernel, "Callback fired for invalid thread %08X", thread_handle); | ||||||
|         return; |         return; | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
| @ -248,14 +255,13 @@ static void ThreadWakeupCallback(u64 parameter, int cycles_late) { | |||||||
| } | } | ||||||
| 
 | 
 | ||||||
| 
 | 
 | ||||||
| void WakeThreadAfterDelay(Thread* thread, s64 nanoseconds) { | void Thread::WakeAfterDelay(s64 nanoseconds) { | ||||||
|     // Don't schedule a wakeup if the thread wants to wait forever
 |     // Don't schedule a wakeup if the thread wants to wait forever
 | ||||||
|     if (nanoseconds == -1) |     if (nanoseconds == -1) | ||||||
|         return; |         return; | ||||||
|     _dbg_assert_(Kernel, thread != nullptr); |  | ||||||
| 
 | 
 | ||||||
|     u64 microseconds = nanoseconds / 1000; |     u64 microseconds = nanoseconds / 1000; | ||||||
|     CoreTiming::ScheduleEvent(usToCycles(microseconds), ThreadWakeupEventType, thread->GetHandle()); |     CoreTiming::ScheduleEvent(usToCycles(microseconds), ThreadWakeupEventType, callback_handle); | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| void Thread::ReleaseWaitObject(WaitObject* wait_object) { | void Thread::ReleaseWaitObject(WaitObject* wait_object) { | ||||||
| @ -302,7 +308,7 @@ void Thread::ReleaseWaitObject(WaitObject* wait_object) { | |||||||
| 
 | 
 | ||||||
| void Thread::ResumeFromWait() { | void Thread::ResumeFromWait() { | ||||||
|     // Cancel any outstanding wakeup events
 |     // Cancel any outstanding wakeup events
 | ||||||
|     CoreTiming::UnscheduleEvent(ThreadWakeupEventType, GetHandle()); |     CoreTiming::UnscheduleEvent(ThreadWakeupEventType, callback_handle); | ||||||
| 
 | 
 | ||||||
|     status &= ~THREADSTATUS_WAIT; |     status &= ~THREADSTATUS_WAIT; | ||||||
| 
 | 
 | ||||||
| @ -326,11 +332,11 @@ static void DebugThreadQueue() { | |||||||
|     if (!thread) { |     if (!thread) { | ||||||
|         return; |         return; | ||||||
|     } |     } | ||||||
|     LOG_DEBUG(Kernel, "0x%02X 0x%08X (current)", thread->current_priority, GetCurrentThread()->GetHandle()); |     LOG_DEBUG(Kernel, "0x%02X %u (current)", thread->current_priority, GetCurrentThread()->GetObjectId()); | ||||||
|     for (auto& t : thread_list) { |     for (auto& t : thread_list) { | ||||||
|         s32 priority = thread_ready_queue.contains(t.get()); |         s32 priority = thread_ready_queue.contains(t.get()); | ||||||
|         if (priority != -1) { |         if (priority != -1) { | ||||||
|             LOG_DEBUG(Kernel, "0x%02X 0x%08X", priority, t->GetHandle()); |             LOG_DEBUG(Kernel, "0x%02X %u", priority, t->GetObjectId()); | ||||||
|         } |         } | ||||||
|     } |     } | ||||||
| } | } | ||||||
| @ -362,14 +368,6 @@ ResultVal<SharedPtr<Thread>> Thread::Create(std::string name, VAddr entry_point, | |||||||
| 
 | 
 | ||||||
|     SharedPtr<Thread> thread(new Thread); |     SharedPtr<Thread> thread(new Thread); | ||||||
| 
 | 
 | ||||||
|     // TODO(yuriks): Thread requires a handle to be inserted into the various scheduling queues for
 |  | ||||||
|     //               the time being. Create a handle here, it will be copied to the handle field in
 |  | ||||||
|     //               the object and use by the rest of the code. This should be removed when other
 |  | ||||||
|     //               code doesn't rely on the handle anymore.
 |  | ||||||
|     ResultVal<Handle> handle = Kernel::g_handle_table.Create(thread); |  | ||||||
|     if (handle.Failed()) |  | ||||||
|         return handle.Code(); |  | ||||||
| 
 |  | ||||||
|     thread_list.push_back(thread); |     thread_list.push_back(thread); | ||||||
|     thread_ready_queue.prepare(priority); |     thread_ready_queue.prepare(priority); | ||||||
| 
 | 
 | ||||||
| @ -385,6 +383,7 @@ ResultVal<SharedPtr<Thread>> Thread::Create(std::string name, VAddr entry_point, | |||||||
|     thread->wait_objects.clear(); |     thread->wait_objects.clear(); | ||||||
|     thread->wait_address = 0; |     thread->wait_address = 0; | ||||||
|     thread->name = std::move(name); |     thread->name = std::move(name); | ||||||
|  |     thread->callback_handle = wakeup_callback_handle_table.Create(thread).MoveFrom(); | ||||||
| 
 | 
 | ||||||
|     ResetThread(thread.get(), arg, 0); |     ResetThread(thread.get(), arg, 0); | ||||||
|     CallThread(thread.get()); |     CallThread(thread.get()); | ||||||
| @ -418,16 +417,14 @@ void Thread::SetPriority(s32 priority) { | |||||||
|     } |     } | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| Handle SetupIdleThread() { | SharedPtr<Thread> SetupIdleThread() { | ||||||
|     // We need to pass a few valid values to get around parameter checking in Thread::Create.
 |     // We need to pass a few valid values to get around parameter checking in Thread::Create.
 | ||||||
|     auto thread_res = Thread::Create("idle", Memory::KERNEL_MEMORY_VADDR, THREADPRIO_LOWEST, 0, |     auto thread = Thread::Create("idle", Memory::KERNEL_MEMORY_VADDR, THREADPRIO_LOWEST, 0, | ||||||
|             THREADPROCESSORID_0, 0, Kernel::DEFAULT_STACK_SIZE); |             THREADPROCESSORID_0, 0, Kernel::DEFAULT_STACK_SIZE).MoveFrom(); | ||||||
|     _dbg_assert_(Kernel, thread_res.Succeeded()); |  | ||||||
|     SharedPtr<Thread> thread = std::move(*thread_res); |  | ||||||
| 
 | 
 | ||||||
|     thread->idle = true; |     thread->idle = true; | ||||||
|     CallThread(thread.get()); |     CallThread(thread.get()); | ||||||
|     return thread->GetHandle(); |     return thread; | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| SharedPtr<Thread> SetupMainThread(s32 priority, u32 stack_size) { | SharedPtr<Thread> SetupMainThread(s32 priority, u32 stack_size) { | ||||||
| @ -460,13 +457,13 @@ void Reschedule() { | |||||||
|     HLE::g_reschedule = false; |     HLE::g_reschedule = false; | ||||||
| 
 | 
 | ||||||
|     if (next != nullptr) { |     if (next != nullptr) { | ||||||
|         LOG_TRACE(Kernel, "context switch 0x%08X -> 0x%08X", prev->GetHandle(), next->GetHandle()); |         LOG_TRACE(Kernel, "context switch %u -> %u", prev->GetObjectId(), next->GetObjectId()); | ||||||
|         SwitchContext(next); |         SwitchContext(next); | ||||||
|     } else { |     } else { | ||||||
|         LOG_TRACE(Kernel, "cannot context switch from 0x%08X, no higher priority thread!", prev->GetHandle()); |         LOG_TRACE(Kernel, "cannot context switch from %u, no higher priority thread!", prev->GetObjectId()); | ||||||
| 
 | 
 | ||||||
|         for (auto& thread : thread_list) { |         for (auto& thread : thread_list) { | ||||||
|             LOG_TRACE(Kernel, "\thandle=0x%08X prio=0x%02X, status=0x%08X", thread->GetHandle(),  |             LOG_TRACE(Kernel, "\tid=%u prio=0x%02X, status=0x%08X", thread->GetObjectId(),  | ||||||
|                       thread->current_priority, thread->status); |                       thread->current_priority, thread->status); | ||||||
|         } |         } | ||||||
|     } |     } | ||||||
|  | |||||||
| @ -7,6 +7,8 @@ | |||||||
| #include <string> | #include <string> | ||||||
| #include <vector> | #include <vector> | ||||||
| 
 | 
 | ||||||
|  | #include <boost/container/flat_set.hpp> | ||||||
|  | 
 | ||||||
| #include "common/common_types.h" | #include "common/common_types.h" | ||||||
| 
 | 
 | ||||||
| #include "core/core.h" | #include "core/core.h" | ||||||
| @ -40,6 +42,8 @@ enum ThreadStatus { | |||||||
| 
 | 
 | ||||||
| namespace Kernel { | namespace Kernel { | ||||||
| 
 | 
 | ||||||
|  | class Mutex; | ||||||
|  | 
 | ||||||
| class Thread final : public WaitObject { | class Thread final : public WaitObject { | ||||||
| public: | public: | ||||||
|     static ResultVal<SharedPtr<Thread>> Create(std::string name, VAddr entry_point, s32 priority, |     static ResultVal<SharedPtr<Thread>> Create(std::string name, VAddr entry_point, s32 priority, | ||||||
| @ -77,6 +81,12 @@ public: | |||||||
|     /// Resumes a thread from waiting by marking it as "ready"
 |     /// Resumes a thread from waiting by marking it as "ready"
 | ||||||
|     void ResumeFromWait(); |     void ResumeFromWait(); | ||||||
| 
 | 
 | ||||||
|  |     /**
 | ||||||
|  |     * Schedules an event to wake up the specified thread after the specified delay. | ||||||
|  |     * @param nanoseconds The time this thread will be allowed to sleep for. | ||||||
|  |     */ | ||||||
|  |     void WakeAfterDelay(s64 nanoseconds); | ||||||
|  | 
 | ||||||
|     /**
 |     /**
 | ||||||
|      * Sets the result after the thread awakens (from either WaitSynchronization SVC) |      * Sets the result after the thread awakens (from either WaitSynchronization SVC) | ||||||
|      * @param result Value to set to the returned result |      * @param result Value to set to the returned result | ||||||
| @ -103,8 +113,10 @@ public: | |||||||
| 
 | 
 | ||||||
|     s32 processor_id; |     s32 processor_id; | ||||||
| 
 | 
 | ||||||
|     std::vector<SharedPtr<WaitObject>> wait_objects; ///< Objects that the thread is waiting on
 |     /// Mutexes currently held by this thread, which will be released when it exits.
 | ||||||
|  |     boost::container::flat_set<SharedPtr<Mutex>> held_mutexes; | ||||||
| 
 | 
 | ||||||
|  |     std::vector<SharedPtr<WaitObject>> wait_objects; ///< Objects that the thread is waiting on
 | ||||||
|     VAddr wait_address;     ///< If waiting on an AddressArbiter, this is the arbitration address
 |     VAddr wait_address;     ///< If waiting on an AddressArbiter, this is the arbitration address
 | ||||||
|     bool wait_all;          ///< True if the thread is waiting on all objects before resuming
 |     bool wait_all;          ///< True if the thread is waiting on all objects before resuming
 | ||||||
|     bool wait_set_output;   ///< True if the output parameter should be set on thread wakeup
 |     bool wait_set_output;   ///< True if the output parameter should be set on thread wakeup
 | ||||||
| @ -115,9 +127,15 @@ public: | |||||||
|     bool idle = false; |     bool idle = false; | ||||||
| 
 | 
 | ||||||
| private: | private: | ||||||
|     Thread() = default; |     Thread(); | ||||||
|  |     ~Thread() override; | ||||||
|  | 
 | ||||||
|  |     /// Handle used as userdata to reference this object when inserting into the CoreTiming queue.
 | ||||||
|  |     Handle callback_handle; | ||||||
| }; | }; | ||||||
| 
 | 
 | ||||||
|  | extern SharedPtr<Thread> g_main_thread; | ||||||
|  | 
 | ||||||
| /// Sets up the primary application thread
 | /// Sets up the primary application thread
 | ||||||
| SharedPtr<Thread> SetupMainThread(s32 priority, u32 stack_size); | SharedPtr<Thread> SetupMainThread(s32 priority, u32 stack_size); | ||||||
| 
 | 
 | ||||||
| @ -150,20 +168,13 @@ void WaitCurrentThread_WaitSynchronization(SharedPtr<WaitObject> wait_object, bo | |||||||
|  */ |  */ | ||||||
| void WaitCurrentThread_ArbitrateAddress(VAddr wait_address); | void WaitCurrentThread_ArbitrateAddress(VAddr wait_address); | ||||||
| 
 | 
 | ||||||
| /**
 |  | ||||||
|  * Schedules an event to wake up the specified thread after the specified delay. |  | ||||||
|  * @param handle The thread handle. |  | ||||||
|  * @param nanoseconds The time this thread will be allowed to sleep for. |  | ||||||
|  */ |  | ||||||
| void WakeThreadAfterDelay(Thread* thread, s64 nanoseconds); |  | ||||||
| 
 |  | ||||||
| /**
 | /**
 | ||||||
|  * Sets up the idle thread, this is a thread that is intended to never execute instructions, |  * Sets up the idle thread, this is a thread that is intended to never execute instructions, | ||||||
|  * only to advance the timing. It is scheduled when there are no other ready threads in the thread queue |  * only to advance the timing. It is scheduled when there are no other ready threads in the thread queue | ||||||
|  * and will try to yield on every call. |  * and will try to yield on every call. | ||||||
|  * @returns The handle of the idle thread |  * @returns The handle of the idle thread | ||||||
|  */ |  */ | ||||||
| Handle SetupIdleThread(); | SharedPtr<Thread> SetupIdleThread(); | ||||||
| 
 | 
 | ||||||
| /// Initialize threading
 | /// Initialize threading
 | ||||||
| void ThreadingInit(); | void ThreadingInit(); | ||||||
|  | |||||||
| @ -2,8 +2,6 @@ | |||||||
| // Licensed under GPLv2 or any later version
 | // Licensed under GPLv2 or any later version
 | ||||||
| // Refer to the license.txt file included.
 | // Refer to the license.txt file included.
 | ||||||
| 
 | 
 | ||||||
| #include <set> |  | ||||||
| 
 |  | ||||||
| #include "common/common.h" | #include "common/common.h" | ||||||
| 
 | 
 | ||||||
| #include "core/core_timing.h" | #include "core/core_timing.h" | ||||||
| @ -15,18 +13,24 @@ namespace Kernel { | |||||||
| 
 | 
 | ||||||
| /// The event type of the generic timer callback event
 | /// The event type of the generic timer callback event
 | ||||||
| static int timer_callback_event_type = -1; | static int timer_callback_event_type = -1; | ||||||
|  | // TODO(yuriks): This can be removed if Timer objects are explicitly pooled in the future, allowing
 | ||||||
|  | //               us to simply use a pool index or similar.
 | ||||||
|  | static Kernel::HandleTable timer_callback_handle_table; | ||||||
| 
 | 
 | ||||||
| ResultVal<SharedPtr<Timer>> Timer::Create(ResetType reset_type, std::string name) { | Timer::Timer() {} | ||||||
|  | Timer::~Timer() {} | ||||||
|  | 
 | ||||||
|  | SharedPtr<Timer> Timer::Create(ResetType reset_type, std::string name) { | ||||||
|     SharedPtr<Timer> timer(new Timer); |     SharedPtr<Timer> timer(new Timer); | ||||||
|     // TOOD(yuriks): Don't create Handle (see Thread::Create())
 |  | ||||||
|     CASCADE_RESULT(auto unused, Kernel::g_handle_table.Create(timer)); |  | ||||||
| 
 | 
 | ||||||
|     timer->reset_type = reset_type; |     timer->reset_type = reset_type; | ||||||
|     timer->signaled = false; |     timer->signaled = false; | ||||||
|     timer->name = std::move(name); |     timer->name = std::move(name); | ||||||
|     timer->initial_delay = 0; |     timer->initial_delay = 0; | ||||||
|     timer->interval_delay = 0; |     timer->interval_delay = 0; | ||||||
|     return MakeResult<SharedPtr<Timer>>(timer); |     timer->callback_handle = timer_callback_handle_table.Create(timer).MoveFrom(); | ||||||
|  | 
 | ||||||
|  |     return timer; | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| bool Timer::ShouldWait() { | bool Timer::ShouldWait() { | ||||||
| @ -38,17 +42,19 @@ void Timer::Acquire() { | |||||||
| } | } | ||||||
| 
 | 
 | ||||||
| void Timer::Set(s64 initial, s64 interval) { | void Timer::Set(s64 initial, s64 interval) { | ||||||
|  |     // Ensure we get rid of any previous scheduled event
 | ||||||
|  |     Cancel(); | ||||||
|  | 
 | ||||||
|     initial_delay = initial; |     initial_delay = initial; | ||||||
|     interval_delay = interval; |     interval_delay = interval; | ||||||
| 
 | 
 | ||||||
|     u64 initial_microseconds = initial / 1000; |     u64 initial_microseconds = initial / 1000; | ||||||
|     // TODO(yuriks): Figure out a replacement for GetHandle here
 |     CoreTiming::ScheduleEvent(usToCycles(initial_microseconds), | ||||||
|     CoreTiming::ScheduleEvent(usToCycles(initial_microseconds), timer_callback_event_type, |             timer_callback_event_type, callback_handle); | ||||||
|             GetHandle()); |  | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| void Timer::Cancel() { | void Timer::Cancel() { | ||||||
|     CoreTiming::UnscheduleEvent(timer_callback_event_type, GetHandle()); |     CoreTiming::UnscheduleEvent(timer_callback_event_type, callback_handle); | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| void Timer::Clear() { | void Timer::Clear() { | ||||||
| @ -57,7 +63,7 @@ void Timer::Clear() { | |||||||
| 
 | 
 | ||||||
| /// The timer callback event, called when a timer is fired
 | /// The timer callback event, called when a timer is fired
 | ||||||
| static void TimerCallback(u64 timer_handle, int cycles_late) { | static void TimerCallback(u64 timer_handle, int cycles_late) { | ||||||
|     SharedPtr<Timer> timer = Kernel::g_handle_table.Get<Timer>(timer_handle); |     SharedPtr<Timer> timer = timer_callback_handle_table.Get<Timer>(timer_handle); | ||||||
| 
 | 
 | ||||||
|     if (timer == nullptr) { |     if (timer == nullptr) { | ||||||
|         LOG_CRITICAL(Kernel, "Callback fired for invalid timer %08X", timer_handle); |         LOG_CRITICAL(Kernel, "Callback fired for invalid timer %08X", timer_handle); | ||||||
|  | |||||||
| @ -19,7 +19,7 @@ public: | |||||||
|      * @param name Optional name of timer |      * @param name Optional name of timer | ||||||
|      * @return The created Timer |      * @return The created Timer | ||||||
|      */ |      */ | ||||||
|     static ResultVal<SharedPtr<Timer>> Create(ResetType reset_type, std::string name = "Unknown"); |     static SharedPtr<Timer> Create(ResetType reset_type, std::string name = "Unknown"); | ||||||
| 
 | 
 | ||||||
|     std::string GetTypeName() const override { return "Timer"; } |     std::string GetTypeName() const override { return "Timer"; } | ||||||
|     std::string GetName() const override { return name; } |     std::string GetName() const override { return name; } | ||||||
| @ -49,7 +49,11 @@ public: | |||||||
|     void Clear(); |     void Clear(); | ||||||
| 
 | 
 | ||||||
| private: | private: | ||||||
|     Timer() = default; |     Timer(); | ||||||
|  |     ~Timer() override; | ||||||
|  | 
 | ||||||
|  |     /// Handle used as userdata to reference this object when inserting into the CoreTiming queue.
 | ||||||
|  |     Handle callback_handle; | ||||||
| }; | }; | ||||||
| 
 | 
 | ||||||
| /// Initializes the required variables for timers
 | /// Initializes the required variables for timers
 | ||||||
|  | |||||||
| @ -53,7 +53,7 @@ const Interface::FunctionInfo FunctionTable[] = { | |||||||
| // Interface class
 | // Interface class
 | ||||||
| 
 | 
 | ||||||
| Interface::Interface() { | Interface::Interface() { | ||||||
|     Register(FunctionTable, ARRAY_SIZE(FunctionTable)); |     Register(FunctionTable); | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| } // namespace
 | } // namespace
 | ||||||
|  | |||||||
| @ -18,7 +18,7 @@ namespace ACT_U { | |||||||
| // Interface class
 | // Interface class
 | ||||||
| 
 | 
 | ||||||
| Interface::Interface() { | Interface::Interface() { | ||||||
|     //Register(FunctionTable, ARRAY_SIZE(FunctionTable));
 |     //Register(FunctionTable);
 | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| } // namespace
 | } // namespace
 | ||||||
|  | |||||||
| @ -18,7 +18,7 @@ namespace AM_APP { | |||||||
| // Interface class
 | // Interface class
 | ||||||
| 
 | 
 | ||||||
| Interface::Interface() { | Interface::Interface() { | ||||||
|     //Register(FunctionTable, ARRAY_SIZE(FunctionTable));
 |     //Register(FunctionTable);
 | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| } // namespace
 | } // namespace
 | ||||||
|  | |||||||
| @ -38,7 +38,7 @@ const Interface::FunctionInfo FunctionTable[] = { | |||||||
| // Interface class
 | // Interface class
 | ||||||
| 
 | 
 | ||||||
| Interface::Interface() { | Interface::Interface() { | ||||||
|     Register(FunctionTable, ARRAY_SIZE(FunctionTable)); |     Register(FunctionTable); | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| } // namespace
 | } // namespace
 | ||||||
|  | |||||||
| @ -18,7 +18,7 @@ namespace AM_SYS { | |||||||
| // Interface class
 | // Interface class
 | ||||||
| 
 | 
 | ||||||
| Interface::Interface() { | Interface::Interface() { | ||||||
|     //Register(FunctionTable, ARRAY_SIZE(FunctionTable));
 |     //Register(FunctionTable);
 | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| } // namespace
 | } // namespace
 | ||||||
|  | |||||||
| @ -39,7 +39,7 @@ const Interface::FunctionInfo FunctionTable[] = { | |||||||
| // Interface class
 | // Interface class
 | ||||||
| 
 | 
 | ||||||
| Interface::Interface() { | Interface::Interface() { | ||||||
|     Register(FunctionTable, ARRAY_SIZE(FunctionTable)); |     Register(FunctionTable); | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| } // namespace
 | } // namespace
 | ||||||
|  | |||||||
| @ -117,7 +117,7 @@ const Interface::FunctionInfo FunctionTable[] = { | |||||||
| // Interface class
 | // Interface class
 | ||||||
| 
 | 
 | ||||||
| Interface::Interface() { | Interface::Interface() { | ||||||
|     Register(FunctionTable, ARRAY_SIZE(FunctionTable)); |     Register(FunctionTable); | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| } // namespace
 | } // namespace
 | ||||||
|  | |||||||
| @ -69,8 +69,8 @@ void Initialize(Service::Interface* self) { | |||||||
|     u32* cmd_buff = Kernel::GetCommandBuffer(); |     u32* cmd_buff = Kernel::GetCommandBuffer(); | ||||||
| 
 | 
 | ||||||
|     // TODO(bunnei): Check if these are created in Initialize or on APT process startup.
 |     // TODO(bunnei): Check if these are created in Initialize or on APT process startup.
 | ||||||
|     notification_event = Kernel::Event::Create(RESETTYPE_ONESHOT, "APT_U:Notification").MoveFrom(); |     notification_event = Kernel::Event::Create(RESETTYPE_ONESHOT, "APT_U:Notification"); | ||||||
|     pause_event = Kernel::Event::Create(RESETTYPE_ONESHOT, "APT_U:Pause").MoveFrom(); |     pause_event = Kernel::Event::Create(RESETTYPE_ONESHOT, "APT_U:Pause"); | ||||||
| 
 | 
 | ||||||
|     cmd_buff[3] = Kernel::g_handle_table.Create(notification_event).MoveFrom(); |     cmd_buff[3] = Kernel::g_handle_table.Create(notification_event).MoveFrom(); | ||||||
|     cmd_buff[4] = Kernel::g_handle_table.Create(pause_event).MoveFrom(); |     cmd_buff[4] = Kernel::g_handle_table.Create(pause_event).MoveFrom(); | ||||||
| @ -512,15 +512,15 @@ Interface::Interface() { | |||||||
|         file.ReadBytes(shared_font.data(), (size_t)file.GetSize()); |         file.ReadBytes(shared_font.data(), (size_t)file.GetSize()); | ||||||
| 
 | 
 | ||||||
|         // Create shared font memory object
 |         // Create shared font memory object
 | ||||||
|         shared_font_mem = Kernel::SharedMemory::Create("APT_U:shared_font_mem").MoveFrom(); |         shared_font_mem = Kernel::SharedMemory::Create("APT_U:shared_font_mem"); | ||||||
|     } else { |     } else { | ||||||
|         LOG_WARNING(Service_APT, "Unable to load shared font: %s", filepath.c_str()); |         LOG_WARNING(Service_APT, "Unable to load shared font: %s", filepath.c_str()); | ||||||
|         shared_font_mem = nullptr; |         shared_font_mem = nullptr; | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     lock = Kernel::Mutex::Create(false, "APT_U:Lock").MoveFrom(); |     lock = Kernel::Mutex::Create(false, "APT_U:Lock"); | ||||||
| 
 | 
 | ||||||
|     Register(FunctionTable, ARRAY_SIZE(FunctionTable)); |     Register(FunctionTable); | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| } // namespace
 | } // namespace
 | ||||||
|  | |||||||
| @ -18,7 +18,7 @@ namespace BOSS_P { | |||||||
| // Interface class
 | // Interface class
 | ||||||
| 
 | 
 | ||||||
| Interface::Interface() { | Interface::Interface() { | ||||||
|     //Register(FunctionTable, ARRAY_SIZE(FunctionTable));
 |     //Register(FunctionTable);
 | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| } // namespace
 | } // namespace
 | ||||||
|  | |||||||
| @ -19,7 +19,7 @@ const Interface::FunctionInfo FunctionTable[] = { | |||||||
| // Interface class
 | // Interface class
 | ||||||
| 
 | 
 | ||||||
| Interface::Interface() { | Interface::Interface() { | ||||||
|     Register(FunctionTable, ARRAY_SIZE(FunctionTable)); |     Register(FunctionTable); | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| } // namespace
 | } // namespace
 | ||||||
|  | |||||||
| @ -18,7 +18,7 @@ namespace CAM_U { | |||||||
| // Interface class
 | // Interface class
 | ||||||
| 
 | 
 | ||||||
| Interface::Interface() { | Interface::Interface() { | ||||||
|     //Register(FunctionTable, ARRAY_SIZE(FunctionTable));
 |     //Register(FunctionTable);
 | ||||||
| } | } | ||||||
|      |      | ||||||
| } // namespace
 | } // namespace
 | ||||||
|  | |||||||
| @ -18,7 +18,7 @@ namespace CECD_S { | |||||||
| // Interface class
 | // Interface class
 | ||||||
| 
 | 
 | ||||||
| Interface::Interface() { | Interface::Interface() { | ||||||
|     //Register(FunctionTable, ARRAY_SIZE(FunctionTable));
 |     //Register(FunctionTable);
 | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| } // namespace
 | } // namespace
 | ||||||
|  | |||||||
| @ -18,7 +18,7 @@ namespace CECD_U { | |||||||
| // Interface class
 | // Interface class
 | ||||||
| 
 | 
 | ||||||
| Interface::Interface() { | Interface::Interface() { | ||||||
|     //Register(FunctionTable, ARRAY_SIZE(FunctionTable));
 |     //Register(FunctionTable);
 | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| } // namespace
 | } // namespace
 | ||||||
|  | |||||||
| @ -104,7 +104,7 @@ const Interface::FunctionInfo FunctionTable[] = { | |||||||
| // Interface class
 | // Interface class
 | ||||||
| 
 | 
 | ||||||
| Interface::Interface() { | Interface::Interface() { | ||||||
|     Register(FunctionTable, ARRAY_SIZE(FunctionTable)); |     Register(FunctionTable); | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| } // namespace
 | } // namespace
 | ||||||
|  | |||||||
| @ -92,7 +92,7 @@ const Interface::FunctionInfo FunctionTable[] = { | |||||||
| // Interface class
 | // Interface class
 | ||||||
| 
 | 
 | ||||||
| Interface::Interface() { | Interface::Interface() { | ||||||
|     Register(FunctionTable, ARRAY_SIZE(FunctionTable)); |     Register(FunctionTable); | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| } // namespace
 | } // namespace
 | ||||||
|  | |||||||
| @ -186,7 +186,7 @@ const Interface::FunctionInfo FunctionTable[] = { | |||||||
| // Interface class
 | // Interface class
 | ||||||
| 
 | 
 | ||||||
| Interface::Interface() { | Interface::Interface() { | ||||||
|     Register(FunctionTable, ARRAY_SIZE(FunctionTable)); |     Register(FunctionTable); | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| } // namespace
 | } // namespace
 | ||||||
|  | |||||||
| @ -29,7 +29,7 @@ const Interface::FunctionInfo FunctionTable[] = { | |||||||
| // Interface class
 | // Interface class
 | ||||||
| 
 | 
 | ||||||
| Interface::Interface() { | Interface::Interface() { | ||||||
|     Register(FunctionTable, ARRAY_SIZE(FunctionTable)); |     Register(FunctionTable); | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| } // namespace
 | } // namespace
 | ||||||
|  | |||||||
| @ -201,12 +201,11 @@ const Interface::FunctionInfo FunctionTable[] = { | |||||||
| // Interface class
 | // Interface class
 | ||||||
| 
 | 
 | ||||||
| Interface::Interface() { | Interface::Interface() { | ||||||
|     semaphore_event = Kernel::Event::Create(RESETTYPE_ONESHOT, |     semaphore_event = Kernel::Event::Create(RESETTYPE_ONESHOT, "DSP_DSP::semaphore_event"); | ||||||
|             "DSP_DSP::semaphore_event").MoveFrom(); |  | ||||||
|     interrupt_event = nullptr; |     interrupt_event = nullptr; | ||||||
|     read_pipe_count = 0; |     read_pipe_count = 0; | ||||||
| 
 | 
 | ||||||
|     Register(FunctionTable, ARRAY_SIZE(FunctionTable)); |     Register(FunctionTable); | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| } // namespace
 | } // namespace
 | ||||||
|  | |||||||
| @ -19,7 +19,7 @@ const Interface::FunctionInfo FunctionTable[] = { | |||||||
| // Interface class
 | // Interface class
 | ||||||
| 
 | 
 | ||||||
| Interface::Interface() { | Interface::Interface() { | ||||||
|     Register(FunctionTable, ARRAY_SIZE(FunctionTable)); |     Register(FunctionTable); | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| } // namespace
 | } // namespace
 | ||||||
|  | |||||||
| @ -18,7 +18,7 @@ namespace FRD_A { | |||||||
| // Interface class
 | // Interface class
 | ||||||
| 
 | 
 | ||||||
| Interface::Interface() { | Interface::Interface() { | ||||||
|     //Register(FunctionTable, ARRAY_SIZE(FunctionTable));
 |     //Register(FunctionTable);
 | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| } // namespace
 | } // namespace
 | ||||||
|  | |||||||
| @ -27,7 +27,7 @@ const Interface::FunctionInfo FunctionTable[] = { | |||||||
| // Interface class
 | // Interface class
 | ||||||
| 
 | 
 | ||||||
| Interface::Interface() { | Interface::Interface() { | ||||||
|     Register(FunctionTable, ARRAY_SIZE(FunctionTable)); |     Register(FunctionTable); | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| } // namespace
 | } // namespace
 | ||||||
|  | |||||||
| @ -163,7 +163,7 @@ public: | |||||||
|         case FileCommand::OpenLinkFile: |         case FileCommand::OpenLinkFile: | ||||||
|         { |         { | ||||||
|             LOG_WARNING(Service_FS, "(STUBBED) File command OpenLinkFile %s", GetName().c_str()); |             LOG_WARNING(Service_FS, "(STUBBED) File command OpenLinkFile %s", GetName().c_str()); | ||||||
|             cmd_buff[3] = GetHandle(); |             cmd_buff[3] = Kernel::g_handle_table.Create(this).ValueOr(INVALID_HANDLE); | ||||||
|             break; |             break; | ||||||
|         } |         } | ||||||
| 
 | 
 | ||||||
| @ -303,7 +303,8 @@ ResultCode CreateArchive(std::unique_ptr<FileSys::ArchiveBackend>&& backend, Arc | |||||||
|     return RESULT_SUCCESS; |     return RESULT_SUCCESS; | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| ResultVal<Handle> OpenFileFromArchive(ArchiveHandle archive_handle, const FileSys::Path& path, const FileSys::Mode mode) { | ResultVal<Kernel::SharedPtr<Kernel::Session>> OpenFileFromArchive(ArchiveHandle archive_handle, | ||||||
|  |         const FileSys::Path& path, const FileSys::Mode mode) { | ||||||
|     Archive* archive = GetArchive(archive_handle); |     Archive* archive = GetArchive(archive_handle); | ||||||
|     if (archive == nullptr) |     if (archive == nullptr) | ||||||
|         return ERR_INVALID_HANDLE; |         return ERR_INVALID_HANDLE; | ||||||
| @ -314,10 +315,8 @@ ResultVal<Handle> OpenFileFromArchive(ArchiveHandle archive_handle, const FileSy | |||||||
|                           ErrorSummary::NotFound, ErrorLevel::Status); |                           ErrorSummary::NotFound, ErrorLevel::Status); | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     auto file = Common::make_unique<File>(std::move(backend), path); |     auto file = Kernel::SharedPtr<File>(new File(std::move(backend), path)); | ||||||
|     // TOOD(yuriks): Fix error reporting
 |     return MakeResult<Kernel::SharedPtr<Kernel::Session>>(std::move(file)); | ||||||
|     Handle handle = Kernel::g_handle_table.Create(file.release()).ValueOr(INVALID_HANDLE); |  | ||||||
|     return MakeResult<Handle>(handle); |  | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| ResultCode DeleteFileFromArchive(ArchiveHandle archive_handle, const FileSys::Path& path) { | ResultCode DeleteFileFromArchive(ArchiveHandle archive_handle, const FileSys::Path& path) { | ||||||
| @ -403,13 +402,8 @@ ResultCode RenameDirectoryBetweenArchives(ArchiveHandle src_archive_handle, cons | |||||||
|                       ErrorSummary::NothingHappened, ErrorLevel::Status); |                       ErrorSummary::NothingHappened, ErrorLevel::Status); | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| /**
 | ResultVal<Kernel::SharedPtr<Kernel::Session>> OpenDirectoryFromArchive(ArchiveHandle archive_handle, | ||||||
|  * Open a Directory from an Archive |         const FileSys::Path& path) { | ||||||
|  * @param archive_handle Handle to an open Archive object |  | ||||||
|  * @param path Path to the Directory inside of the Archive |  | ||||||
|  * @return Opened Directory object |  | ||||||
|  */ |  | ||||||
| ResultVal<Handle> OpenDirectoryFromArchive(ArchiveHandle archive_handle, const FileSys::Path& path) { |  | ||||||
|     Archive* archive = GetArchive(archive_handle); |     Archive* archive = GetArchive(archive_handle); | ||||||
|     if (archive == nullptr) |     if (archive == nullptr) | ||||||
|         return ERR_INVALID_HANDLE; |         return ERR_INVALID_HANDLE; | ||||||
| @ -420,10 +414,8 @@ ResultVal<Handle> OpenDirectoryFromArchive(ArchiveHandle archive_handle, const F | |||||||
|                           ErrorSummary::NotFound, ErrorLevel::Permanent); |                           ErrorSummary::NotFound, ErrorLevel::Permanent); | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     auto directory = Common::make_unique<Directory>(std::move(backend), path); |     auto directory = Kernel::SharedPtr<Directory>(new Directory(std::move(backend), path)); | ||||||
|     // TOOD(yuriks): Fix error reporting
 |     return MakeResult<Kernel::SharedPtr<Kernel::Session>>(std::move(directory)); | ||||||
|     Handle handle = Kernel::g_handle_table.Create(directory.release()).ValueOr(INVALID_HANDLE); |  | ||||||
|     return MakeResult<Handle>(handle); |  | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| ResultCode FormatSaveData() { | ResultCode FormatSaveData() { | ||||||
|  | |||||||
| @ -15,6 +15,10 @@ extern const std::string SYSTEM_ID; | |||||||
| /// The scrambled SD card CID, also known as ID1
 | /// The scrambled SD card CID, also known as ID1
 | ||||||
| extern const std::string SDCARD_ID; | extern const std::string SDCARD_ID; | ||||||
| 
 | 
 | ||||||
|  | namespace Kernel { | ||||||
|  |     class Session; | ||||||
|  | } | ||||||
|  | 
 | ||||||
| namespace Service { | namespace Service { | ||||||
| namespace FS { | namespace FS { | ||||||
| 
 | 
 | ||||||
| @ -58,9 +62,10 @@ ResultCode CreateArchive(std::unique_ptr<FileSys::ArchiveBackend>&& backend, Arc | |||||||
|  * @param archive_handle Handle to an open Archive object |  * @param archive_handle Handle to an open Archive object | ||||||
|  * @param path Path to the File inside of the Archive |  * @param path Path to the File inside of the Archive | ||||||
|  * @param mode Mode under which to open the File |  * @param mode Mode under which to open the File | ||||||
|  * @return Handle to the opened File object |  * @return The opened File object as a Session | ||||||
|  */ |  */ | ||||||
| ResultVal<Handle> OpenFileFromArchive(ArchiveHandle archive_handle, const FileSys::Path& path, const FileSys::Mode mode); | ResultVal<Kernel::SharedPtr<Kernel::Session>> OpenFileFromArchive(ArchiveHandle archive_handle, | ||||||
|  |         const FileSys::Path& path, const FileSys::Mode mode); | ||||||
| 
 | 
 | ||||||
| /**
 | /**
 | ||||||
|  * Delete a File from an Archive |  * Delete a File from an Archive | ||||||
| @ -121,9 +126,10 @@ ResultCode RenameDirectoryBetweenArchives(ArchiveHandle src_archive_handle, cons | |||||||
|  * Open a Directory from an Archive |  * Open a Directory from an Archive | ||||||
|  * @param archive_handle Handle to an open Archive object |  * @param archive_handle Handle to an open Archive object | ||||||
|  * @param path Path to the Directory inside of the Archive |  * @param path Path to the Directory inside of the Archive | ||||||
|  * @return Handle to the opened File object |  * @return The opened Directory object as a Session | ||||||
|  */ |  */ | ||||||
| ResultVal<Handle> OpenDirectoryFromArchive(ArchiveHandle archive_handle, const FileSys::Path& path); | ResultVal<Kernel::SharedPtr<Kernel::Session>> OpenDirectoryFromArchive(ArchiveHandle archive_handle, | ||||||
|  |         const FileSys::Path& path); | ||||||
| 
 | 
 | ||||||
| /**
 | /**
 | ||||||
|  * Creates a blank SaveData archive. |  * Creates a blank SaveData archive. | ||||||
|  | |||||||
| @ -14,6 +14,9 @@ | |||||||
| ////////////////////////////////////////////////////////////////////////////////////////////////////
 | ////////////////////////////////////////////////////////////////////////////////////////////////////
 | ||||||
| // Namespace FS_User
 | // Namespace FS_User
 | ||||||
| 
 | 
 | ||||||
|  | using Kernel::SharedPtr; | ||||||
|  | using Kernel::Session; | ||||||
|  | 
 | ||||||
| namespace Service { | namespace Service { | ||||||
| namespace FS { | namespace FS { | ||||||
| 
 | 
 | ||||||
| @ -58,10 +61,10 @@ static void OpenFile(Service::Interface* self) { | |||||||
| 
 | 
 | ||||||
|     LOG_DEBUG(Service_FS, "path=%s, mode=%d attrs=%u", file_path.DebugStr().c_str(), mode.hex, attributes); |     LOG_DEBUG(Service_FS, "path=%s, mode=%d attrs=%u", file_path.DebugStr().c_str(), mode.hex, attributes); | ||||||
| 
 | 
 | ||||||
|     ResultVal<Handle> handle = OpenFileFromArchive(archive_handle, file_path, mode); |     ResultVal<SharedPtr<Session>> file_res = OpenFileFromArchive(archive_handle, file_path, mode); | ||||||
|     cmd_buff[1] = handle.Code().raw; |     cmd_buff[1] = file_res.Code().raw; | ||||||
|     if (handle.Succeeded()) { |     if (file_res.Succeeded()) { | ||||||
|         cmd_buff[3] = *handle; |         cmd_buff[3] = Kernel::g_handle_table.Create(*file_res).MoveFrom(); | ||||||
|     } else { |     } else { | ||||||
|         cmd_buff[3] = 0; |         cmd_buff[3] = 0; | ||||||
|         LOG_ERROR(Service_FS, "failed to get a handle for file %s", file_path.DebugStr().c_str()); |         LOG_ERROR(Service_FS, "failed to get a handle for file %s", file_path.DebugStr().c_str()); | ||||||
| @ -114,10 +117,10 @@ static void OpenFileDirectly(Service::Interface* self) { | |||||||
|     } |     } | ||||||
|     SCOPE_EXIT({ CloseArchive(*archive_handle); }); |     SCOPE_EXIT({ CloseArchive(*archive_handle); }); | ||||||
| 
 | 
 | ||||||
|     ResultVal<Handle> handle = OpenFileFromArchive(*archive_handle, file_path, mode); |     ResultVal<SharedPtr<Session>> file_res = OpenFileFromArchive(*archive_handle, file_path, mode); | ||||||
|     cmd_buff[1] = handle.Code().raw; |     cmd_buff[1] = file_res.Code().raw; | ||||||
|     if (handle.Succeeded()) { |     if (file_res.Succeeded()) { | ||||||
|         cmd_buff[3] = *handle; |         cmd_buff[3] = Kernel::g_handle_table.Create(*file_res).MoveFrom(); | ||||||
|     } else { |     } else { | ||||||
|         cmd_buff[3] = 0; |         cmd_buff[3] = 0; | ||||||
|         LOG_ERROR(Service_FS, "failed to get a handle for file %s", file_path.DebugStr().c_str()); |         LOG_ERROR(Service_FS, "failed to get a handle for file %s", file_path.DebugStr().c_str()); | ||||||
| @ -334,10 +337,10 @@ static void OpenDirectory(Service::Interface* self) { | |||||||
| 
 | 
 | ||||||
|     LOG_DEBUG(Service_FS, "type=%d size=%d data=%s", dirname_type, dirname_size, dir_path.DebugStr().c_str()); |     LOG_DEBUG(Service_FS, "type=%d size=%d data=%s", dirname_type, dirname_size, dir_path.DebugStr().c_str()); | ||||||
| 
 | 
 | ||||||
|     ResultVal<Handle> handle = OpenDirectoryFromArchive(archive_handle, dir_path); |     ResultVal<SharedPtr<Session>> dir_res = OpenDirectoryFromArchive(archive_handle, dir_path); | ||||||
|     cmd_buff[1] = handle.Code().raw; |     cmd_buff[1] = dir_res.Code().raw; | ||||||
|     if (handle.Succeeded()) { |     if (dir_res.Succeeded()) { | ||||||
|         cmd_buff[3] = *handle; |         cmd_buff[3] = Kernel::g_handle_table.Create(*dir_res).MoveFrom(); | ||||||
|     } else { |     } else { | ||||||
|         LOG_ERROR(Service_FS, "failed to get a handle for directory"); |         LOG_ERROR(Service_FS, "failed to get a handle for directory"); | ||||||
|     } |     } | ||||||
| @ -588,7 +591,7 @@ const FSUserInterface::FunctionInfo FunctionTable[] = { | |||||||
| // Interface class
 | // Interface class
 | ||||||
| 
 | 
 | ||||||
| FSUserInterface::FSUserInterface() { | FSUserInterface::FSUserInterface() { | ||||||
|     Register(FunctionTable, ARRAY_SIZE(FunctionTable)); |     Register(FunctionTable); | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| } // namespace FS
 | } // namespace FS
 | ||||||
|  | |||||||
| @ -187,7 +187,7 @@ static void RegisterInterruptRelayQueue(Service::Interface* self) { | |||||||
| 
 | 
 | ||||||
|     g_interrupt_event = Kernel::g_handle_table.Get<Kernel::Event>(cmd_buff[3]); |     g_interrupt_event = Kernel::g_handle_table.Get<Kernel::Event>(cmd_buff[3]); | ||||||
|     _assert_msg_(GSP, (g_interrupt_event != nullptr), "handle is not valid!"); |     _assert_msg_(GSP, (g_interrupt_event != nullptr), "handle is not valid!"); | ||||||
|     g_shared_memory = Kernel::SharedMemory::Create("GSPSharedMem").MoveFrom(); |     g_shared_memory = Kernel::SharedMemory::Create("GSPSharedMem"); | ||||||
| 
 | 
 | ||||||
|     Handle shmem_handle = Kernel::g_handle_table.Create(g_shared_memory).MoveFrom(); |     Handle shmem_handle = Kernel::g_handle_table.Create(g_shared_memory).MoveFrom(); | ||||||
| 
 | 
 | ||||||
| @ -389,7 +389,7 @@ const Interface::FunctionInfo FunctionTable[] = { | |||||||
| // Interface class
 | // Interface class
 | ||||||
| 
 | 
 | ||||||
| Interface::Interface() { | Interface::Interface() { | ||||||
|     Register(FunctionTable, ARRAY_SIZE(FunctionTable)); |     Register(FunctionTable); | ||||||
| 
 | 
 | ||||||
|     g_interrupt_event = 0; |     g_interrupt_event = 0; | ||||||
|     g_shared_memory = 0; |     g_shared_memory = 0; | ||||||
|  | |||||||
| @ -20,7 +20,7 @@ namespace GSP_LCD { | |||||||
| // Interface class
 | // Interface class
 | ||||||
| 
 | 
 | ||||||
| Interface::Interface() { | Interface::Interface() { | ||||||
|     //Register(FunctionTable, ARRAY_SIZE(FunctionTable));
 |     //Register(FunctionTable);
 | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| } // namespace
 | } // namespace
 | ||||||
|  | |||||||
| @ -30,6 +30,8 @@ static s16 next_circle_y = 0; | |||||||
|  * Gets a pointer to the PadData structure inside HID shared memory |  * Gets a pointer to the PadData structure inside HID shared memory | ||||||
|  */ |  */ | ||||||
| static inline PadData* GetPadData() { | static inline PadData* GetPadData() { | ||||||
|  |     if (g_shared_mem == nullptr) | ||||||
|  |         return nullptr; | ||||||
|     return reinterpret_cast<PadData*>(g_shared_mem->GetPointer().ValueOr(nullptr)); |     return reinterpret_cast<PadData*>(g_shared_mem->GetPointer().ValueOr(nullptr)); | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| @ -122,14 +124,14 @@ void PadUpdateComplete() { | |||||||
| void HIDInit() { | void HIDInit() { | ||||||
|     using namespace Kernel; |     using namespace Kernel; | ||||||
| 
 | 
 | ||||||
|     g_shared_mem = SharedMemory::Create("HID:SharedMem").MoveFrom(); |     g_shared_mem = SharedMemory::Create("HID:SharedMem"); | ||||||
| 
 | 
 | ||||||
|     // Create event handles
 |     // Create event handles
 | ||||||
|     g_event_pad_or_touch_1 = Event::Create(RESETTYPE_ONESHOT, "HID:EventPadOrTouch1").MoveFrom(); |     g_event_pad_or_touch_1 = Event::Create(RESETTYPE_ONESHOT, "HID:EventPadOrTouch1"); | ||||||
|     g_event_pad_or_touch_2 = Event::Create(RESETTYPE_ONESHOT, "HID:EventPadOrTouch2").MoveFrom(); |     g_event_pad_or_touch_2 = Event::Create(RESETTYPE_ONESHOT, "HID:EventPadOrTouch2"); | ||||||
|     g_event_accelerometer  = Event::Create(RESETTYPE_ONESHOT, "HID:EventAccelerometer").MoveFrom(); |     g_event_accelerometer  = Event::Create(RESETTYPE_ONESHOT, "HID:EventAccelerometer"); | ||||||
|     g_event_gyroscope      = Event::Create(RESETTYPE_ONESHOT, "HID:EventGyroscope").MoveFrom(); |     g_event_gyroscope      = Event::Create(RESETTYPE_ONESHOT, "HID:EventGyroscope"); | ||||||
|     g_event_debug_pad      = Event::Create(RESETTYPE_ONESHOT, "HID:EventDebugPad").MoveFrom(); |     g_event_debug_pad      = Event::Create(RESETTYPE_ONESHOT, "HID:EventDebugPad"); | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| void HIDShutdown() { | void HIDShutdown() { | ||||||
|  | |||||||
| @ -32,7 +32,7 @@ const Interface::FunctionInfo FunctionTable[] = { | |||||||
| // Interface class
 | // Interface class
 | ||||||
| 
 | 
 | ||||||
| Interface::Interface() { | Interface::Interface() { | ||||||
|     Register(FunctionTable, ARRAY_SIZE(FunctionTable)); |     Register(FunctionTable); | ||||||
| } | } | ||||||
|      |      | ||||||
| } // namespace
 | } // namespace
 | ||||||
|  | |||||||
| @ -72,7 +72,7 @@ const Interface::FunctionInfo FunctionTable[] = { | |||||||
| // Interface class
 | // Interface class
 | ||||||
| 
 | 
 | ||||||
| Interface::Interface() { | Interface::Interface() { | ||||||
|     Register(FunctionTable, ARRAY_SIZE(FunctionTable)); |     Register(FunctionTable); | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| } // namespace
 | } // namespace
 | ||||||
|  | |||||||
| @ -58,7 +58,7 @@ const Interface::FunctionInfo FunctionTable[] = { | |||||||
| // Interface class
 | // Interface class
 | ||||||
| 
 | 
 | ||||||
| Interface::Interface() { | Interface::Interface() { | ||||||
|     Register(FunctionTable, ARRAY_SIZE(FunctionTable)); |     Register(FunctionTable); | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| } // namespace
 | } // namespace
 | ||||||
|  | |||||||
| @ -22,7 +22,7 @@ const Interface::FunctionInfo FunctionTable[] = { | |||||||
| // Interface class
 | // Interface class
 | ||||||
| 
 | 
 | ||||||
| Interface::Interface() { | Interface::Interface() { | ||||||
|     Register(FunctionTable, ARRAY_SIZE(FunctionTable)); |     Register(FunctionTable); | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| } // namespace
 | } // namespace
 | ||||||
|  | |||||||
| @ -36,7 +36,7 @@ const Interface::FunctionInfo FunctionTable[] = { | |||||||
| // Interface class
 | // Interface class
 | ||||||
| 
 | 
 | ||||||
| Interface::Interface() { | Interface::Interface() { | ||||||
|     Register(FunctionTable, ARRAY_SIZE(FunctionTable)); |     Register(FunctionTable); | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| } // namespace
 | } // namespace
 | ||||||
|  | |||||||
| @ -27,7 +27,7 @@ const Interface::FunctionInfo FunctionTable[] = { | |||||||
| // Interface class
 | // Interface class
 | ||||||
| 
 | 
 | ||||||
| Interface::Interface() { | Interface::Interface() { | ||||||
|     Register(FunctionTable, ARRAY_SIZE(FunctionTable)); |     Register(FunctionTable); | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| } // namespace
 | } // namespace
 | ||||||
|  | |||||||
| @ -34,7 +34,7 @@ const Interface::FunctionInfo FunctionTable[] = { | |||||||
| // Interface class
 | // Interface class
 | ||||||
| 
 | 
 | ||||||
| Interface::Interface() { | Interface::Interface() { | ||||||
|     Register(FunctionTable, ARRAY_SIZE(FunctionTable)); |     Register(FunctionTable); | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| } // namespace
 | } // namespace
 | ||||||
|  | |||||||
| @ -24,7 +24,7 @@ const Interface::FunctionInfo FunctionTable[] = { | |||||||
| // Interface class
 | // Interface class
 | ||||||
| 
 | 
 | ||||||
| Interface::Interface() { | Interface::Interface() { | ||||||
|     Register(FunctionTable, ARRAY_SIZE(FunctionTable)); |     Register(FunctionTable); | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| } // namespace
 | } // namespace
 | ||||||
|  | |||||||
| @ -19,7 +19,7 @@ const Interface::FunctionInfo FunctionTable[] = { | |||||||
| // Interface class
 | // Interface class
 | ||||||
| 
 | 
 | ||||||
| Interface::Interface() { | Interface::Interface() { | ||||||
|     Register(FunctionTable, ARRAY_SIZE(FunctionTable)); |     Register(FunctionTable); | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| } // namespace
 | } // namespace
 | ||||||
|  | |||||||
| @ -19,7 +19,7 @@ const Interface::FunctionInfo FunctionTable[] = { | |||||||
| // Interface class
 | // Interface class
 | ||||||
| 
 | 
 | ||||||
| Interface::Interface() { | Interface::Interface() { | ||||||
|     Register(FunctionTable, ARRAY_SIZE(FunctionTable)); |     Register(FunctionTable); | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| } // namespace
 | } // namespace
 | ||||||
|  | |||||||
| @ -25,7 +25,7 @@ const Interface::FunctionInfo FunctionTable[] = { | |||||||
| // Interface class
 | // Interface class
 | ||||||
| 
 | 
 | ||||||
| Interface::Interface() { | Interface::Interface() { | ||||||
|     Register(FunctionTable, ARRAY_SIZE(FunctionTable)); |     Register(FunctionTable); | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| } // namespace
 | } // namespace
 | ||||||
|  | |||||||
| @ -21,7 +21,7 @@ const Interface::FunctionInfo FunctionTable[] = { | |||||||
| // Interface class
 | // Interface class
 | ||||||
| 
 | 
 | ||||||
| Interface::Interface() { | Interface::Interface() { | ||||||
|     Register(FunctionTable, ARRAY_SIZE(FunctionTable)); |     Register(FunctionTable); | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| } // namespace
 | } // namespace
 | ||||||
|  | |||||||
| @ -26,7 +26,7 @@ const Interface::FunctionInfo FunctionTable[] = { | |||||||
| // Interface class
 | // Interface class
 | ||||||
| 
 | 
 | ||||||
| Interface::Interface() { | Interface::Interface() { | ||||||
|     Register(FunctionTable, ARRAY_SIZE(FunctionTable)); |     Register(FunctionTable); | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| } // namespace
 | } // namespace
 | ||||||
|  | |||||||
| @ -26,7 +26,7 @@ const Interface::FunctionInfo FunctionTable[] = { | |||||||
| // Interface class
 | // Interface class
 | ||||||
| 
 | 
 | ||||||
| Interface::Interface() { | Interface::Interface() { | ||||||
|     Register(FunctionTable, ARRAY_SIZE(FunctionTable)); |     Register(FunctionTable); | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| } // namespace
 | } // namespace
 | ||||||
|  | |||||||
| @ -22,7 +22,7 @@ const Interface::FunctionInfo FunctionTable[] = { | |||||||
| // Interface class
 | // Interface class
 | ||||||
| 
 | 
 | ||||||
| Interface::Interface() { | Interface::Interface() { | ||||||
|     Register(FunctionTable, ARRAY_SIZE(FunctionTable)); |     Register(FunctionTable); | ||||||
| } | } | ||||||
|      |      | ||||||
| } // namespace
 | } // namespace
 | ||||||
|  | |||||||
| @ -50,7 +50,7 @@ const Interface::FunctionInfo FunctionTable[] = { | |||||||
| // Interface class
 | // Interface class
 | ||||||
| 
 | 
 | ||||||
| Interface::Interface() { | Interface::Interface() { | ||||||
|     Register(FunctionTable, ARRAY_SIZE(FunctionTable)); |     Register(FunctionTable); | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| } // namespace
 | } // namespace
 | ||||||
|  | |||||||
| @ -137,7 +137,7 @@ const Interface::FunctionInfo FunctionTable[] = { | |||||||
| // Interface class
 | // Interface class
 | ||||||
| 
 | 
 | ||||||
| Interface::Interface() { | Interface::Interface() { | ||||||
|     Register(FunctionTable, ARRAY_SIZE(FunctionTable)); |     Register(FunctionTable); | ||||||
|     // Create the SharedExtSaveData archive 0xF000000B and the gamecoin.dat file
 |     // Create the SharedExtSaveData archive 0xF000000B and the gamecoin.dat file
 | ||||||
|     // TODO(Subv): In the future we should use the FS service to query this archive
 |     // TODO(Subv): In the future we should use the FS service to query this archive
 | ||||||
|     std::string nand_directory = FileUtil::GetUserPath(D_NAND_IDX); |     std::string nand_directory = FileUtil::GetUserPath(D_NAND_IDX); | ||||||
|  | |||||||
| @ -54,96 +54,76 @@ | |||||||
| 
 | 
 | ||||||
| namespace Service { | namespace Service { | ||||||
| 
 | 
 | ||||||
| Manager* g_manager = nullptr;  ///< Service manager
 | std::unordered_map<std::string, Kernel::SharedPtr<Interface>> g_kernel_named_ports; | ||||||
| 
 | std::unordered_map<std::string, Kernel::SharedPtr<Interface>> g_srv_services; | ||||||
| ////////////////////////////////////////////////////////////////////////////////////////////////////
 |  | ||||||
| // Service Manager class
 |  | ||||||
| 
 |  | ||||||
| void Manager::AddService(Interface* service) { |  | ||||||
|     // TOOD(yuriks): Fix error reporting
 |  | ||||||
|     m_port_map[service->GetPortName()] = Kernel::g_handle_table.Create(service).ValueOr(INVALID_HANDLE); |  | ||||||
|     m_services.push_back(service); |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| void Manager::DeleteService(const std::string& port_name) { |  | ||||||
|     Interface* service = FetchFromPortName(port_name); |  | ||||||
|     m_services.erase(std::remove(m_services.begin(), m_services.end(), service), m_services.end()); |  | ||||||
|     m_port_map.erase(port_name); |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| Interface* Manager::FetchFromHandle(Handle handle) { |  | ||||||
|     // TODO(yuriks): This function is very suspicious and should probably be exterminated.
 |  | ||||||
|     return Kernel::g_handle_table.Get<Interface>(handle).get(); |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| Interface* Manager::FetchFromPortName(const std::string& port_name) { |  | ||||||
|     auto itr = m_port_map.find(port_name); |  | ||||||
|     if (itr == m_port_map.end()) { |  | ||||||
|         return nullptr; |  | ||||||
|     } |  | ||||||
|     return FetchFromHandle(itr->second); |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| 
 | 
 | ||||||
| ////////////////////////////////////////////////////////////////////////////////////////////////////
 | ////////////////////////////////////////////////////////////////////////////////////////////////////
 | ||||||
| // Module interface
 | // Module interface
 | ||||||
| 
 | 
 | ||||||
|  | static void AddNamedPort(Interface* interface) { | ||||||
|  |     g_kernel_named_ports.emplace(interface->GetPortName(), interface); | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | static void AddService(Interface* interface) { | ||||||
|  |     g_srv_services.emplace(interface->GetPortName(), interface); | ||||||
|  | } | ||||||
|  | 
 | ||||||
| /// Initialize ServiceManager
 | /// Initialize ServiceManager
 | ||||||
| void Init() { | void Init() { | ||||||
|     g_manager = new Manager; |     AddNamedPort(new SRV::Interface); | ||||||
| 
 | 
 | ||||||
|     g_manager->AddService(new SRV::Interface); |     AddService(new AC_U::Interface); | ||||||
|     g_manager->AddService(new AC_U::Interface); |     AddService(new ACT_U::Interface); | ||||||
|     g_manager->AddService(new ACT_U::Interface); |     AddService(new AM_APP::Interface); | ||||||
|     g_manager->AddService(new AM_APP::Interface); |     AddService(new AM_NET::Interface); | ||||||
|     g_manager->AddService(new AM_NET::Interface); |     AddService(new AM_SYS::Interface); | ||||||
|     g_manager->AddService(new AM_SYS::Interface); |     AddService(new APT_A::Interface); | ||||||
|     g_manager->AddService(new APT_A::Interface); |     AddService(new APT_S::Interface); | ||||||
|     g_manager->AddService(new APT_S::Interface); |     AddService(new APT_U::Interface); | ||||||
|     g_manager->AddService(new APT_U::Interface); |     AddService(new BOSS_P::Interface); | ||||||
|     g_manager->AddService(new BOSS_P::Interface); |     AddService(new BOSS_U::Interface); | ||||||
|     g_manager->AddService(new BOSS_U::Interface); |     AddService(new CAM_U::Interface); | ||||||
|     g_manager->AddService(new CAM_U::Interface); |     AddService(new CECD_S::Interface); | ||||||
|     g_manager->AddService(new CECD_S::Interface); |     AddService(new CECD_U::Interface); | ||||||
|     g_manager->AddService(new CECD_U::Interface); |     AddService(new CFG_I::Interface); | ||||||
|     g_manager->AddService(new CFG_I::Interface); |     AddService(new CFG_S::Interface); | ||||||
|     g_manager->AddService(new CFG_S::Interface); |     AddService(new CFG_U::Interface); | ||||||
|     g_manager->AddService(new CFG_U::Interface); |     AddService(new CSND_SND::Interface); | ||||||
|     g_manager->AddService(new CSND_SND::Interface); |     AddService(new DSP_DSP::Interface); | ||||||
|     g_manager->AddService(new DSP_DSP::Interface); |     AddService(new ERR_F::Interface); | ||||||
|     g_manager->AddService(new ERR_F::Interface); |     AddService(new FRD_A::Interface); | ||||||
|     g_manager->AddService(new FRD_A::Interface); |     AddService(new FRD_U::Interface); | ||||||
|     g_manager->AddService(new FRD_U::Interface); |     AddService(new FS::FSUserInterface); | ||||||
|     g_manager->AddService(new FS::FSUserInterface); |     AddService(new GSP_GPU::Interface); | ||||||
|     g_manager->AddService(new GSP_GPU::Interface); |     AddService(new GSP_LCD::Interface); | ||||||
|     g_manager->AddService(new GSP_LCD::Interface); |     AddService(new HID_User::Interface); | ||||||
|     g_manager->AddService(new HID_User::Interface); |     AddService(new HID_SPVR::Interface); | ||||||
|     g_manager->AddService(new HID_SPVR::Interface); |     AddService(new HTTP_C::Interface); | ||||||
|     g_manager->AddService(new HTTP_C::Interface); |     AddService(new IR_RST::Interface); | ||||||
|     g_manager->AddService(new IR_RST::Interface); |     AddService(new IR_U::Interface); | ||||||
|     g_manager->AddService(new IR_U::Interface); |     AddService(new LDR_RO::Interface); | ||||||
|     g_manager->AddService(new LDR_RO::Interface); |     AddService(new MIC_U::Interface); | ||||||
|     g_manager->AddService(new MIC_U::Interface); |     AddService(new NDM_U::Interface); | ||||||
|     g_manager->AddService(new NDM_U::Interface); |     AddService(new NEWS_S::Interface); | ||||||
|     g_manager->AddService(new NEWS_S::Interface); |     AddService(new NEWS_U::Interface); | ||||||
|     g_manager->AddService(new NEWS_U::Interface); |     AddService(new NIM_AOC::Interface); | ||||||
|     g_manager->AddService(new NIM_AOC::Interface); |     AddService(new NS_S::Interface); | ||||||
|     g_manager->AddService(new NS_S::Interface); |     AddService(new NWM_UDS::Interface); | ||||||
|     g_manager->AddService(new NWM_UDS::Interface); |     AddService(new PM_APP::Interface); | ||||||
|     g_manager->AddService(new PM_APP::Interface); |     AddService(new PTM_PLAY::Interface); | ||||||
|     g_manager->AddService(new PTM_PLAY::Interface); |     AddService(new PTM_U::Interface); | ||||||
|     g_manager->AddService(new PTM_U::Interface); |     AddService(new PTM_SYSM::Interface); | ||||||
|     g_manager->AddService(new PTM_SYSM::Interface); |     AddService(new SOC_U::Interface); | ||||||
|     g_manager->AddService(new SOC_U::Interface); |     AddService(new SSL_C::Interface); | ||||||
|     g_manager->AddService(new SSL_C::Interface); |     AddService(new Y2R_U::Interface); | ||||||
|     g_manager->AddService(new Y2R_U::Interface); |  | ||||||
| 
 | 
 | ||||||
|     LOG_DEBUG(Service, "initialized OK"); |     LOG_DEBUG(Service, "initialized OK"); | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| /// Shutdown ServiceManager
 | /// Shutdown ServiceManager
 | ||||||
| void Shutdown() { | void Shutdown() { | ||||||
|     delete g_manager; |     g_srv_services.clear(); | ||||||
|  |     g_kernel_named_ports.clear(); | ||||||
|     LOG_DEBUG(Service, "shutdown OK"); |     LOG_DEBUG(Service, "shutdown OK"); | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
|  | |||||||
| @ -5,9 +5,11 @@ | |||||||
| #pragma once | #pragma once | ||||||
| 
 | 
 | ||||||
| #include <algorithm> | #include <algorithm> | ||||||
| #include <vector> |  | ||||||
| #include <map> |  | ||||||
| #include <string> | #include <string> | ||||||
|  | #include <unordered_map> | ||||||
|  | #include <vector> | ||||||
|  | 
 | ||||||
|  | #include <boost/container/flat_map.hpp> | ||||||
| 
 | 
 | ||||||
| #include "common/common.h" | #include "common/common.h" | ||||||
| #include "common/string_util.h" | #include "common/string_util.h" | ||||||
| @ -38,11 +40,11 @@ class Interface  : public Kernel::Session { | |||||||
|      * Creates a function string for logging, complete with the name (or header code, depending  |      * Creates a function string for logging, complete with the name (or header code, depending  | ||||||
|      * on what's passed in) the port name, and all the cmd_buff arguments. |      * on what's passed in) the port name, and all the cmd_buff arguments. | ||||||
|      */ |      */ | ||||||
|     std::string MakeFunctionString(const std::string& name, const std::string& port_name, const u32* cmd_buff) { |     std::string MakeFunctionString(const char* name, const char* port_name, const u32* cmd_buff) { | ||||||
|         // Number of params == bits 0-5 + bits 6-11
 |         // Number of params == bits 0-5 + bits 6-11
 | ||||||
|         int num_params = (cmd_buff[0] & 0x3F) + ((cmd_buff[0] >> 6) & 0x3F); |         int num_params = (cmd_buff[0] & 0x3F) + ((cmd_buff[0] >> 6) & 0x3F); | ||||||
| 
 | 
 | ||||||
|         std::string function_string = Common::StringFromFormat("function '%s': port=%s", name.c_str(), port_name.c_str()); |         std::string function_string = Common::StringFromFormat("function '%s': port=%s", name, port_name); | ||||||
|         for (int i = 1; i <= num_params; ++i) { |         for (int i = 1; i <= num_params; ++i) { | ||||||
|             function_string += Common::StringFromFormat(", cmd_buff[%i]=%u", i, cmd_buff[i]); |             function_string += Common::StringFromFormat(", cmd_buff[%i]=%u", i, cmd_buff[i]); | ||||||
|         } |         } | ||||||
| @ -57,7 +59,7 @@ public: | |||||||
|     struct FunctionInfo { |     struct FunctionInfo { | ||||||
|         u32         id; |         u32         id; | ||||||
|         Function    func; |         Function    func; | ||||||
|         std::string name; |         const char* name; | ||||||
|     }; |     }; | ||||||
| 
 | 
 | ||||||
|     /**
 |     /**
 | ||||||
| @ -68,34 +70,19 @@ public: | |||||||
|         return "[UNKNOWN SERVICE PORT]"; |         return "[UNKNOWN SERVICE PORT]"; | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     /// Allocates a new handle for the service
 |  | ||||||
|     Handle CreateHandle(Kernel::Object *obj) { |  | ||||||
|         // TODO(yuriks): Fix error reporting
 |  | ||||||
|         Handle handle = Kernel::g_handle_table.Create(obj).ValueOr(INVALID_HANDLE); |  | ||||||
|         m_handles.push_back(handle); |  | ||||||
|         return handle; |  | ||||||
|     } |  | ||||||
| 
 |  | ||||||
|     /// Frees a handle from the service
 |  | ||||||
|     template <class T> |  | ||||||
|     void DeleteHandle(const Handle handle) { |  | ||||||
|         Kernel::g_handle_table.Close(handle); |  | ||||||
|         m_handles.erase(std::remove(m_handles.begin(), m_handles.end(), handle), m_handles.end()); |  | ||||||
|     } |  | ||||||
| 
 |  | ||||||
|     ResultVal<bool> SyncRequest() override { |     ResultVal<bool> SyncRequest() override { | ||||||
|         u32* cmd_buff = Kernel::GetCommandBuffer(); |         u32* cmd_buff = Kernel::GetCommandBuffer(); | ||||||
|         auto itr = m_functions.find(cmd_buff[0]); |         auto itr = m_functions.find(cmd_buff[0]); | ||||||
| 
 | 
 | ||||||
|         if (itr == m_functions.end() || itr->second.func == nullptr) { |         if (itr == m_functions.end() || itr->second.func == nullptr) { | ||||||
|             std::string function_name = (itr == m_functions.end()) ? Common::StringFromFormat("0x%08X", cmd_buff[0]) : itr->second.name; |             std::string function_name = (itr == m_functions.end()) ? Common::StringFromFormat("0x%08X", cmd_buff[0]) : itr->second.name; | ||||||
|             LOG_ERROR(Service, "%s %s", "unknown/unimplemented", MakeFunctionString(function_name, GetPortName(), cmd_buff).c_str()); |             LOG_ERROR(Service, "unknown / unimplemented %s", MakeFunctionString(function_name.c_str(), GetPortName().c_str(), cmd_buff).c_str()); | ||||||
| 
 | 
 | ||||||
|             // TODO(bunnei): Hack - ignore error
 |             // TODO(bunnei): Hack - ignore error
 | ||||||
|             cmd_buff[1] = 0; |             cmd_buff[1] = 0; | ||||||
|             return MakeResult<bool>(false); |             return MakeResult<bool>(false); | ||||||
|         } else { |         } else { | ||||||
|             LOG_TRACE(Service, "%s", MakeFunctionString(itr->second.name, GetPortName(), cmd_buff).c_str()); |             LOG_TRACE(Service, "%s", MakeFunctionString(itr->second.name, GetPortName().c_str(), cmd_buff).c_str()); | ||||||
|         } |         } | ||||||
| 
 | 
 | ||||||
|         itr->second.func(this); |         itr->second.func(this); | ||||||
| @ -108,37 +95,18 @@ protected: | |||||||
|     /**
 |     /**
 | ||||||
|      * Registers the functions in the service |      * Registers the functions in the service | ||||||
|      */ |      */ | ||||||
|     void Register(const FunctionInfo* functions, int len) { |     template <size_t N> | ||||||
|         for (int i = 0; i < len; i++) { |     void Register(const FunctionInfo (&functions)[N]) { | ||||||
|             m_functions[functions[i].id] = functions[i]; |         m_functions.reserve(N); | ||||||
|  |         for (auto& fn : functions) { | ||||||
|  |             // Usually this array is sorted by id already, so hint to instead at the end
 | ||||||
|  |             m_functions.emplace_hint(m_functions.cend(), fn.id, fn); | ||||||
|         } |         } | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
| private: | private: | ||||||
|  |     boost::container::flat_map<u32, FunctionInfo> m_functions; | ||||||
| 
 | 
 | ||||||
|     std::vector<Handle>         m_handles; |  | ||||||
|     std::map<u32, FunctionInfo> m_functions; |  | ||||||
| 
 |  | ||||||
| }; |  | ||||||
| 
 |  | ||||||
| /// Simple class to manage accessing services from ports and UID handles
 |  | ||||||
| class Manager { |  | ||||||
| public: |  | ||||||
|     /// Add a service to the manager
 |  | ||||||
|     void AddService(Interface* service); |  | ||||||
| 
 |  | ||||||
|     /// Removes a service from the manager
 |  | ||||||
|     void DeleteService(const std::string& port_name); |  | ||||||
| 
 |  | ||||||
|     /// Get a Service Interface from its Handle
 |  | ||||||
|     Interface* FetchFromHandle(Handle handle); |  | ||||||
| 
 |  | ||||||
|     /// Get a Service Interface from its port
 |  | ||||||
|     Interface* FetchFromPortName(const std::string& port_name); |  | ||||||
| 
 |  | ||||||
| private: |  | ||||||
|     std::vector<Interface*>     m_services; |  | ||||||
|     std::map<std::string, u32>  m_port_map; |  | ||||||
| }; | }; | ||||||
| 
 | 
 | ||||||
| /// Initialize ServiceManager
 | /// Initialize ServiceManager
 | ||||||
| @ -147,8 +115,9 @@ void Init(); | |||||||
| /// Shutdown ServiceManager
 | /// Shutdown ServiceManager
 | ||||||
| void Shutdown(); | void Shutdown(); | ||||||
| 
 | 
 | ||||||
| 
 | /// Map of named ports managed by the kernel, which can be retrieved using the ConnectToPort SVC.
 | ||||||
| extern Manager* g_manager; ///< Service manager
 | extern std::unordered_map<std::string, Kernel::SharedPtr<Interface>> g_kernel_named_ports; | ||||||
| 
 | /// Map of services registered with the "srv:" service, retrieved using GetServiceHandle.
 | ||||||
|  | extern std::unordered_map<std::string, Kernel::SharedPtr<Interface>> g_srv_services; | ||||||
| 
 | 
 | ||||||
| } // namespace
 | } // namespace
 | ||||||
|  | |||||||
| @ -734,7 +734,7 @@ const Interface::FunctionInfo FunctionTable[] = { | |||||||
| // Interface class
 | // Interface class
 | ||||||
| 
 | 
 | ||||||
| Interface::Interface() { | Interface::Interface() { | ||||||
|     Register(FunctionTable, ARRAY_SIZE(FunctionTable)); |     Register(FunctionTable); | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| Interface::~Interface() { | Interface::~Interface() { | ||||||
|  | |||||||
| @ -23,7 +23,7 @@ static void GetProcSemaphore(Service::Interface* self) { | |||||||
|     u32* cmd_buff = Kernel::GetCommandBuffer(); |     u32* cmd_buff = Kernel::GetCommandBuffer(); | ||||||
| 
 | 
 | ||||||
|     // TODO(bunnei): Change to a semaphore once these have been implemented
 |     // TODO(bunnei): Change to a semaphore once these have been implemented
 | ||||||
|     event_handle = Kernel::Event::Create(RESETTYPE_ONESHOT, "SRV:Event").MoveFrom(); |     event_handle = Kernel::Event::Create(RESETTYPE_ONESHOT, "SRV:Event"); | ||||||
|     event_handle->Clear(); |     event_handle->Clear(); | ||||||
| 
 | 
 | ||||||
|     cmd_buff[1] = 0; // No error
 |     cmd_buff[1] = 0; // No error
 | ||||||
| @ -35,10 +35,10 @@ static void GetServiceHandle(Service::Interface* self) { | |||||||
|     u32* cmd_buff = Kernel::GetCommandBuffer(); |     u32* cmd_buff = Kernel::GetCommandBuffer(); | ||||||
| 
 | 
 | ||||||
|     std::string port_name = std::string((const char*)&cmd_buff[1], 0, Service::kMaxPortSize); |     std::string port_name = std::string((const char*)&cmd_buff[1], 0, Service::kMaxPortSize); | ||||||
|     Service::Interface* service = Service::g_manager->FetchFromPortName(port_name); |     auto it = Service::g_srv_services.find(port_name); | ||||||
| 
 | 
 | ||||||
|     if (nullptr != service) { |     if (it != Service::g_srv_services.end()) { | ||||||
|         cmd_buff[3] = service->GetHandle(); |         cmd_buff[3] = Kernel::g_handle_table.Create(it->second).MoveFrom(); | ||||||
|         LOG_TRACE(Service_SRV, "called port=%s, handle=0x%08X", port_name.c_str(), cmd_buff[3]); |         LOG_TRACE(Service_SRV, "called port=%s, handle=0x%08X", port_name.c_str(), cmd_buff[3]); | ||||||
|     } else { |     } else { | ||||||
|         LOG_ERROR(Service_SRV, "(UNIMPLEMENTED) called port=%s", port_name.c_str()); |         LOG_ERROR(Service_SRV, "(UNIMPLEMENTED) called port=%s", port_name.c_str()); | ||||||
| @ -63,7 +63,7 @@ const Interface::FunctionInfo FunctionTable[] = { | |||||||
| // Interface class
 | // Interface class
 | ||||||
| 
 | 
 | ||||||
| Interface::Interface() { | Interface::Interface() { | ||||||
|     Register(FunctionTable, ARRAY_SIZE(FunctionTable)); |     Register(FunctionTable); | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| } // namespace
 | } // namespace
 | ||||||
|  | |||||||
| @ -22,7 +22,7 @@ const Interface::FunctionInfo FunctionTable[] = { | |||||||
| // Interface class
 | // Interface class
 | ||||||
| 
 | 
 | ||||||
| Interface::Interface() { | Interface::Interface() { | ||||||
|     Register(FunctionTable, ARRAY_SIZE(FunctionTable)); |     Register(FunctionTable); | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| } // namespace
 | } // namespace
 | ||||||
|  | |||||||
| @ -54,7 +54,7 @@ const Interface::FunctionInfo FunctionTable[] = { | |||||||
| // Interface class
 | // Interface class
 | ||||||
| 
 | 
 | ||||||
| Interface::Interface() { | Interface::Interface() { | ||||||
|     Register(FunctionTable, ARRAY_SIZE(FunctionTable)); |     Register(FunctionTable); | ||||||
| } | } | ||||||
|      |      | ||||||
| } // namespace
 | } // namespace
 | ||||||
|  | |||||||
| @ -30,6 +30,11 @@ using Kernel::ERR_INVALID_HANDLE; | |||||||
| 
 | 
 | ||||||
| namespace SVC { | namespace SVC { | ||||||
| 
 | 
 | ||||||
|  | const ResultCode ERR_NOT_FOUND(ErrorDescription::NotFound, ErrorModule::Kernel, | ||||||
|  |         ErrorSummary::NotFound, ErrorLevel::Permanent); // 0xD88007FA
 | ||||||
|  | const ResultCode ERR_PORT_NAME_TOO_LONG(ErrorDescription(30), ErrorModule::OS, | ||||||
|  |         ErrorSummary::InvalidArgument, ErrorLevel::Usage); // 0xE0E0181E
 | ||||||
|  | 
 | ||||||
| /// An invalid result code that is meant to be overwritten when a thread resumes from waiting
 | /// An invalid result code that is meant to be overwritten when a thread resumes from waiting
 | ||||||
| const ResultCode RESULT_INVALID(0xDEADC0DE); | const ResultCode RESULT_INVALID(0xDEADC0DE); | ||||||
| 
 | 
 | ||||||
| @ -94,14 +99,21 @@ static ResultCode MapMemoryBlock(Handle handle, u32 addr, u32 permissions, u32 o | |||||||
| } | } | ||||||
| 
 | 
 | ||||||
| /// Connect to an OS service given the port name, returns the handle to the port to out
 | /// Connect to an OS service given the port name, returns the handle to the port to out
 | ||||||
| static ResultCode ConnectToPort(Handle* out, const char* port_name) { | static ResultCode ConnectToPort(Handle* out_handle, const char* port_name) { | ||||||
|     Service::Interface* service = Service::g_manager->FetchFromPortName(port_name); |     if (port_name == nullptr) | ||||||
|  |         return ERR_NOT_FOUND; | ||||||
|  |     if (std::strlen(port_name) > 11) | ||||||
|  |         return ERR_PORT_NAME_TOO_LONG; | ||||||
| 
 | 
 | ||||||
|     LOG_TRACE(Kernel_SVC, "called port_name=%s", port_name); |     LOG_TRACE(Kernel_SVC, "called port_name=%s", port_name); | ||||||
|     _assert_msg_(KERNEL, (service != nullptr), "called, but service is not implemented!"); |  | ||||||
| 
 | 
 | ||||||
|     *out = service->GetHandle(); |     auto it = Service::g_kernel_named_ports.find(port_name); | ||||||
|  |     if (it == Service::g_kernel_named_ports.end()) { | ||||||
|  |         LOG_WARNING(Kernel_SVC, "tried to connect to unknown port: %s", port_name); | ||||||
|  |         return ERR_NOT_FOUND; | ||||||
|  |     } | ||||||
| 
 | 
 | ||||||
|  |     CASCADE_RESULT(*out_handle, Kernel::g_handle_table.Create(it->second)); | ||||||
|     return RESULT_SUCCESS; |     return RESULT_SUCCESS; | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| @ -119,9 +131,8 @@ static ResultCode SendSyncRequest(Handle handle) { | |||||||
| 
 | 
 | ||||||
| /// Close a handle
 | /// Close a handle
 | ||||||
| static ResultCode CloseHandle(Handle handle) { | static ResultCode CloseHandle(Handle handle) { | ||||||
|     // ImplementMe
 |     LOG_TRACE(Kernel_SVC, "Closing handle 0x%08X", handle); | ||||||
|     LOG_ERROR(Kernel_SVC, "(UNIMPLEMENTED) called handle=0x%08X", handle); |     return Kernel::g_handle_table.Close(handle); | ||||||
|     return RESULT_SUCCESS; |  | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| /// Wait for a handle to synchronize, timeout after the specified nanoseconds
 | /// Wait for a handle to synchronize, timeout after the specified nanoseconds
 | ||||||
| @ -140,7 +151,7 @@ static ResultCode WaitSynchronization1(Handle handle, s64 nano_seconds) { | |||||||
|         Kernel::WaitCurrentThread_WaitSynchronization(object, false, false); |         Kernel::WaitCurrentThread_WaitSynchronization(object, false, false); | ||||||
| 
 | 
 | ||||||
|         // Create an event to wake the thread up after the specified nanosecond delay has passed
 |         // Create an event to wake the thread up after the specified nanosecond delay has passed
 | ||||||
|         Kernel::WakeThreadAfterDelay(Kernel::GetCurrentThread(), nano_seconds); |         Kernel::GetCurrentThread()->WakeAfterDelay(nano_seconds); | ||||||
| 
 | 
 | ||||||
|         HLE::Reschedule(__func__); |         HLE::Reschedule(__func__); | ||||||
| 
 | 
 | ||||||
| @ -216,7 +227,7 @@ static ResultCode WaitSynchronizationN(s32* out, Handle* handles, s32 handle_cou | |||||||
|         } |         } | ||||||
| 
 | 
 | ||||||
|         // Create an event to wake the thread up after the specified nanosecond delay has passed
 |         // Create an event to wake the thread up after the specified nanosecond delay has passed
 | ||||||
|         Kernel::WakeThreadAfterDelay(Kernel::GetCurrentThread(), nano_seconds); |         Kernel::GetCurrentThread()->WakeAfterDelay(nano_seconds); | ||||||
| 
 | 
 | ||||||
|         HLE::Reschedule(__func__); |         HLE::Reschedule(__func__); | ||||||
| 
 | 
 | ||||||
| @ -250,7 +261,7 @@ static ResultCode WaitSynchronizationN(s32* out, Handle* handles, s32 handle_cou | |||||||
| static ResultCode CreateAddressArbiter(Handle* out_handle) { | static ResultCode CreateAddressArbiter(Handle* out_handle) { | ||||||
|     using Kernel::AddressArbiter; |     using Kernel::AddressArbiter; | ||||||
| 
 | 
 | ||||||
|     CASCADE_RESULT(SharedPtr<AddressArbiter> arbiter, AddressArbiter::Create()); |     SharedPtr<AddressArbiter> arbiter = AddressArbiter::Create(); | ||||||
|     CASCADE_RESULT(*out_handle, Kernel::g_handle_table.Create(std::move(arbiter))); |     CASCADE_RESULT(*out_handle, Kernel::g_handle_table.Create(std::move(arbiter))); | ||||||
|     LOG_TRACE(Kernel_SVC, "returned handle=0x%08X", *out_handle); |     LOG_TRACE(Kernel_SVC, "returned handle=0x%08X", *out_handle); | ||||||
|     return RESULT_SUCCESS; |     return RESULT_SUCCESS; | ||||||
| @ -355,7 +366,7 @@ static ResultCode SetThreadPriority(Handle handle, s32 priority) { | |||||||
| static ResultCode CreateMutex(Handle* out_handle, u32 initial_locked) { | static ResultCode CreateMutex(Handle* out_handle, u32 initial_locked) { | ||||||
|     using Kernel::Mutex; |     using Kernel::Mutex; | ||||||
| 
 | 
 | ||||||
|     CASCADE_RESULT(SharedPtr<Mutex> mutex, Mutex::Create(initial_locked != 0)); |     SharedPtr<Mutex> mutex = Mutex::Create(initial_locked != 0); | ||||||
|     CASCADE_RESULT(*out_handle, Kernel::g_handle_table.Create(std::move(mutex))); |     CASCADE_RESULT(*out_handle, Kernel::g_handle_table.Create(std::move(mutex))); | ||||||
| 
 | 
 | ||||||
|     LOG_TRACE(Kernel_SVC, "called initial_locked=%s : created handle=0x%08X", |     LOG_TRACE(Kernel_SVC, "called initial_locked=%s : created handle=0x%08X", | ||||||
| @ -423,7 +434,9 @@ static ResultCode QueryMemory(void* info, void* out, u32 addr) { | |||||||
| 
 | 
 | ||||||
| /// Create an event
 | /// Create an event
 | ||||||
| static ResultCode CreateEvent(Handle* out_handle, u32 reset_type) { | static ResultCode CreateEvent(Handle* out_handle, u32 reset_type) { | ||||||
|     CASCADE_RESULT(auto evt, Kernel::Event::Create(static_cast<ResetType>(reset_type))); |     using Kernel::Event; | ||||||
|  | 
 | ||||||
|  |     SharedPtr<Event> evt = Kernel::Event::Create(static_cast<ResetType>(reset_type)); | ||||||
|     CASCADE_RESULT(*out_handle, Kernel::g_handle_table.Create(std::move(evt))); |     CASCADE_RESULT(*out_handle, Kernel::g_handle_table.Create(std::move(evt))); | ||||||
| 
 | 
 | ||||||
|     LOG_TRACE(Kernel_SVC, "called reset_type=0x%08X : created handle=0x%08X", |     LOG_TRACE(Kernel_SVC, "called reset_type=0x%08X : created handle=0x%08X", | ||||||
| @ -433,19 +446,17 @@ static ResultCode CreateEvent(Handle* out_handle, u32 reset_type) { | |||||||
| 
 | 
 | ||||||
| /// Duplicates a kernel handle
 | /// Duplicates a kernel handle
 | ||||||
| static ResultCode DuplicateHandle(Handle* out, Handle handle) { | static ResultCode DuplicateHandle(Handle* out, Handle handle) { | ||||||
|     ResultVal<Handle> out_h = Kernel::g_handle_table.Duplicate(handle); |     CASCADE_RESULT(*out, Kernel::g_handle_table.Duplicate(handle)); | ||||||
|     if (out_h.Succeeded()) { |  | ||||||
|         *out = *out_h; |  | ||||||
|     LOG_TRACE(Kernel_SVC, "duplicated 0x%08X to 0x%08X", handle, *out); |     LOG_TRACE(Kernel_SVC, "duplicated 0x%08X to 0x%08X", handle, *out); | ||||||
|     } |     return RESULT_SUCCESS; | ||||||
|     return out_h.Code(); |  | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| /// Signals an event
 | /// Signals an event
 | ||||||
| static ResultCode SignalEvent(Handle handle) { | static ResultCode SignalEvent(Handle handle) { | ||||||
|  |     using Kernel::Event; | ||||||
|     LOG_TRACE(Kernel_SVC, "called event=0x%08X", handle); |     LOG_TRACE(Kernel_SVC, "called event=0x%08X", handle); | ||||||
| 
 | 
 | ||||||
|     auto evt = Kernel::g_handle_table.Get<Kernel::Event>(handle); |     SharedPtr<Event> evt = Kernel::g_handle_table.Get<Kernel::Event>(handle); | ||||||
|     if (evt == nullptr) |     if (evt == nullptr) | ||||||
|         return ERR_INVALID_HANDLE; |         return ERR_INVALID_HANDLE; | ||||||
| 
 | 
 | ||||||
| @ -456,9 +467,10 @@ static ResultCode SignalEvent(Handle handle) { | |||||||
| 
 | 
 | ||||||
| /// Clears an event
 | /// Clears an event
 | ||||||
| static ResultCode ClearEvent(Handle handle) { | static ResultCode ClearEvent(Handle handle) { | ||||||
|  |     using Kernel::Event; | ||||||
|     LOG_TRACE(Kernel_SVC, "called event=0x%08X", handle); |     LOG_TRACE(Kernel_SVC, "called event=0x%08X", handle); | ||||||
| 
 | 
 | ||||||
|     auto evt = Kernel::g_handle_table.Get<Kernel::Event>(handle); |     SharedPtr<Event> evt = Kernel::g_handle_table.Get<Kernel::Event>(handle); | ||||||
|     if (evt == nullptr) |     if (evt == nullptr) | ||||||
|         return ERR_INVALID_HANDLE; |         return ERR_INVALID_HANDLE; | ||||||
| 
 | 
 | ||||||
| @ -470,7 +482,7 @@ static ResultCode ClearEvent(Handle handle) { | |||||||
| static ResultCode CreateTimer(Handle* out_handle, u32 reset_type) { | static ResultCode CreateTimer(Handle* out_handle, u32 reset_type) { | ||||||
|     using Kernel::Timer; |     using Kernel::Timer; | ||||||
| 
 | 
 | ||||||
|     CASCADE_RESULT(auto timer, Timer::Create(static_cast<ResetType>(reset_type))); |     SharedPtr<Timer> timer = Timer::Create(static_cast<ResetType>(reset_type)); | ||||||
|     CASCADE_RESULT(*out_handle, Kernel::g_handle_table.Create(std::move(timer))); |     CASCADE_RESULT(*out_handle, Kernel::g_handle_table.Create(std::move(timer))); | ||||||
| 
 | 
 | ||||||
|     LOG_TRACE(Kernel_SVC, "called reset_type=0x%08X : created handle=0x%08X", |     LOG_TRACE(Kernel_SVC, "called reset_type=0x%08X : created handle=0x%08X", | ||||||
| @ -528,7 +540,7 @@ static void SleepThread(s64 nanoseconds) { | |||||||
|     Kernel::WaitCurrentThread_Sleep(); |     Kernel::WaitCurrentThread_Sleep(); | ||||||
| 
 | 
 | ||||||
|     // Create an event to wake the thread up after the specified nanosecond delay has passed
 |     // Create an event to wake the thread up after the specified nanosecond delay has passed
 | ||||||
|     Kernel::WakeThreadAfterDelay(Kernel::GetCurrentThread(), nanoseconds); |     Kernel::GetCurrentThread()->WakeAfterDelay(nanoseconds); | ||||||
| 
 | 
 | ||||||
|     HLE::Reschedule(__func__); |     HLE::Reschedule(__func__); | ||||||
| } | } | ||||||
| @ -544,7 +556,7 @@ static ResultCode CreateMemoryBlock(Handle* out_handle, u32 addr, u32 size, u32 | |||||||
|     using Kernel::SharedMemory; |     using Kernel::SharedMemory; | ||||||
|     // TODO(Subv): Implement this function
 |     // TODO(Subv): Implement this function
 | ||||||
| 
 | 
 | ||||||
|     CASCADE_RESULT(auto shared_memory, SharedMemory::Create()); |     SharedPtr<SharedMemory> shared_memory = SharedMemory::Create(); | ||||||
|     CASCADE_RESULT(*out_handle, Kernel::g_handle_table.Create(std::move(shared_memory))); |     CASCADE_RESULT(*out_handle, Kernel::g_handle_table.Create(std::move(shared_memory))); | ||||||
| 
 | 
 | ||||||
|     LOG_WARNING(Kernel_SVC, "(STUBBED) called addr=0x%08X", addr); |     LOG_WARNING(Kernel_SVC, "(STUBBED) called addr=0x%08X", addr); | ||||||
|  | |||||||
		Loading…
	
		Reference in New Issue
	
	Block a user
	 bunnei
						bunnei