diff options
Diffstat (limited to '')
-rw-r--r-- | src/core/hle/kernel/address_arbiter.cpp | 42 | ||||
-rw-r--r-- | src/core/hle/kernel/address_arbiter.h | 27 | ||||
-rw-r--r-- | src/core/hle/kernel/event.cpp | 83 | ||||
-rw-r--r-- | src/core/hle/kernel/event.h | 51 | ||||
-rw-r--r-- | src/core/hle/kernel/kernel.h | 8 | ||||
-rw-r--r-- | src/core/hle/kernel/mutex.cpp | 143 | ||||
-rw-r--r-- | src/core/hle/kernel/mutex.h | 52 | ||||
-rw-r--r-- | src/core/hle/kernel/semaphore.cpp | 65 | ||||
-rw-r--r-- | src/core/hle/kernel/semaphore.h | 57 | ||||
-rw-r--r-- | src/core/hle/kernel/shared_memory.cpp | 73 | ||||
-rw-r--r-- | src/core/hle/kernel/shared_memory.h | 60 | ||||
-rw-r--r-- | src/core/hle/kernel/thread.h | 3 | ||||
-rw-r--r-- | src/core/hle/kernel/timer.cpp | 107 | ||||
-rw-r--r-- | src/core/hle/kernel/timer.h | 69 |
14 files changed, 360 insertions, 480 deletions
diff --git a/src/core/hle/kernel/address_arbiter.cpp b/src/core/hle/kernel/address_arbiter.cpp index 9e855b0bf..2d01e2ef5 100644 --- a/src/core/hle/kernel/address_arbiter.cpp +++ b/src/core/hle/kernel/address_arbiter.cpp @@ -15,26 +15,18 @@ namespace Kernel { -class AddressArbiter : public Object { -public: - std::string GetTypeName() const override { return "Arbiter"; } - std::string GetName() const override { return name; } +ResultVal<SharedPtr<AddressArbiter>> AddressArbiter::Create(std::string name) { + 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)); - static const HandleType HANDLE_TYPE = HandleType::AddressArbiter; - HandleType GetHandleType() const override { return HANDLE_TYPE; } + address_arbiter->name = std::move(name); - std::string name; ///< Name of address arbiter object (optional) -}; - -//////////////////////////////////////////////////////////////////////////////////////////////////// - -/// Arbitrate an address -ResultCode ArbitrateAddress(Handle handle, ArbitrationType type, u32 address, s32 value, u64 nanoseconds) { - AddressArbiter* object = Kernel::g_handle_table.Get<AddressArbiter>(handle).get(); - - if (object == nullptr) - return InvalidHandle(ErrorModule::Kernel); + return MakeResult<SharedPtr<AddressArbiter>>(std::move(address_arbiter)); +} +ResultCode AddressArbiter::ArbitrateAddress(ArbitrationType type, VAddr address, s32 value, + u64 nanoseconds) { switch (type) { // Signal thread(s) waiting for arbitrate address... @@ -92,20 +84,4 @@ ResultCode ArbitrateAddress(Handle handle, ArbitrationType type, u32 address, s3 return RESULT_SUCCESS; } -/// Create an address arbiter -AddressArbiter* CreateAddressArbiter(Handle& handle, const std::string& name) { - AddressArbiter* address_arbiter = new AddressArbiter; - // TOOD(yuriks): Fix error reporting - handle = Kernel::g_handle_table.Create(address_arbiter).ValueOr(INVALID_HANDLE); - address_arbiter->name = name; - return address_arbiter; -} - -/// Create an address arbiter -Handle CreateAddressArbiter(const std::string& name) { - Handle handle; - CreateAddressArbiter(handle, name); - return handle; -} - } // namespace Kernel diff --git a/src/core/hle/kernel/address_arbiter.h b/src/core/hle/kernel/address_arbiter.h index 3ffd465a2..638afff9e 100644 --- a/src/core/hle/kernel/address_arbiter.h +++ b/src/core/hle/kernel/address_arbiter.h @@ -18,7 +18,6 @@ namespace Kernel { -/// Address arbitration types enum class ArbitrationType : u32 { Signal, WaitIfLessThan, @@ -27,10 +26,28 @@ enum class ArbitrationType : u32 { DecrementAndWaitIfLessThanWithTimeout, }; -/// Arbitrate an address -ResultCode ArbitrateAddress(Handle handle, ArbitrationType type, u32 address, s32 value, u64 nanoseconds); +class AddressArbiter final : public Object { +public: + /** + * Creates an address arbiter. + * + * @param name Optional name used for debugging. + * @returns The created AddressArbiter. + */ + static ResultVal<SharedPtr<AddressArbiter>> Create(std::string name = "Unknown"); -/// Create an address arbiter -Handle CreateAddressArbiter(const std::string& name = "Unknown"); + std::string GetTypeName() const override { return "Arbiter"; } + std::string GetName() const override { return name; } + + static const HandleType HANDLE_TYPE = HandleType::AddressArbiter; + HandleType GetHandleType() const override { return HANDLE_TYPE; } + + std::string name; ///< Name of address arbiter object (optional) + + ResultCode ArbitrateAddress(ArbitrationType type, VAddr address, s32 value, u64 nanoseconds); + +private: + AddressArbiter() = default; +}; } // namespace FileSys diff --git a/src/core/hle/kernel/event.cpp b/src/core/hle/kernel/event.cpp index a48125965..d9ad40c6a 100644 --- a/src/core/hle/kernel/event.cpp +++ b/src/core/hle/kernel/event.cpp @@ -14,78 +14,37 @@ namespace Kernel { -class Event : public WaitObject { -public: - std::string GetTypeName() const override { return "Event"; } - std::string GetName() const override { return name; } - - static const HandleType HANDLE_TYPE = HandleType::Event; - HandleType GetHandleType() const override { return HANDLE_TYPE; } - - ResetType intitial_reset_type; ///< ResetType specified at Event initialization - ResetType reset_type; ///< Current ResetType - - bool signaled; ///< Whether the event has already been signaled - std::string name; ///< Name of event (optional) - - bool ShouldWait() override { - return !signaled; - } - - void Acquire() override { - _assert_msg_(Kernel, !ShouldWait(), "object unavailable!"); - - // Release the event if it's not sticky... - if (reset_type != RESETTYPE_STICKY) - signaled = false; - } -}; - -ResultCode SignalEvent(const Handle handle) { - Event* evt = g_handle_table.Get<Event>(handle).get(); - if (evt == nullptr) - return InvalidHandle(ErrorModule::Kernel); - - evt->signaled = true; - evt->WakeupAllWaitingThreads(); - - return RESULT_SUCCESS; -} - -ResultCode ClearEvent(Handle handle) { - Event* evt = g_handle_table.Get<Event>(handle).get(); - if (evt == nullptr) - return InvalidHandle(ErrorModule::Kernel); +ResultVal<SharedPtr<Event>> Event::Create(ResetType reset_type, std::string name) { + 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->reset_type = evt->intitial_reset_type = reset_type; + evt->name = std::move(name); - return RESULT_SUCCESS; + return MakeResult<SharedPtr<Event>>(evt); } -/** - * Creates an event - * @param handle Reference to handle for the newly created mutex - * @param reset_type ResetType describing how to create event - * @param name Optional name of event - * @return Newly created Event object - */ -Event* CreateEvent(Handle& handle, const ResetType reset_type, const std::string& name) { - Event* evt = new Event; +bool Event::ShouldWait() { + return !signaled; +} - // TOOD(yuriks): Fix error reporting - handle = Kernel::g_handle_table.Create(evt).ValueOr(INVALID_HANDLE); +void Event::Acquire() { + _assert_msg_(Kernel, !ShouldWait(), "object unavailable!"); - evt->signaled = false; - evt->reset_type = evt->intitial_reset_type = reset_type; - evt->name = name; + // Release the event if it's not sticky... + if (reset_type != RESETTYPE_STICKY) + signaled = false; +} - return evt; +void Event::Signal() { + signaled = true; + WakeupAllWaitingThreads(); } -Handle CreateEvent(const ResetType reset_type, const std::string& name) { - Handle handle; - Event* evt = CreateEvent(handle, reset_type, name); - return handle; +void Event::Clear() { + signaled = false; } } // namespace diff --git a/src/core/hle/kernel/event.h b/src/core/hle/kernel/event.h index c08b12ee1..2c3e6b14e 100644 --- a/src/core/hle/kernel/event.h +++ b/src/core/hle/kernel/event.h @@ -11,26 +11,35 @@ namespace Kernel { -/** - * Signals an event - * @param handle Handle to event to signal - * @return Result of operation, 0 on success, otherwise error code - */ -ResultCode SignalEvent(const Handle handle); - -/** - * Clears an event - * @param handle Handle to event to clear - * @return Result of operation, 0 on success, otherwise error code - */ -ResultCode ClearEvent(Handle handle); - -/** - * Creates an event - * @param reset_type ResetType describing how to create event - * @param name Optional name of event - * @return Handle to newly created Event object - */ -Handle CreateEvent(const ResetType reset_type, const std::string& name="Unknown"); +class Event final : public WaitObject { +public: + /** + * Creates an event + * @param reset_type ResetType describing how to create event + * @param name Optional name of event + */ + static ResultVal<SharedPtr<Event>> Create(ResetType reset_type, std::string name = "Unknown"); + + std::string GetTypeName() const override { return "Event"; } + std::string GetName() const override { return name; } + + static const HandleType HANDLE_TYPE = HandleType::Event; + HandleType GetHandleType() const override { return HANDLE_TYPE; } + + ResetType intitial_reset_type; ///< ResetType specified at Event initialization + ResetType reset_type; ///< Current ResetType + + bool signaled; ///< Whether the event has already been signaled + std::string name; ///< Name of event (optional) + + bool ShouldWait() override; + void Acquire() override; + + void Signal(); + void Clear(); + +private: + Event() = default; +}; } // namespace diff --git a/src/core/hle/kernel/kernel.h b/src/core/hle/kernel/kernel.h index 3828efbea..9860479ac 100644 --- a/src/core/hle/kernel/kernel.h +++ b/src/core/hle/kernel/kernel.h @@ -16,6 +16,11 @@ typedef u32 Handle; typedef s32 Result; +// TODO: It would be nice to eventually replace these with strong types that prevent accidental +// conversion between each other. +typedef u32 VAddr; ///< Represents a pointer in the userspace virtual address space. +typedef u32 PAddr; ///< Represents a pointer in the ARM11 physical address space. + const Handle INVALID_HANDLE = 0; namespace Kernel { @@ -26,7 +31,8 @@ class Thread; const ResultCode ERR_OUT_OF_HANDLES(ErrorDescription::OutOfMemory, ErrorModule::Kernel, ErrorSummary::OutOfResource, ErrorLevel::Temporary); // TOOD: Verify code -const ResultCode ERR_INVALID_HANDLE = InvalidHandle(ErrorModule::Kernel); +const ResultCode ERR_INVALID_HANDLE(ErrorDescription::InvalidHandle, ErrorModule::Kernel, + ErrorSummary::InvalidArgument, ErrorLevel::Permanent); enum KernelHandle : Handle { CurrentThread = 0xFFFF8000, diff --git a/src/core/hle/kernel/mutex.cpp b/src/core/hle/kernel/mutex.cpp index cd05a1397..acf484659 100644 --- a/src/core/hle/kernel/mutex.cpp +++ b/src/core/hle/kernel/mutex.cpp @@ -13,59 +13,30 @@ namespace Kernel { -class Mutex : public WaitObject { -public: - std::string GetTypeName() const override { return "Mutex"; } - std::string GetName() const override { return name; } - - static const HandleType HANDLE_TYPE = HandleType::Mutex; - HandleType GetHandleType() const override { return HANDLE_TYPE; } - - bool initial_locked; ///< Initial lock state when mutex was created - bool locked; ///< Current locked state - std::string name; ///< Name of mutex (optional) - SharedPtr<Thread> holding_thread; ///< Thread that has acquired the mutex - - bool ShouldWait() override; - void Acquire() override; -}; - -//////////////////////////////////////////////////////////////////////////////////////////////////// - typedef std::multimap<SharedPtr<Thread>, SharedPtr<Mutex>> MutexMap; static MutexMap g_mutex_held_locks; /** - * Acquires the specified mutex for the specified thread - * @param mutex Mutex that is to be acquired - * @param thread Thread that will acquire the mutex - */ -void MutexAcquireLock(Mutex* mutex, Thread* thread) { - g_mutex_held_locks.insert(std::make_pair(thread, mutex)); - mutex->holding_thread = thread; -} - -/** * Resumes a thread waiting for the specified mutex * @param mutex The mutex that some thread is waiting on */ -void ResumeWaitingThread(Mutex* mutex) { +static void ResumeWaitingThread(Mutex* mutex) { + // Reset mutex lock thread handle, nothing is waiting + mutex->locked = false; + mutex->holding_thread = nullptr; + // Find the next waiting thread for the mutex... auto next_thread = mutex->WakeupNextThread(); if (next_thread != nullptr) { - MutexAcquireLock(mutex, next_thread); - } else { - // Reset mutex lock thread handle, nothing is waiting - mutex->locked = false; - mutex->holding_thread = nullptr; + mutex->Acquire(next_thread); } } void ReleaseThreadMutexes(Thread* thread) { - auto locked = g_mutex_held_locks.equal_range(thread); + auto locked_range = g_mutex_held_locks.equal_range(thread); // Release every mutex that the thread holds, and resume execution on the waiting threads - for (auto iter = locked.first; iter != locked.second; ++iter) { + for (auto iter = locked_range.first; iter != locked_range.second; ++iter) { ResumeWaitingThread(iter->second.get()); } @@ -73,72 +44,21 @@ void ReleaseThreadMutexes(Thread* thread) { g_mutex_held_locks.erase(thread); } -bool ReleaseMutex(Mutex* mutex) { - if (mutex->locked) { - auto locked = g_mutex_held_locks.equal_range(mutex->holding_thread); - - for (MutexMap::iterator iter = locked.first; iter != locked.second; ++iter) { - if (iter->second == mutex) { - g_mutex_held_locks.erase(iter); - break; - } - } - - ResumeWaitingThread(mutex); - } - return true; -} +ResultVal<SharedPtr<Mutex>> Mutex::Create(bool initial_locked, std::string name) { + SharedPtr<Mutex> mutex(new Mutex); + // TOOD(yuriks): Don't create Handle (see Thread::Create()) + CASCADE_RESULT(auto unused, Kernel::g_handle_table.Create(mutex)); -/** - * Releases a mutex - * @param handle Handle to mutex to release - */ -ResultCode ReleaseMutex(Handle handle) { - Mutex* mutex = Kernel::g_handle_table.Get<Mutex>(handle).get(); - if (mutex == nullptr) return InvalidHandle(ErrorModule::Kernel); - - if (!ReleaseMutex(mutex)) { - // TODO(yuriks): Verify error code, this one was pulled out of thin air. I'm not even sure - // what error condition this is supposed to be signaling. - return ResultCode(ErrorDescription::AlreadyDone, ErrorModule::Kernel, - ErrorSummary::NothingHappened, ErrorLevel::Temporary); - } - return RESULT_SUCCESS; -} - -/** - * Creates a mutex - * @param handle Reference to handle for the newly created mutex - * @param initial_locked Specifies if the mutex should be locked initially - * @param name Optional name of mutex - * @return Pointer to new Mutex object - */ -Mutex* CreateMutex(Handle& handle, bool initial_locked, const std::string& name) { - Mutex* mutex = new Mutex; - // TODO(yuriks): Fix error reporting - handle = Kernel::g_handle_table.Create(mutex).ValueOr(INVALID_HANDLE); - - mutex->locked = mutex->initial_locked = initial_locked; - mutex->name = name; + mutex->initial_locked = initial_locked; + mutex->locked = false; + mutex->name = std::move(name); mutex->holding_thread = nullptr; // Acquire mutex with current thread if initialized as locked... - if (mutex->locked) - MutexAcquireLock(mutex, GetCurrentThread()); - - return mutex; -} + if (initial_locked) + mutex->Acquire(); -/** - * Creates a mutex - * @param initial_locked Specifies if the mutex should be locked initially - * @param name Optional name of mutex - * @return Handle to newly created object - */ -Handle CreateMutex(bool initial_locked, const std::string& name) { - Handle handle; - Mutex* mutex = CreateMutex(handle, initial_locked, name); - return handle; + return MakeResult<SharedPtr<Mutex>>(mutex); } bool Mutex::ShouldWait() { @@ -146,9 +66,34 @@ bool Mutex::ShouldWait() { } void Mutex::Acquire() { + Acquire(GetCurrentThread()); +} + +void Mutex::Acquire(Thread* thread) { _assert_msg_(Kernel, !ShouldWait(), "object unavailable!"); + if (locked) + return; + locked = true; - MutexAcquireLock(this, GetCurrentThread()); + + g_mutex_held_locks.insert(std::make_pair(thread, this)); + holding_thread = thread; +} + +void Mutex::Release() { + if (!locked) + return; + + auto locked_range = g_mutex_held_locks.equal_range(holding_thread); + + 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); } } // namespace diff --git a/src/core/hle/kernel/mutex.h b/src/core/hle/kernel/mutex.h index bb8778c98..1e69528f1 100644 --- a/src/core/hle/kernel/mutex.h +++ b/src/core/hle/kernel/mutex.h @@ -4,25 +4,51 @@ #pragma once +#include <string> + #include "common/common_types.h" #include "core/hle/kernel/kernel.h" namespace Kernel { -/** - * Releases a mutex - * @param handle Handle to mutex to release - */ -ResultCode ReleaseMutex(Handle handle); - -/** - * Creates a mutex - * @param initial_locked Specifies if the mutex should be locked initially - * @param name Optional name of mutex - * @return Handle to newly created object - */ -Handle CreateMutex(bool initial_locked, const std::string& name="Unknown"); +class Thread; + +class Mutex final : public WaitObject { +public: + /** + * Creates a mutex. + * @param initial_locked Specifies if the mutex should be locked initially + * @param name Optional name of mutex + * @return Pointer to new Mutex object + */ + static ResultVal<SharedPtr<Mutex>> Create(bool initial_locked, std::string name = "Unknown"); + + std::string GetTypeName() const override { return "Mutex"; } + std::string GetName() const override { return name; } + + static const HandleType HANDLE_TYPE = HandleType::Mutex; + HandleType GetHandleType() const override { return HANDLE_TYPE; } + + bool initial_locked; ///< Initial lock state when mutex was created + bool locked; ///< Current locked state + std::string name; ///< Name of mutex (optional) + SharedPtr<Thread> holding_thread; ///< Thread that has acquired the mutex + + bool ShouldWait() override; + void Acquire() override; + + /** + * Acquires the specified mutex for the specified thread + * @param mutex Mutex that is to be acquired + * @param thread Thread that will acquire the mutex + */ + void Acquire(Thread* thread); + void Release(); + +private: + Mutex() = default; +}; /** * Releases all the mutexes held by the specified thread diff --git a/src/core/hle/kernel/semaphore.cpp b/src/core/hle/kernel/semaphore.cpp index 135d8fb2a..a9e406ef4 100644 --- a/src/core/hle/kernel/semaphore.cpp +++ b/src/core/hle/kernel/semaphore.cpp @@ -2,8 +2,6 @@ // Licensed under GPLv2 or any later version // Refer to the license.txt file included. -#include <queue> - #include "common/common.h" #include "core/hle/kernel/kernel.h" @@ -12,69 +10,50 @@ namespace Kernel { -class Semaphore : public WaitObject { -public: - std::string GetTypeName() const override { return "Semaphore"; } - std::string GetName() const override { return name; } - - static const HandleType HANDLE_TYPE = HandleType::Semaphore; - HandleType GetHandleType() const override { return HANDLE_TYPE; } - - s32 max_count; ///< Maximum number of simultaneous holders the semaphore can have - s32 available_count; ///< Number of free slots left in the semaphore - std::string name; ///< Name of semaphore (optional) - - bool ShouldWait() override { - return available_count <= 0; - } - - void Acquire() override { - _assert_msg_(Kernel, !ShouldWait(), "object unavailable!"); - --available_count; - } -}; - -//////////////////////////////////////////////////////////////////////////////////////////////////// - -ResultCode CreateSemaphore(Handle* handle, s32 initial_count, - s32 max_count, const std::string& name) { +ResultVal<SharedPtr<Semaphore>> Semaphore::Create(s32 initial_count, s32 max_count, + std::string name) { if (initial_count > max_count) return ResultCode(ErrorDescription::InvalidCombination, ErrorModule::Kernel, ErrorSummary::WrongArgument, ErrorLevel::Permanent); - Semaphore* semaphore = new Semaphore; - // TOOD(yuriks): Fix error reporting - *handle = g_handle_table.Create(semaphore).ValueOr(INVALID_HANDLE); + 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, // and the rest is reserved for the caller thread semaphore->max_count = max_count; semaphore->available_count = initial_count; - semaphore->name = name; + semaphore->name = std::move(name); - return RESULT_SUCCESS; + return MakeResult<SharedPtr<Semaphore>>(std::move(semaphore)); } -ResultCode ReleaseSemaphore(s32* count, Handle handle, s32 release_count) { - Semaphore* semaphore = g_handle_table.Get<Semaphore>(handle).get(); - if (semaphore == nullptr) - return InvalidHandle(ErrorModule::Kernel); +bool Semaphore::ShouldWait() { + return available_count <= 0; +} + +void Semaphore::Acquire() { + _assert_msg_(Kernel, !ShouldWait(), "object unavailable!"); + --available_count; +} - if (semaphore->max_count - semaphore->available_count < release_count) +ResultVal<s32> Semaphore::Release(s32 release_count) { + if (max_count - available_count < release_count) return ResultCode(ErrorDescription::OutOfRange, ErrorModule::Kernel, ErrorSummary::InvalidArgument, ErrorLevel::Permanent); - *count = semaphore->available_count; - semaphore->available_count += release_count; + s32 previous_count = available_count; + available_count += release_count; // Notify some of the threads that the semaphore has been released // stop once the semaphore is full again or there are no more waiting threads - while (!semaphore->ShouldWait() && semaphore->WakeupNextThread() != nullptr) { - semaphore->Acquire(); + while (!ShouldWait() && WakeupNextThread() != nullptr) { + Acquire(); } - return RESULT_SUCCESS; + return MakeResult<s32>(previous_count); } } // namespace diff --git a/src/core/hle/kernel/semaphore.h b/src/core/hle/kernel/semaphore.h index 8644ecf0c..9bb404ab6 100644 --- a/src/core/hle/kernel/semaphore.h +++ b/src/core/hle/kernel/semaphore.h @@ -4,29 +4,50 @@ #pragma once +#include <queue> +#include <string> + #include "common/common_types.h" #include "core/hle/kernel/kernel.h" namespace Kernel { -/** - * Creates a semaphore. - * @param handle Pointer to the handle of the newly created object - * @param initial_count Number of slots reserved for other threads - * @param max_count Maximum number of slots the semaphore can have - * @param name Optional name of semaphore - * @return ResultCode of the error - */ -ResultCode CreateSemaphore(Handle* handle, s32 initial_count, s32 max_count, const std::string& name = "Unknown"); - -/** - * Releases a certain number of slots from a semaphore. - * @param count The number of free slots the semaphore had before this call - * @param handle The handle of the semaphore to release - * @param release_count The number of slots to release - * @return ResultCode of the error - */ -ResultCode ReleaseSemaphore(s32* count, Handle handle, s32 release_count); +class Semaphore final : public WaitObject { +public: + /** + * Creates a semaphore. + * @param handle Pointer to the handle of the newly created object + * @param initial_count Number of slots reserved for other threads + * @param max_count Maximum number of slots the semaphore can have + * @param name Optional name of semaphore + * @return The created semaphore + */ + static ResultVal<SharedPtr<Semaphore>> Create(s32 initial_count, s32 max_count, + std::string name = "Unknown"); + + std::string GetTypeName() const override { return "Semaphore"; } + std::string GetName() const override { return name; } + + static const HandleType HANDLE_TYPE = HandleType::Semaphore; + HandleType GetHandleType() const override { return HANDLE_TYPE; } + + s32 max_count; ///< Maximum number of simultaneous holders the semaphore can have + s32 available_count; ///< Number of free slots left in the semaphore + std::string name; ///< Name of semaphore (optional) + + bool ShouldWait() override; + void Acquire() override; + + /** + * Releases a certain number of slots from a semaphore. + * @param release_count The number of slots to release + * @return The number of free slots the semaphore had before this call + */ + ResultVal<s32> Release(s32 release_count); + +private: + Semaphore() = default; +}; } // namespace diff --git a/src/core/hle/kernel/shared_memory.cpp b/src/core/hle/kernel/shared_memory.cpp index 5368e4728..536d134b0 100644 --- a/src/core/hle/kernel/shared_memory.cpp +++ b/src/core/hle/kernel/shared_memory.cpp @@ -9,76 +9,39 @@ namespace Kernel { -class SharedMemory : public Object { -public: - std::string GetTypeName() const override { return "SharedMemory"; } +ResultVal<SharedPtr<SharedMemory>> SharedMemory::Create(std::string name) { + SharedPtr<SharedMemory> shared_memory(new SharedMemory); - static const HandleType HANDLE_TYPE = HandleType::SharedMemory; - HandleType GetHandleType() const override { return HANDLE_TYPE; } + // TOOD(yuriks): Don't create Handle (see Thread::Create()) + CASCADE_RESULT(auto unused, Kernel::g_handle_table.Create(shared_memory)); - u32 base_address; ///< Address of shared memory block in RAM - MemoryPermission permissions; ///< Permissions of shared memory block (SVC field) - MemoryPermission other_permissions; ///< Other permissions of shared memory block (SVC field) - std::string name; ///< Name of shared memory object (optional) -}; - -//////////////////////////////////////////////////////////////////////////////////////////////////// - -/** - * Creates a shared memory object - * @param handle Handle of newly created shared memory object - * @param name Name of shared memory object - * @return Pointer to newly created shared memory object - */ -SharedMemory* CreateSharedMemory(Handle& handle, const std::string& name) { - SharedMemory* shared_memory = new SharedMemory; - // TOOD(yuriks): Fix error reporting - handle = Kernel::g_handle_table.Create(shared_memory).ValueOr(INVALID_HANDLE); - shared_memory->name = name; - return shared_memory; + shared_memory->name = std::move(name); + return MakeResult<SharedPtr<SharedMemory>>(std::move(shared_memory)); } -Handle CreateSharedMemory(const std::string& name) { - Handle handle; - CreateSharedMemory(handle, name); - return handle; -} - -/** - * Maps a shared memory block to an address in system memory - * @param handle Shared memory block handle - * @param address Address in system memory to map shared memory block to - * @param permissions Memory block map permissions (specified by SVC field) - * @param other_permissions Memory block map other permissions (specified by SVC field) - * @return Result of operation, 0 on success, otherwise error code - */ -ResultCode MapSharedMemory(u32 handle, u32 address, MemoryPermission permissions, - MemoryPermission other_permissions) { +ResultCode SharedMemory::Map(VAddr address, MemoryPermission permissions, + MemoryPermission other_permissions) { if (address < Memory::SHARED_MEMORY_VADDR || address >= Memory::SHARED_MEMORY_VADDR_END) { - LOG_ERROR(Kernel_SVC, "cannot map handle=0x%08X, address=0x%08X outside of shared mem bounds!", - handle, address); + LOG_ERROR(Kernel, "cannot map handle=0x%08X, address=0x%08X outside of shared mem bounds!", + GetHandle(), address); + // TODO: Verify error code with hardware return ResultCode(ErrorDescription::InvalidAddress, ErrorModule::Kernel, ErrorSummary::InvalidArgument, ErrorLevel::Permanent); } - SharedMemory* shared_memory = Kernel::g_handle_table.Get<SharedMemory>(handle).get(); - if (shared_memory == nullptr) return InvalidHandle(ErrorModule::Kernel); - shared_memory->base_address = address; - shared_memory->permissions = permissions; - shared_memory->other_permissions = other_permissions; + base_address = address; + permissions = permissions; + other_permissions = other_permissions; return RESULT_SUCCESS; } -ResultVal<u8*> GetSharedMemoryPointer(Handle handle, u32 offset) { - SharedMemory* shared_memory = Kernel::g_handle_table.Get<SharedMemory>(handle).get(); - if (shared_memory == nullptr) return InvalidHandle(ErrorModule::Kernel); - - if (0 != shared_memory->base_address) - return MakeResult<u8*>(Memory::GetPointer(shared_memory->base_address + offset)); +ResultVal<u8*> SharedMemory::GetPointer(u32 offset) { + if (base_address != 0) + return MakeResult<u8*>(Memory::GetPointer(base_address + offset)); - LOG_ERROR(Kernel_SVC, "memory block handle=0x%08X not mapped!", handle); + LOG_ERROR(Kernel_SVC, "memory block handle=0x%08X not mapped!", GetHandle()); // TODO(yuriks): Verify error code. return ResultCode(ErrorDescription::InvalidAddress, ErrorModule::Kernel, ErrorSummary::InvalidState, ErrorLevel::Permanent); diff --git a/src/core/hle/kernel/shared_memory.h b/src/core/hle/kernel/shared_memory.h index bb65c7ccd..f9ae23e93 100644 --- a/src/core/hle/kernel/shared_memory.h +++ b/src/core/hle/kernel/shared_memory.h @@ -23,29 +23,41 @@ enum class MemoryPermission : u32 { DontCare = (1u << 28) }; -/** - * Creates a shared memory object - * @param name Optional name of shared memory object - * @return Handle of newly created shared memory object - */ -Handle CreateSharedMemory(const std::string& name="Unknown"); - -/** - * Maps a shared memory block to an address in system memory - * @param handle Shared memory block handle - * @param address Address in system memory to map shared memory block to - * @param permissions Memory block map permissions (specified by SVC field) - * @param other_permissions Memory block map other permissions (specified by SVC field) - */ -ResultCode MapSharedMemory(Handle handle, u32 address, MemoryPermission permissions, - MemoryPermission other_permissions); - -/** - * Gets a pointer to the shared memory block - * @param handle Shared memory block handle - * @param offset Offset from the start of the shared memory block to get pointer - * @return Pointer to the shared memory block from the specified offset - */ -ResultVal<u8*> GetSharedMemoryPointer(Handle handle, u32 offset); +class SharedMemory final : public Object { +public: + /** + * Creates a shared memory object + * @param name Optional object name, used only for debugging purposes. + */ + static ResultVal<SharedPtr<SharedMemory>> Create(std::string name = "Unknown"); + + std::string GetTypeName() const override { return "SharedMemory"; } + + static const HandleType HANDLE_TYPE = HandleType::SharedMemory; + HandleType GetHandleType() const override { return HANDLE_TYPE; } + + /** + * Maps a shared memory block to an address in system memory + * @param address Address in system memory to map shared memory block to + * @param permissions Memory block map permissions (specified by SVC field) + * @param other_permissions Memory block map other permissions (specified by SVC field) + */ + ResultCode Map(VAddr address, MemoryPermission permissions, MemoryPermission other_permissions); + + /** + * Gets a pointer to the shared memory block + * @param offset Offset from the start of the shared memory block to get pointer + * @return Pointer to the shared memory block from the specified offset + */ + ResultVal<u8*> GetPointer(u32 offset = 0); + + VAddr base_address; ///< Address of shared memory block in RAM + MemoryPermission permissions; ///< Permissions of shared memory block (SVC field) + MemoryPermission other_permissions; ///< Other permissions of shared memory block (SVC field) + std::string name; ///< Name of shared memory object (optional) + +private: + SharedMemory() = default; +}; } // namespace diff --git a/src/core/hle/kernel/thread.h b/src/core/hle/kernel/thread.h index 5fab1ab58..d6299364a 100644 --- a/src/core/hle/kernel/thread.h +++ b/src/core/hle/kernel/thread.h @@ -40,7 +40,7 @@ enum ThreadStatus { namespace Kernel { -class Thread : public WaitObject { +class Thread final : public WaitObject { public: static ResultVal<SharedPtr<Thread>> Create(std::string name, VAddr entry_point, s32 priority, u32 arg, s32 processor_id, VAddr stack_top, u32 stack_size); @@ -115,7 +115,6 @@ public: bool idle = false; private: - Thread() = default; }; diff --git a/src/core/hle/kernel/timer.cpp b/src/core/hle/kernel/timer.cpp index ec0b2c323..503a5d2ce 100644 --- a/src/core/hle/kernel/timer.cpp +++ b/src/core/hle/kernel/timer.cpp @@ -13,75 +13,54 @@ namespace Kernel { -class Timer : public WaitObject { -public: - std::string GetTypeName() const override { return "Timer"; } - std::string GetName() const override { return name; } - - static const HandleType HANDLE_TYPE = HandleType::Timer; - HandleType GetHandleType() const override { return HANDLE_TYPE; } - - ResetType reset_type; ///< The ResetType of this timer - - bool signaled; ///< Whether the timer has been signaled or not - std::string name; ///< Name of timer (optional) - - u64 initial_delay; ///< The delay until the timer fires for the first time - u64 interval_delay; ///< The delay until the timer fires after the first time - - bool ShouldWait() override { - return !signaled; - } - - void Acquire() override { - _assert_msg_(Kernel, !ShouldWait(), "object unavailable!"); - } -}; - -/** - * Creates a timer. - * @param handle Reference to handle for the newly created timer - * @param reset_type ResetType describing how to create timer - * @param name Optional name of timer - * @return Newly created Timer object - */ -Timer* CreateTimer(Handle& handle, const ResetType reset_type, const std::string& name) { - Timer* timer = new Timer; +/// The event type of the generic timer callback event +static int timer_callback_event_type = -1; - handle = Kernel::g_handle_table.Create(timer).ValueOr(INVALID_HANDLE); +ResultVal<SharedPtr<Timer>> Timer::Create(ResetType reset_type, std::string name) { + 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->signaled = false; - timer->name = name; + timer->name = std::move(name); timer->initial_delay = 0; timer->interval_delay = 0; - return timer; + return MakeResult<SharedPtr<Timer>>(timer); } -ResultCode CreateTimer(Handle* handle, const ResetType reset_type, const std::string& name) { - CreateTimer(*handle, reset_type, name); - return RESULT_SUCCESS; +bool Timer::ShouldWait() { + return !signaled; } -ResultCode ClearTimer(Handle handle) { - SharedPtr<Timer> timer = Kernel::g_handle_table.Get<Timer>(handle); - - if (timer == nullptr) - return InvalidHandle(ErrorModule::Kernel); +void Timer::Acquire() { + _assert_msg_(Kernel, !ShouldWait(), "object unavailable!"); +} - timer->signaled = false; - return RESULT_SUCCESS; +void Timer::Set(s64 initial, s64 interval) { + initial_delay = initial; + interval_delay = interval; + + u64 initial_microseconds = initial / 1000; + // TODO(yuriks): Figure out a replacement for GetHandle here + CoreTiming::ScheduleEvent(usToCycles(initial_microseconds), timer_callback_event_type, + GetHandle()); } -/// The event type of the generic timer callback event -static int TimerCallbackEventType = -1; +void Timer::Cancel() { + CoreTiming::UnscheduleEvent(timer_callback_event_type, GetHandle()); +} + +void Timer::Clear() { + signaled = false; +} /// The timer callback event, called when a timer is fired static void TimerCallback(u64 timer_handle, int cycles_late) { SharedPtr<Timer> timer = Kernel::g_handle_table.Get<Timer>(timer_handle); if (timer == nullptr) { - LOG_CRITICAL(Kernel, "Callback fired for invalid timer %u", timer_handle); + LOG_CRITICAL(Kernel, "Callback fired for invalid timer %08X", timer_handle); return; } @@ -99,36 +78,12 @@ static void TimerCallback(u64 timer_handle, int cycles_late) { // Reschedule the timer with the interval delay u64 interval_microseconds = timer->interval_delay / 1000; CoreTiming::ScheduleEvent(usToCycles(interval_microseconds) - cycles_late, - TimerCallbackEventType, timer_handle); + timer_callback_event_type, timer_handle); } } -ResultCode SetTimer(Handle handle, s64 initial, s64 interval) { - SharedPtr<Timer> timer = Kernel::g_handle_table.Get<Timer>(handle); - - if (timer == nullptr) - return InvalidHandle(ErrorModule::Kernel); - - timer->initial_delay = initial; - timer->interval_delay = interval; - - u64 initial_microseconds = initial / 1000; - CoreTiming::ScheduleEvent(usToCycles(initial_microseconds), TimerCallbackEventType, handle); - return RESULT_SUCCESS; -} - -ResultCode CancelTimer(Handle handle) { - SharedPtr<Timer> timer = Kernel::g_handle_table.Get<Timer>(handle); - - if (timer == nullptr) - return InvalidHandle(ErrorModule::Kernel); - - CoreTiming::UnscheduleEvent(TimerCallbackEventType, handle); - return RESULT_SUCCESS; -} - void TimersInit() { - TimerCallbackEventType = CoreTiming::RegisterEvent("TimerCallback", TimerCallback); + timer_callback_event_type = CoreTiming::RegisterEvent("TimerCallback", TimerCallback); } void TimersShutdown() { diff --git a/src/core/hle/kernel/timer.h b/src/core/hle/kernel/timer.h index 8170e82d4..c45e79954 100644 --- a/src/core/hle/kernel/timer.h +++ b/src/core/hle/kernel/timer.h @@ -11,37 +11,50 @@ namespace Kernel { -/** - * Cancels a timer - * @param handle Handle of the timer to cancel - */ -ResultCode CancelTimer(Handle handle); - -/** - * Starts a timer with the specified initial delay and interval - * @param handle Handle of the timer to start - * @param initial Delay until the timer is first fired - * @param interval Delay until the timer is fired after the first time - */ -ResultCode SetTimer(Handle handle, s64 initial, s64 interval); - -/** - * Clears a timer - * @param handle Handle of the timer to clear - */ -ResultCode ClearTimer(Handle handle); - -/** - * Creates a timer - * @param handle Handle to the newly created Timer object - * @param reset_type ResetType describing how to create the timer - * @param name Optional name of timer - * @return ResultCode of the error - */ -ResultCode CreateTimer(Handle* handle, const ResetType reset_type, const std::string& name="Unknown"); +class Timer final : public WaitObject { +public: + /** + * Creates a timer + * @param reset_type ResetType describing how to create the timer + * @param name Optional name of timer + * @return The created Timer + */ + static ResultVal<SharedPtr<Timer>> Create(ResetType reset_type, std::string name = "Unknown"); + + std::string GetTypeName() const override { return "Timer"; } + std::string GetName() const override { return name; } + + static const HandleType HANDLE_TYPE = HandleType::Timer; + HandleType GetHandleType() const override { return HANDLE_TYPE; } + + ResetType reset_type; ///< The ResetType of this timer + + bool signaled; ///< Whether the timer has been signaled or not + std::string name; ///< Name of timer (optional) + + u64 initial_delay; ///< The delay until the timer fires for the first time + u64 interval_delay; ///< The delay until the timer fires after the first time + + bool ShouldWait() override; + void Acquire() override; + + /** + * Starts the timer, with the specified initial delay and interval. + * @param initial Delay until the timer is first fired + * @param interval Delay until the timer is fired after the first time + */ + void Set(s64 initial, s64 interval); + + void Cancel(); + void Clear(); + +private: + Timer() = default; +}; /// Initializes the required variables for timers void TimersInit(); /// Tears down the timer variables void TimersShutdown(); + } // namespace |