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 a new issue