diff options
| author | 2015-01-30 15:00:17 +0100 | |
|---|---|---|
| committer | 2015-01-30 15:00:17 +0100 | |
| commit | 28702cbfeb1fe21109f8b1efa189785594319b78 (patch) | |
| tree | 64e4b1ec43b7699fe1a6ab1be1c688b6d63c0d75 /src/core/hle/kernel | |
| parent | Merge pull request #412 from purpasmart96/svc_table_cleanup (diff) | |
| parent | Kernel: Mark all appropriate kernel objects as "final" (diff) | |
| download | yuzu-28702cbfeb1fe21109f8b1efa189785594319b78.tar.gz yuzu-28702cbfeb1fe21109f8b1efa189785594319b78.tar.xz yuzu-28702cbfeb1fe21109f8b1efa189785594319b78.zip | |
Merge pull request #503 from yuriks/kernel-lifetime4
Kernel Lifetime Reform Pt. 4
Diffstat (limited to 'src/core/hle/kernel')
| -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 @@ | |||
| 15 | 15 | ||
| 16 | namespace Kernel { | 16 | namespace Kernel { |
| 17 | 17 | ||
| 18 | class AddressArbiter : public Object { | 18 | ResultVal<SharedPtr<AddressArbiter>> AddressArbiter::Create(std::string name) { |
| 19 | public: | 19 | SharedPtr<AddressArbiter> address_arbiter(new AddressArbiter); |
| 20 | std::string GetTypeName() const override { return "Arbiter"; } | 20 | // TOOD(yuriks): Don't create Handle (see Thread::Create()) |
| 21 | std::string GetName() const override { return name; } | 21 | CASCADE_RESULT(auto unused, Kernel::g_handle_table.Create(address_arbiter)); |
| 22 | 22 | ||
| 23 | static const HandleType HANDLE_TYPE = HandleType::AddressArbiter; | 23 | address_arbiter->name = std::move(name); |
| 24 | HandleType GetHandleType() const override { return HANDLE_TYPE; } | ||
| 25 | 24 | ||
| 26 | std::string name; ///< Name of address arbiter object (optional) | 25 | return MakeResult<SharedPtr<AddressArbiter>>(std::move(address_arbiter)); |
| 27 | }; | 26 | } |
| 28 | |||
| 29 | //////////////////////////////////////////////////////////////////////////////////////////////////// | ||
| 30 | |||
| 31 | /// Arbitrate an address | ||
| 32 | ResultCode ArbitrateAddress(Handle handle, ArbitrationType type, u32 address, s32 value, u64 nanoseconds) { | ||
| 33 | AddressArbiter* object = Kernel::g_handle_table.Get<AddressArbiter>(handle).get(); | ||
| 34 | |||
| 35 | if (object == nullptr) | ||
| 36 | return InvalidHandle(ErrorModule::Kernel); | ||
| 37 | 27 | ||
| 28 | ResultCode AddressArbiter::ArbitrateAddress(ArbitrationType type, VAddr address, s32 value, | ||
| 29 | u64 nanoseconds) { | ||
| 38 | switch (type) { | 30 | switch (type) { |
| 39 | 31 | ||
| 40 | // Signal thread(s) waiting for arbitrate address... | 32 | // Signal thread(s) waiting for arbitrate address... |
| @@ -92,20 +84,4 @@ ResultCode ArbitrateAddress(Handle handle, ArbitrationType type, u32 address, s3 | |||
| 92 | return RESULT_SUCCESS; | 84 | return RESULT_SUCCESS; |
| 93 | } | 85 | } |
| 94 | 86 | ||
| 95 | /// Create an address arbiter | ||
| 96 | AddressArbiter* CreateAddressArbiter(Handle& handle, const std::string& name) { | ||
| 97 | AddressArbiter* address_arbiter = new AddressArbiter; | ||
| 98 | // TOOD(yuriks): Fix error reporting | ||
| 99 | handle = Kernel::g_handle_table.Create(address_arbiter).ValueOr(INVALID_HANDLE); | ||
| 100 | address_arbiter->name = name; | ||
| 101 | return address_arbiter; | ||
| 102 | } | ||
| 103 | |||
| 104 | /// Create an address arbiter | ||
| 105 | Handle CreateAddressArbiter(const std::string& name) { | ||
| 106 | Handle handle; | ||
| 107 | CreateAddressArbiter(handle, name); | ||
| 108 | return handle; | ||
| 109 | } | ||
| 110 | |||
| 111 | } // namespace Kernel | 87 | } // 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 @@ | |||
| 18 | 18 | ||
| 19 | namespace Kernel { | 19 | namespace Kernel { |
| 20 | 20 | ||
| 21 | /// Address arbitration types | ||
| 22 | enum class ArbitrationType : u32 { | 21 | enum class ArbitrationType : u32 { |
| 23 | Signal, | 22 | Signal, |
| 24 | WaitIfLessThan, | 23 | WaitIfLessThan, |
| @@ -27,10 +26,28 @@ enum class ArbitrationType : u32 { | |||
| 27 | DecrementAndWaitIfLessThanWithTimeout, | 26 | DecrementAndWaitIfLessThanWithTimeout, |
| 28 | }; | 27 | }; |
| 29 | 28 | ||
| 30 | /// Arbitrate an address | 29 | class AddressArbiter final : public Object { |
| 31 | ResultCode ArbitrateAddress(Handle handle, ArbitrationType type, u32 address, s32 value, u64 nanoseconds); | 30 | public: |
| 31 | /** | ||
| 32 | * Creates an address arbiter. | ||
| 33 | * | ||
| 34 | * @param name Optional name used for debugging. | ||
| 35 | * @returns The created AddressArbiter. | ||
| 36 | */ | ||
| 37 | static ResultVal<SharedPtr<AddressArbiter>> Create(std::string name = "Unknown"); | ||
| 32 | 38 | ||
| 33 | /// Create an address arbiter | 39 | std::string GetTypeName() const override { return "Arbiter"; } |
| 34 | Handle CreateAddressArbiter(const std::string& name = "Unknown"); | 40 | std::string GetName() const override { return name; } |
| 41 | |||
| 42 | static const HandleType HANDLE_TYPE = HandleType::AddressArbiter; | ||
| 43 | HandleType GetHandleType() const override { return HANDLE_TYPE; } | ||
| 44 | |||
| 45 | std::string name; ///< Name of address arbiter object (optional) | ||
| 46 | |||
| 47 | ResultCode ArbitrateAddress(ArbitrationType type, VAddr address, s32 value, u64 nanoseconds); | ||
| 48 | |||
| 49 | private: | ||
| 50 | AddressArbiter() = default; | ||
| 51 | }; | ||
| 35 | 52 | ||
| 36 | } // namespace FileSys | 53 | } // 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 @@ | |||
| 14 | 14 | ||
| 15 | namespace Kernel { | 15 | namespace Kernel { |
| 16 | 16 | ||
| 17 | class Event : public WaitObject { | 17 | ResultVal<SharedPtr<Event>> Event::Create(ResetType reset_type, std::string name) { |
| 18 | public: | 18 | SharedPtr<Event> evt(new Event); |
| 19 | std::string GetTypeName() const override { return "Event"; } | 19 | // TOOD(yuriks): Don't create Handle (see Thread::Create()) |
| 20 | std::string GetName() const override { return name; } | 20 | CASCADE_RESULT(auto unused, Kernel::g_handle_table.Create(evt)); |
| 21 | |||
| 22 | static const HandleType HANDLE_TYPE = HandleType::Event; | ||
| 23 | HandleType GetHandleType() const override { return HANDLE_TYPE; } | ||
| 24 | |||
| 25 | ResetType intitial_reset_type; ///< ResetType specified at Event initialization | ||
| 26 | ResetType reset_type; ///< Current ResetType | ||
| 27 | |||
| 28 | bool signaled; ///< Whether the event has already been signaled | ||
| 29 | std::string name; ///< Name of event (optional) | ||
| 30 | |||
| 31 | bool ShouldWait() override { | ||
| 32 | return !signaled; | ||
| 33 | } | ||
| 34 | |||
| 35 | void Acquire() override { | ||
| 36 | _assert_msg_(Kernel, !ShouldWait(), "object unavailable!"); | ||
| 37 | |||
| 38 | // Release the event if it's not sticky... | ||
| 39 | if (reset_type != RESETTYPE_STICKY) | ||
| 40 | signaled = false; | ||
| 41 | } | ||
| 42 | }; | ||
| 43 | |||
| 44 | ResultCode SignalEvent(const Handle handle) { | ||
| 45 | Event* evt = g_handle_table.Get<Event>(handle).get(); | ||
| 46 | if (evt == nullptr) | ||
| 47 | return InvalidHandle(ErrorModule::Kernel); | ||
| 48 | |||
| 49 | evt->signaled = true; | ||
| 50 | evt->WakeupAllWaitingThreads(); | ||
| 51 | |||
| 52 | return RESULT_SUCCESS; | ||
| 53 | } | ||
| 54 | |||
| 55 | ResultCode ClearEvent(Handle handle) { | ||
| 56 | Event* evt = g_handle_table.Get<Event>(handle).get(); | ||
| 57 | if (evt == nullptr) | ||
| 58 | return InvalidHandle(ErrorModule::Kernel); | ||
| 59 | 21 | ||
| 60 | evt->signaled = false; | 22 | evt->signaled = false; |
| 23 | evt->reset_type = evt->intitial_reset_type = reset_type; | ||
| 24 | evt->name = std::move(name); | ||
| 61 | 25 | ||
| 62 | return RESULT_SUCCESS; | 26 | return MakeResult<SharedPtr<Event>>(evt); |
| 63 | } | 27 | } |
| 64 | 28 | ||
| 65 | /** | 29 | bool Event::ShouldWait() { |
| 66 | * Creates an event | 30 | return !signaled; |
| 67 | * @param handle Reference to handle for the newly created mutex | 31 | } |
| 68 | * @param reset_type ResetType describing how to create event | ||
| 69 | * @param name Optional name of event | ||
| 70 | * @return Newly created Event object | ||
| 71 | */ | ||
| 72 | Event* CreateEvent(Handle& handle, const ResetType reset_type, const std::string& name) { | ||
| 73 | Event* evt = new Event; | ||
| 74 | 32 | ||
| 75 | // TOOD(yuriks): Fix error reporting | 33 | void Event::Acquire() { |
| 76 | handle = Kernel::g_handle_table.Create(evt).ValueOr(INVALID_HANDLE); | 34 | _assert_msg_(Kernel, !ShouldWait(), "object unavailable!"); |
| 77 | 35 | ||
| 78 | evt->signaled = false; | 36 | // Release the event if it's not sticky... |
| 79 | evt->reset_type = evt->intitial_reset_type = reset_type; | 37 | if (reset_type != RESETTYPE_STICKY) |
| 80 | evt->name = name; | 38 | signaled = false; |
| 39 | } | ||
| 81 | 40 | ||
| 82 | return evt; | 41 | void Event::Signal() { |
| 42 | signaled = true; | ||
| 43 | WakeupAllWaitingThreads(); | ||
| 83 | } | 44 | } |
| 84 | 45 | ||
| 85 | Handle CreateEvent(const ResetType reset_type, const std::string& name) { | 46 | void Event::Clear() { |
| 86 | Handle handle; | 47 | signaled = false; |
| 87 | Event* evt = CreateEvent(handle, reset_type, name); | ||
| 88 | return handle; | ||
| 89 | } | 48 | } |
| 90 | 49 | ||
| 91 | } // namespace | 50 | } // 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 @@ | |||
| 11 | 11 | ||
| 12 | namespace Kernel { | 12 | namespace Kernel { |
| 13 | 13 | ||
| 14 | /** | 14 | class Event final : public WaitObject { |
| 15 | * Signals an event | 15 | public: |
| 16 | * @param handle Handle to event to signal | 16 | /** |
| 17 | * @return Result of operation, 0 on success, otherwise error code | 17 | * Creates an event |
| 18 | */ | 18 | * @param reset_type ResetType describing how to create event |
| 19 | ResultCode SignalEvent(const Handle handle); | 19 | * @param name Optional name of event |
| 20 | 20 | */ | |
| 21 | /** | 21 | static ResultVal<SharedPtr<Event>> Create(ResetType reset_type, std::string name = "Unknown"); |
| 22 | * Clears an event | 22 | |
| 23 | * @param handle Handle to event to clear | 23 | std::string GetTypeName() const override { return "Event"; } |
| 24 | * @return Result of operation, 0 on success, otherwise error code | 24 | std::string GetName() const override { return name; } |
| 25 | */ | 25 | |
| 26 | ResultCode ClearEvent(Handle handle); | 26 | static const HandleType HANDLE_TYPE = HandleType::Event; |
| 27 | 27 | HandleType GetHandleType() const override { return HANDLE_TYPE; } | |
| 28 | /** | 28 | |
| 29 | * Creates an event | 29 | ResetType intitial_reset_type; ///< ResetType specified at Event initialization |
| 30 | * @param reset_type ResetType describing how to create event | 30 | ResetType reset_type; ///< Current ResetType |
| 31 | * @param name Optional name of event | 31 | |
| 32 | * @return Handle to newly created Event object | 32 | bool signaled; ///< Whether the event has already been signaled |
| 33 | */ | 33 | std::string name; ///< Name of event (optional) |
| 34 | Handle CreateEvent(const ResetType reset_type, const std::string& name="Unknown"); | 34 | |
| 35 | bool ShouldWait() override; | ||
| 36 | void Acquire() override; | ||
| 37 | |||
| 38 | void Signal(); | ||
| 39 | void Clear(); | ||
| 40 | |||
| 41 | private: | ||
| 42 | Event() = default; | ||
| 43 | }; | ||
| 35 | 44 | ||
| 36 | } // namespace | 45 | } // 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 @@ | |||
| 16 | typedef u32 Handle; | 16 | typedef u32 Handle; |
| 17 | typedef s32 Result; | 17 | typedef s32 Result; |
| 18 | 18 | ||
| 19 | // TODO: It would be nice to eventually replace these with strong types that prevent accidental | ||
| 20 | // conversion between each other. | ||
| 21 | typedef u32 VAddr; ///< Represents a pointer in the userspace virtual address space. | ||
| 22 | typedef u32 PAddr; ///< Represents a pointer in the ARM11 physical address space. | ||
| 23 | |||
| 19 | const Handle INVALID_HANDLE = 0; | 24 | const Handle INVALID_HANDLE = 0; |
| 20 | 25 | ||
| 21 | namespace Kernel { | 26 | namespace Kernel { |
| @@ -26,7 +31,8 @@ class Thread; | |||
| 26 | const ResultCode ERR_OUT_OF_HANDLES(ErrorDescription::OutOfMemory, ErrorModule::Kernel, | 31 | const ResultCode ERR_OUT_OF_HANDLES(ErrorDescription::OutOfMemory, ErrorModule::Kernel, |
| 27 | ErrorSummary::OutOfResource, ErrorLevel::Temporary); | 32 | ErrorSummary::OutOfResource, ErrorLevel::Temporary); |
| 28 | // TOOD: Verify code | 33 | // TOOD: Verify code |
| 29 | const ResultCode ERR_INVALID_HANDLE = InvalidHandle(ErrorModule::Kernel); | 34 | const ResultCode ERR_INVALID_HANDLE(ErrorDescription::InvalidHandle, ErrorModule::Kernel, |
| 35 | ErrorSummary::InvalidArgument, ErrorLevel::Permanent); | ||
| 30 | 36 | ||
| 31 | enum KernelHandle : Handle { | 37 | enum KernelHandle : Handle { |
| 32 | CurrentThread = 0xFFFF8000, | 38 | 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 @@ | |||
| 13 | 13 | ||
| 14 | namespace Kernel { | 14 | namespace Kernel { |
| 15 | 15 | ||
| 16 | class Mutex : public WaitObject { | ||
| 17 | public: | ||
| 18 | std::string GetTypeName() const override { return "Mutex"; } | ||
| 19 | std::string GetName() const override { return name; } | ||
| 20 | |||
| 21 | static const HandleType HANDLE_TYPE = HandleType::Mutex; | ||
| 22 | HandleType GetHandleType() const override { return HANDLE_TYPE; } | ||
| 23 | |||
| 24 | bool initial_locked; ///< Initial lock state when mutex was created | ||
| 25 | bool locked; ///< Current locked state | ||
| 26 | std::string name; ///< Name of mutex (optional) | ||
| 27 | SharedPtr<Thread> holding_thread; ///< Thread that has acquired the mutex | ||
| 28 | |||
| 29 | bool ShouldWait() override; | ||
| 30 | void Acquire() override; | ||
| 31 | }; | ||
| 32 | |||
| 33 | //////////////////////////////////////////////////////////////////////////////////////////////////// | ||
| 34 | |||
| 35 | typedef std::multimap<SharedPtr<Thread>, SharedPtr<Mutex>> MutexMap; | 16 | typedef std::multimap<SharedPtr<Thread>, SharedPtr<Mutex>> MutexMap; |
| 36 | static MutexMap g_mutex_held_locks; | 17 | static MutexMap g_mutex_held_locks; |
| 37 | 18 | ||
| 38 | /** | 19 | /** |
| 39 | * Acquires the specified mutex for the specified thread | ||
| 40 | * @param mutex Mutex that is to be acquired | ||
| 41 | * @param thread Thread that will acquire the mutex | ||
| 42 | */ | ||
| 43 | void MutexAcquireLock(Mutex* mutex, Thread* thread) { | ||
| 44 | g_mutex_held_locks.insert(std::make_pair(thread, mutex)); | ||
| 45 | mutex->holding_thread = thread; | ||
| 46 | } | ||
| 47 | |||
| 48 | /** | ||
| 49 | * Resumes a thread waiting for the specified mutex | 20 | * Resumes a thread waiting for the specified mutex |
| 50 | * @param mutex The mutex that some thread is waiting on | 21 | * @param mutex The mutex that some thread is waiting on |
| 51 | */ | 22 | */ |
| 52 | void ResumeWaitingThread(Mutex* mutex) { | 23 | static void ResumeWaitingThread(Mutex* mutex) { |
| 24 | // Reset mutex lock thread handle, nothing is waiting | ||
| 25 | mutex->locked = false; | ||
| 26 | mutex->holding_thread = nullptr; | ||
| 27 | |||
| 53 | // Find the next waiting thread for the mutex... | 28 | // Find the next waiting thread for the mutex... |
| 54 | auto next_thread = mutex->WakeupNextThread(); | 29 | auto next_thread = mutex->WakeupNextThread(); |
| 55 | if (next_thread != nullptr) { | 30 | if (next_thread != nullptr) { |
| 56 | MutexAcquireLock(mutex, next_thread); | 31 | mutex->Acquire(next_thread); |
| 57 | } else { | ||
| 58 | // Reset mutex lock thread handle, nothing is waiting | ||
| 59 | mutex->locked = false; | ||
| 60 | mutex->holding_thread = nullptr; | ||
| 61 | } | 32 | } |
| 62 | } | 33 | } |
| 63 | 34 | ||
| 64 | void ReleaseThreadMutexes(Thread* thread) { | 35 | void ReleaseThreadMutexes(Thread* thread) { |
| 65 | auto locked = g_mutex_held_locks.equal_range(thread); | 36 | auto locked_range = g_mutex_held_locks.equal_range(thread); |
| 66 | 37 | ||
| 67 | // Release every mutex that the thread holds, and resume execution on the waiting threads | 38 | // Release every mutex that the thread holds, and resume execution on the waiting threads |
| 68 | for (auto iter = locked.first; iter != locked.second; ++iter) { | 39 | for (auto iter = locked_range.first; iter != locked_range.second; ++iter) { |
| 69 | ResumeWaitingThread(iter->second.get()); | 40 | ResumeWaitingThread(iter->second.get()); |
| 70 | } | 41 | } |
| 71 | 42 | ||
| @@ -73,72 +44,21 @@ void ReleaseThreadMutexes(Thread* thread) { | |||
| 73 | g_mutex_held_locks.erase(thread); | 44 | g_mutex_held_locks.erase(thread); |
| 74 | } | 45 | } |
| 75 | 46 | ||
| 76 | bool ReleaseMutex(Mutex* mutex) { | 47 | ResultVal<SharedPtr<Mutex>> Mutex::Create(bool initial_locked, std::string name) { |
| 77 | if (mutex->locked) { | 48 | SharedPtr<Mutex> mutex(new Mutex); |
| 78 | auto locked = g_mutex_held_locks.equal_range(mutex->holding_thread); | 49 | // TOOD(yuriks): Don't create Handle (see Thread::Create()) |
| 79 | 50 | CASCADE_RESULT(auto unused, Kernel::g_handle_table.Create(mutex)); | |
| 80 | for (MutexMap::iterator iter = locked.first; iter != locked.second; ++iter) { | ||
| 81 | if (iter->second == mutex) { | ||
| 82 | g_mutex_held_locks.erase(iter); | ||
| 83 | break; | ||
| 84 | } | ||
| 85 | } | ||
| 86 | |||
| 87 | ResumeWaitingThread(mutex); | ||
| 88 | } | ||
| 89 | return true; | ||
| 90 | } | ||
| 91 | 51 | ||
| 92 | /** | 52 | mutex->initial_locked = initial_locked; |
| 93 | * Releases a mutex | 53 | mutex->locked = false; |
| 94 | * @param handle Handle to mutex to release | 54 | mutex->name = std::move(name); |
| 95 | */ | ||
| 96 | ResultCode ReleaseMutex(Handle handle) { | ||
| 97 | Mutex* mutex = Kernel::g_handle_table.Get<Mutex>(handle).get(); | ||
| 98 | if (mutex == nullptr) return InvalidHandle(ErrorModule::Kernel); | ||
| 99 | |||
| 100 | if (!ReleaseMutex(mutex)) { | ||
| 101 | // TODO(yuriks): Verify error code, this one was pulled out of thin air. I'm not even sure | ||
| 102 | // what error condition this is supposed to be signaling. | ||
| 103 | return ResultCode(ErrorDescription::AlreadyDone, ErrorModule::Kernel, | ||
| 104 | ErrorSummary::NothingHappened, ErrorLevel::Temporary); | ||
| 105 | } | ||
| 106 | return RESULT_SUCCESS; | ||
| 107 | } | ||
| 108 | |||
| 109 | /** | ||
| 110 | * Creates a mutex | ||
| 111 | * @param handle Reference to handle for the newly created mutex | ||
| 112 | * @param initial_locked Specifies if the mutex should be locked initially | ||
| 113 | * @param name Optional name of mutex | ||
| 114 | * @return Pointer to new Mutex object | ||
| 115 | */ | ||
| 116 | Mutex* CreateMutex(Handle& handle, bool initial_locked, const std::string& name) { | ||
| 117 | Mutex* mutex = new Mutex; | ||
| 118 | // TODO(yuriks): Fix error reporting | ||
| 119 | handle = Kernel::g_handle_table.Create(mutex).ValueOr(INVALID_HANDLE); | ||
| 120 | |||
| 121 | mutex->locked = mutex->initial_locked = initial_locked; | ||
| 122 | mutex->name = name; | ||
| 123 | mutex->holding_thread = nullptr; | 55 | mutex->holding_thread = nullptr; |
| 124 | 56 | ||
| 125 | // Acquire mutex with current thread if initialized as locked... | 57 | // Acquire mutex with current thread if initialized as locked... |
| 126 | if (mutex->locked) | 58 | if (initial_locked) |
| 127 | MutexAcquireLock(mutex, GetCurrentThread()); | 59 | mutex->Acquire(); |
| 128 | |||
| 129 | return mutex; | ||
| 130 | } | ||
| 131 | 60 | ||
| 132 | /** | 61 | return MakeResult<SharedPtr<Mutex>>(mutex); |
| 133 | * Creates a mutex | ||
| 134 | * @param initial_locked Specifies if the mutex should be locked initially | ||
| 135 | * @param name Optional name of mutex | ||
| 136 | * @return Handle to newly created object | ||
| 137 | */ | ||
| 138 | Handle CreateMutex(bool initial_locked, const std::string& name) { | ||
| 139 | Handle handle; | ||
| 140 | Mutex* mutex = CreateMutex(handle, initial_locked, name); | ||
| 141 | return handle; | ||
| 142 | } | 62 | } |
| 143 | 63 | ||
| 144 | bool Mutex::ShouldWait() { | 64 | bool Mutex::ShouldWait() { |
| @@ -146,9 +66,34 @@ bool Mutex::ShouldWait() { | |||
| 146 | } | 66 | } |
| 147 | 67 | ||
| 148 | void Mutex::Acquire() { | 68 | void Mutex::Acquire() { |
| 69 | Acquire(GetCurrentThread()); | ||
| 70 | } | ||
| 71 | |||
| 72 | void Mutex::Acquire(Thread* thread) { | ||
| 149 | _assert_msg_(Kernel, !ShouldWait(), "object unavailable!"); | 73 | _assert_msg_(Kernel, !ShouldWait(), "object unavailable!"); |
| 74 | if (locked) | ||
| 75 | return; | ||
| 76 | |||
| 150 | locked = true; | 77 | locked = true; |
| 151 | MutexAcquireLock(this, GetCurrentThread()); | 78 | |
| 79 | g_mutex_held_locks.insert(std::make_pair(thread, this)); | ||
| 80 | holding_thread = thread; | ||
| 81 | } | ||
| 82 | |||
| 83 | void Mutex::Release() { | ||
| 84 | if (!locked) | ||
| 85 | return; | ||
| 86 | |||
| 87 | auto locked_range = g_mutex_held_locks.equal_range(holding_thread); | ||
| 88 | |||
| 89 | for (MutexMap::iterator iter = locked_range.first; iter != locked_range.second; ++iter) { | ||
| 90 | if (iter->second == this) { | ||
| 91 | g_mutex_held_locks.erase(iter); | ||
| 92 | break; | ||
| 93 | } | ||
| 94 | } | ||
| 95 | |||
| 96 | ResumeWaitingThread(this); | ||
| 152 | } | 97 | } |
| 153 | 98 | ||
| 154 | } // namespace | 99 | } // 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 @@ | |||
| 4 | 4 | ||
| 5 | #pragma once | 5 | #pragma once |
| 6 | 6 | ||
| 7 | #include <string> | ||
| 8 | |||
| 7 | #include "common/common_types.h" | 9 | #include "common/common_types.h" |
| 8 | 10 | ||
| 9 | #include "core/hle/kernel/kernel.h" | 11 | #include "core/hle/kernel/kernel.h" |
| 10 | 12 | ||
| 11 | namespace Kernel { | 13 | namespace Kernel { |
| 12 | 14 | ||
| 13 | /** | 15 | class Thread; |
| 14 | * Releases a mutex | 16 | |
| 15 | * @param handle Handle to mutex to release | 17 | class Mutex final : public WaitObject { |
| 16 | */ | 18 | public: |
| 17 | ResultCode ReleaseMutex(Handle handle); | 19 | /** |
| 18 | 20 | * Creates a mutex. | |
| 19 | /** | 21 | * @param initial_locked Specifies if the mutex should be locked initially |
| 20 | * Creates a mutex | 22 | * @param name Optional name of mutex |
| 21 | * @param initial_locked Specifies if the mutex should be locked initially | 23 | * @return Pointer to new Mutex object |
| 22 | * @param name Optional name of mutex | 24 | */ |
| 23 | * @return Handle to newly created object | 25 | static ResultVal<SharedPtr<Mutex>> Create(bool initial_locked, std::string name = "Unknown"); |
| 24 | */ | 26 | |
| 25 | Handle CreateMutex(bool initial_locked, const std::string& name="Unknown"); | 27 | std::string GetTypeName() const override { return "Mutex"; } |
| 28 | std::string GetName() const override { return name; } | ||
| 29 | |||
| 30 | static const HandleType HANDLE_TYPE = HandleType::Mutex; | ||
| 31 | HandleType GetHandleType() const override { return HANDLE_TYPE; } | ||
| 32 | |||
| 33 | bool initial_locked; ///< Initial lock state when mutex was created | ||
| 34 | bool locked; ///< Current locked state | ||
| 35 | std::string name; ///< Name of mutex (optional) | ||
| 36 | SharedPtr<Thread> holding_thread; ///< Thread that has acquired the mutex | ||
| 37 | |||
| 38 | bool ShouldWait() override; | ||
| 39 | void Acquire() override; | ||
| 40 | |||
| 41 | /** | ||
| 42 | * Acquires the specified mutex for the specified thread | ||
| 43 | * @param mutex Mutex that is to be acquired | ||
| 44 | * @param thread Thread that will acquire the mutex | ||
| 45 | */ | ||
| 46 | void Acquire(Thread* thread); | ||
| 47 | void Release(); | ||
| 48 | |||
| 49 | private: | ||
| 50 | Mutex() = default; | ||
| 51 | }; | ||
| 26 | 52 | ||
| 27 | /** | 53 | /** |
| 28 | * Releases all the mutexes held by the specified thread | 54 | * 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 @@ | |||
| 2 | // Licensed under GPLv2 or any later version | 2 | // Licensed under GPLv2 or any later version |
| 3 | // Refer to the license.txt file included. | 3 | // Refer to the license.txt file included. |
| 4 | 4 | ||
| 5 | #include <queue> | ||
| 6 | |||
| 7 | #include "common/common.h" | 5 | #include "common/common.h" |
| 8 | 6 | ||
| 9 | #include "core/hle/kernel/kernel.h" | 7 | #include "core/hle/kernel/kernel.h" |
| @@ -12,69 +10,50 @@ | |||
| 12 | 10 | ||
| 13 | namespace Kernel { | 11 | namespace Kernel { |
| 14 | 12 | ||
| 15 | class Semaphore : public WaitObject { | 13 | ResultVal<SharedPtr<Semaphore>> Semaphore::Create(s32 initial_count, s32 max_count, |
| 16 | public: | 14 | std::string name) { |
| 17 | std::string GetTypeName() const override { return "Semaphore"; } | ||
| 18 | std::string GetName() const override { return name; } | ||
| 19 | |||
| 20 | static const HandleType HANDLE_TYPE = HandleType::Semaphore; | ||
| 21 | HandleType GetHandleType() const override { return HANDLE_TYPE; } | ||
| 22 | |||
| 23 | s32 max_count; ///< Maximum number of simultaneous holders the semaphore can have | ||
| 24 | s32 available_count; ///< Number of free slots left in the semaphore | ||
| 25 | std::string name; ///< Name of semaphore (optional) | ||
| 26 | |||
| 27 | bool ShouldWait() override { | ||
| 28 | return available_count <= 0; | ||
| 29 | } | ||
| 30 | |||
| 31 | void Acquire() override { | ||
| 32 | _assert_msg_(Kernel, !ShouldWait(), "object unavailable!"); | ||
| 33 | --available_count; | ||
| 34 | } | ||
| 35 | }; | ||
| 36 | |||
| 37 | //////////////////////////////////////////////////////////////////////////////////////////////////// | ||
| 38 | |||
| 39 | ResultCode CreateSemaphore(Handle* handle, s32 initial_count, | ||
| 40 | s32 max_count, const std::string& name) { | ||
| 41 | 15 | ||
| 42 | if (initial_count > max_count) | 16 | if (initial_count > max_count) |
| 43 | return ResultCode(ErrorDescription::InvalidCombination, ErrorModule::Kernel, | 17 | return ResultCode(ErrorDescription::InvalidCombination, ErrorModule::Kernel, |
| 44 | ErrorSummary::WrongArgument, ErrorLevel::Permanent); | 18 | ErrorSummary::WrongArgument, ErrorLevel::Permanent); |
| 45 | 19 | ||
| 46 | Semaphore* semaphore = new Semaphore; | 20 | SharedPtr<Semaphore> semaphore(new Semaphore); |
| 47 | // TOOD(yuriks): Fix error reporting | 21 | // TOOD(yuriks): Don't create Handle (see Thread::Create()) |
| 48 | *handle = g_handle_table.Create(semaphore).ValueOr(INVALID_HANDLE); | 22 | CASCADE_RESULT(auto unused, Kernel::g_handle_table.Create(semaphore)); |
| 49 | 23 | ||
| 50 | // When the semaphore is created, some slots are reserved for other threads, | 24 | // When the semaphore is created, some slots are reserved for other threads, |
| 51 | // and the rest is reserved for the caller thread | 25 | // and the rest is reserved for the caller thread |
| 52 | semaphore->max_count = max_count; | 26 | semaphore->max_count = max_count; |
| 53 | semaphore->available_count = initial_count; | 27 | semaphore->available_count = initial_count; |
| 54 | semaphore->name = name; | 28 | semaphore->name = std::move(name); |
| 55 | 29 | ||
| 56 | return RESULT_SUCCESS; | 30 | return MakeResult<SharedPtr<Semaphore>>(std::move(semaphore)); |
| 57 | } | 31 | } |
| 58 | 32 | ||
| 59 | ResultCode ReleaseSemaphore(s32* count, Handle handle, s32 release_count) { | 33 | bool Semaphore::ShouldWait() { |
| 60 | Semaphore* semaphore = g_handle_table.Get<Semaphore>(handle).get(); | 34 | return available_count <= 0; |
| 61 | if (semaphore == nullptr) | 35 | } |
| 62 | return InvalidHandle(ErrorModule::Kernel); | 36 | |
| 37 | void Semaphore::Acquire() { | ||
| 38 | _assert_msg_(Kernel, !ShouldWait(), "object unavailable!"); | ||
| 39 | --available_count; | ||
| 40 | } | ||
| 63 | 41 | ||
| 64 | if (semaphore->max_count - semaphore->available_count < release_count) | 42 | ResultVal<s32> Semaphore::Release(s32 release_count) { |
| 43 | if (max_count - available_count < release_count) | ||
| 65 | return ResultCode(ErrorDescription::OutOfRange, ErrorModule::Kernel, | 44 | return ResultCode(ErrorDescription::OutOfRange, ErrorModule::Kernel, |
| 66 | ErrorSummary::InvalidArgument, ErrorLevel::Permanent); | 45 | ErrorSummary::InvalidArgument, ErrorLevel::Permanent); |
| 67 | 46 | ||
| 68 | *count = semaphore->available_count; | 47 | s32 previous_count = available_count; |
| 69 | semaphore->available_count += release_count; | 48 | available_count += release_count; |
| 70 | 49 | ||
| 71 | // Notify some of the threads that the semaphore has been released | 50 | // Notify some of the threads that the semaphore has been released |
| 72 | // stop once the semaphore is full again or there are no more waiting threads | 51 | // stop once the semaphore is full again or there are no more waiting threads |
| 73 | while (!semaphore->ShouldWait() && semaphore->WakeupNextThread() != nullptr) { | 52 | while (!ShouldWait() && WakeupNextThread() != nullptr) { |
| 74 | semaphore->Acquire(); | 53 | Acquire(); |
| 75 | } | 54 | } |
| 76 | 55 | ||
| 77 | return RESULT_SUCCESS; | 56 | return MakeResult<s32>(previous_count); |
| 78 | } | 57 | } |
| 79 | 58 | ||
| 80 | } // namespace | 59 | } // 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 @@ | |||
| 4 | 4 | ||
| 5 | #pragma once | 5 | #pragma once |
| 6 | 6 | ||
| 7 | #include <queue> | ||
| 8 | #include <string> | ||
| 9 | |||
| 7 | #include "common/common_types.h" | 10 | #include "common/common_types.h" |
| 8 | 11 | ||
| 9 | #include "core/hle/kernel/kernel.h" | 12 | #include "core/hle/kernel/kernel.h" |
| 10 | 13 | ||
| 11 | namespace Kernel { | 14 | namespace Kernel { |
| 12 | 15 | ||
| 13 | /** | 16 | class Semaphore final : public WaitObject { |
| 14 | * Creates a semaphore. | 17 | public: |
| 15 | * @param handle Pointer to the handle of the newly created object | 18 | /** |
| 16 | * @param initial_count Number of slots reserved for other threads | 19 | * Creates a semaphore. |
| 17 | * @param max_count Maximum number of slots the semaphore can have | 20 | * @param handle Pointer to the handle of the newly created object |
| 18 | * @param name Optional name of semaphore | 21 | * @param initial_count Number of slots reserved for other threads |
| 19 | * @return ResultCode of the error | 22 | * @param max_count Maximum number of slots the semaphore can have |
| 20 | */ | 23 | * @param name Optional name of semaphore |
| 21 | ResultCode CreateSemaphore(Handle* handle, s32 initial_count, s32 max_count, const std::string& name = "Unknown"); | 24 | * @return The created semaphore |
| 22 | 25 | */ | |
| 23 | /** | 26 | static ResultVal<SharedPtr<Semaphore>> Create(s32 initial_count, s32 max_count, |
| 24 | * Releases a certain number of slots from a semaphore. | 27 | std::string name = "Unknown"); |
| 25 | * @param count The number of free slots the semaphore had before this call | 28 | |
| 26 | * @param handle The handle of the semaphore to release | 29 | std::string GetTypeName() const override { return "Semaphore"; } |
| 27 | * @param release_count The number of slots to release | 30 | std::string GetName() const override { return name; } |
| 28 | * @return ResultCode of the error | 31 | |
| 29 | */ | 32 | static const HandleType HANDLE_TYPE = HandleType::Semaphore; |
| 30 | ResultCode ReleaseSemaphore(s32* count, Handle handle, s32 release_count); | 33 | HandleType GetHandleType() const override { return HANDLE_TYPE; } |
| 34 | |||
| 35 | s32 max_count; ///< Maximum number of simultaneous holders the semaphore can have | ||
| 36 | s32 available_count; ///< Number of free slots left in the semaphore | ||
| 37 | std::string name; ///< Name of semaphore (optional) | ||
| 38 | |||
| 39 | bool ShouldWait() override; | ||
| 40 | void Acquire() override; | ||
| 41 | |||
| 42 | /** | ||
| 43 | * Releases a certain number of slots from a semaphore. | ||
| 44 | * @param release_count The number of slots to release | ||
| 45 | * @return The number of free slots the semaphore had before this call | ||
| 46 | */ | ||
| 47 | ResultVal<s32> Release(s32 release_count); | ||
| 48 | |||
| 49 | private: | ||
| 50 | Semaphore() = default; | ||
| 51 | }; | ||
| 31 | 52 | ||
| 32 | } // namespace | 53 | } // 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 @@ | |||
| 9 | 9 | ||
| 10 | namespace Kernel { | 10 | namespace Kernel { |
| 11 | 11 | ||
| 12 | class SharedMemory : public Object { | 12 | ResultVal<SharedPtr<SharedMemory>> SharedMemory::Create(std::string name) { |
| 13 | public: | 13 | SharedPtr<SharedMemory> shared_memory(new SharedMemory); |
| 14 | std::string GetTypeName() const override { return "SharedMemory"; } | ||
| 15 | 14 | ||
| 16 | static const HandleType HANDLE_TYPE = HandleType::SharedMemory; | 15 | // TOOD(yuriks): Don't create Handle (see Thread::Create()) |
| 17 | HandleType GetHandleType() const override { return HANDLE_TYPE; } | 16 | CASCADE_RESULT(auto unused, Kernel::g_handle_table.Create(shared_memory)); |
| 18 | 17 | ||
| 19 | u32 base_address; ///< Address of shared memory block in RAM | 18 | shared_memory->name = std::move(name); |
| 20 | MemoryPermission permissions; ///< Permissions of shared memory block (SVC field) | 19 | return MakeResult<SharedPtr<SharedMemory>>(std::move(shared_memory)); |
| 21 | MemoryPermission other_permissions; ///< Other permissions of shared memory block (SVC field) | ||
| 22 | std::string name; ///< Name of shared memory object (optional) | ||
| 23 | }; | ||
| 24 | |||
| 25 | //////////////////////////////////////////////////////////////////////////////////////////////////// | ||
| 26 | |||
| 27 | /** | ||
| 28 | * Creates a shared memory object | ||
| 29 | * @param handle Handle of newly created shared memory object | ||
| 30 | * @param name Name of shared memory object | ||
| 31 | * @return Pointer to newly created shared memory object | ||
| 32 | */ | ||
| 33 | SharedMemory* CreateSharedMemory(Handle& handle, const std::string& name) { | ||
| 34 | SharedMemory* shared_memory = new SharedMemory; | ||
| 35 | // TOOD(yuriks): Fix error reporting | ||
| 36 | handle = Kernel::g_handle_table.Create(shared_memory).ValueOr(INVALID_HANDLE); | ||
| 37 | shared_memory->name = name; | ||
| 38 | return shared_memory; | ||
| 39 | } | 20 | } |
| 40 | 21 | ||
| 41 | Handle CreateSharedMemory(const std::string& name) { | 22 | ResultCode SharedMemory::Map(VAddr address, MemoryPermission permissions, |
| 42 | Handle handle; | 23 | MemoryPermission other_permissions) { |
| 43 | CreateSharedMemory(handle, name); | ||
| 44 | return handle; | ||
| 45 | } | ||
| 46 | |||
| 47 | /** | ||
| 48 | * Maps a shared memory block to an address in system memory | ||
| 49 | * @param handle Shared memory block handle | ||
| 50 | * @param address Address in system memory to map shared memory block to | ||
| 51 | * @param permissions Memory block map permissions (specified by SVC field) | ||
| 52 | * @param other_permissions Memory block map other permissions (specified by SVC field) | ||
| 53 | * @return Result of operation, 0 on success, otherwise error code | ||
| 54 | */ | ||
| 55 | ResultCode MapSharedMemory(u32 handle, u32 address, MemoryPermission permissions, | ||
| 56 | MemoryPermission other_permissions) { | ||
| 57 | 24 | ||
| 58 | if (address < Memory::SHARED_MEMORY_VADDR || address >= Memory::SHARED_MEMORY_VADDR_END) { | 25 | if (address < Memory::SHARED_MEMORY_VADDR || address >= Memory::SHARED_MEMORY_VADDR_END) { |
| 59 | LOG_ERROR(Kernel_SVC, "cannot map handle=0x%08X, address=0x%08X outside of shared mem bounds!", | 26 | LOG_ERROR(Kernel, "cannot map handle=0x%08X, address=0x%08X outside of shared mem bounds!", |
| 60 | handle, address); | 27 | GetHandle(), address); |
| 28 | // TODO: Verify error code with hardware | ||
| 61 | return ResultCode(ErrorDescription::InvalidAddress, ErrorModule::Kernel, | 29 | return ResultCode(ErrorDescription::InvalidAddress, ErrorModule::Kernel, |
| 62 | ErrorSummary::InvalidArgument, ErrorLevel::Permanent); | 30 | ErrorSummary::InvalidArgument, ErrorLevel::Permanent); |
| 63 | } | 31 | } |
| 64 | SharedMemory* shared_memory = Kernel::g_handle_table.Get<SharedMemory>(handle).get(); | ||
| 65 | if (shared_memory == nullptr) return InvalidHandle(ErrorModule::Kernel); | ||
| 66 | 32 | ||
| 67 | shared_memory->base_address = address; | 33 | base_address = address; |
| 68 | shared_memory->permissions = permissions; | 34 | permissions = permissions; |
| 69 | shared_memory->other_permissions = other_permissions; | 35 | other_permissions = other_permissions; |
| 70 | 36 | ||
| 71 | return RESULT_SUCCESS; | 37 | return RESULT_SUCCESS; |
| 72 | } | 38 | } |
| 73 | 39 | ||
| 74 | ResultVal<u8*> GetSharedMemoryPointer(Handle handle, u32 offset) { | 40 | ResultVal<u8*> SharedMemory::GetPointer(u32 offset) { |
| 75 | SharedMemory* shared_memory = Kernel::g_handle_table.Get<SharedMemory>(handle).get(); | 41 | if (base_address != 0) |
| 76 | if (shared_memory == nullptr) return InvalidHandle(ErrorModule::Kernel); | 42 | return MakeResult<u8*>(Memory::GetPointer(base_address + offset)); |
| 77 | |||
| 78 | if (0 != shared_memory->base_address) | ||
| 79 | return MakeResult<u8*>(Memory::GetPointer(shared_memory->base_address + offset)); | ||
| 80 | 43 | ||
| 81 | LOG_ERROR(Kernel_SVC, "memory block handle=0x%08X not mapped!", handle); | 44 | LOG_ERROR(Kernel_SVC, "memory block handle=0x%08X not mapped!", GetHandle()); |
| 82 | // TODO(yuriks): Verify error code. | 45 | // TODO(yuriks): Verify error code. |
| 83 | return ResultCode(ErrorDescription::InvalidAddress, ErrorModule::Kernel, | 46 | return ResultCode(ErrorDescription::InvalidAddress, ErrorModule::Kernel, |
| 84 | ErrorSummary::InvalidState, ErrorLevel::Permanent); | 47 | 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 { | |||
| 23 | DontCare = (1u << 28) | 23 | DontCare = (1u << 28) |
| 24 | }; | 24 | }; |
| 25 | 25 | ||
| 26 | /** | 26 | class SharedMemory final : public Object { |
| 27 | * Creates a shared memory object | 27 | public: |
| 28 | * @param name Optional name of shared memory object | 28 | /** |
| 29 | * @return Handle of newly created shared memory object | 29 | * Creates a shared memory object |
| 30 | */ | 30 | * @param name Optional object name, used only for debugging purposes. |
| 31 | Handle CreateSharedMemory(const std::string& name="Unknown"); | 31 | */ |
| 32 | 32 | static ResultVal<SharedPtr<SharedMemory>> Create(std::string name = "Unknown"); | |
| 33 | /** | 33 | |
| 34 | * Maps a shared memory block to an address in system memory | 34 | std::string GetTypeName() const override { return "SharedMemory"; } |
| 35 | * @param handle Shared memory block handle | 35 | |
| 36 | * @param address Address in system memory to map shared memory block to | 36 | static const HandleType HANDLE_TYPE = HandleType::SharedMemory; |
| 37 | * @param permissions Memory block map permissions (specified by SVC field) | 37 | HandleType GetHandleType() const override { return HANDLE_TYPE; } |
| 38 | * @param other_permissions Memory block map other permissions (specified by SVC field) | 38 | |
| 39 | */ | 39 | /** |
| 40 | ResultCode MapSharedMemory(Handle handle, u32 address, MemoryPermission permissions, | 40 | * Maps a shared memory block to an address in system memory |
| 41 | MemoryPermission other_permissions); | 41 | * @param address Address in system memory to map shared memory block to |
| 42 | 42 | * @param permissions Memory block map permissions (specified by SVC field) | |
| 43 | /** | 43 | * @param other_permissions Memory block map other permissions (specified by SVC field) |
| 44 | * Gets a pointer to the shared memory block | 44 | */ |
| 45 | * @param handle Shared memory block handle | 45 | ResultCode Map(VAddr address, MemoryPermission permissions, MemoryPermission other_permissions); |
| 46 | * @param offset Offset from the start of the shared memory block to get pointer | 46 | |
| 47 | * @return Pointer to the shared memory block from the specified offset | 47 | /** |
| 48 | */ | 48 | * Gets a pointer to the shared memory block |
| 49 | ResultVal<u8*> GetSharedMemoryPointer(Handle handle, u32 offset); | 49 | * @param offset Offset from the start of the shared memory block to get pointer |
| 50 | * @return Pointer to the shared memory block from the specified offset | ||
| 51 | */ | ||
| 52 | ResultVal<u8*> GetPointer(u32 offset = 0); | ||
| 53 | |||
| 54 | VAddr base_address; ///< Address of shared memory block in RAM | ||
| 55 | MemoryPermission permissions; ///< Permissions of shared memory block (SVC field) | ||
| 56 | MemoryPermission other_permissions; ///< Other permissions of shared memory block (SVC field) | ||
| 57 | std::string name; ///< Name of shared memory object (optional) | ||
| 58 | |||
| 59 | private: | ||
| 60 | SharedMemory() = default; | ||
| 61 | }; | ||
| 50 | 62 | ||
| 51 | } // namespace | 63 | } // 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 { | |||
| 40 | 40 | ||
| 41 | namespace Kernel { | 41 | namespace Kernel { |
| 42 | 42 | ||
| 43 | class Thread : public WaitObject { | 43 | class Thread final : public WaitObject { |
| 44 | public: | 44 | public: |
| 45 | static ResultVal<SharedPtr<Thread>> Create(std::string name, VAddr entry_point, s32 priority, | 45 | static ResultVal<SharedPtr<Thread>> Create(std::string name, VAddr entry_point, s32 priority, |
| 46 | u32 arg, s32 processor_id, VAddr stack_top, u32 stack_size); | 46 | u32 arg, s32 processor_id, VAddr stack_top, u32 stack_size); |
| @@ -115,7 +115,6 @@ public: | |||
| 115 | bool idle = false; | 115 | bool idle = false; |
| 116 | 116 | ||
| 117 | private: | 117 | private: |
| 118 | |||
| 119 | Thread() = default; | 118 | Thread() = default; |
| 120 | }; | 119 | }; |
| 121 | 120 | ||
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 @@ | |||
| 13 | 13 | ||
| 14 | namespace Kernel { | 14 | namespace Kernel { |
| 15 | 15 | ||
| 16 | class Timer : public WaitObject { | 16 | /// The event type of the generic timer callback event |
| 17 | public: | 17 | static int timer_callback_event_type = -1; |
| 18 | std::string GetTypeName() const override { return "Timer"; } | ||
| 19 | std::string GetName() const override { return name; } | ||
| 20 | |||
| 21 | static const HandleType HANDLE_TYPE = HandleType::Timer; | ||
| 22 | HandleType GetHandleType() const override { return HANDLE_TYPE; } | ||
| 23 | |||
| 24 | ResetType reset_type; ///< The ResetType of this timer | ||
| 25 | |||
| 26 | bool signaled; ///< Whether the timer has been signaled or not | ||
| 27 | std::string name; ///< Name of timer (optional) | ||
| 28 | |||
| 29 | u64 initial_delay; ///< The delay until the timer fires for the first time | ||
| 30 | u64 interval_delay; ///< The delay until the timer fires after the first time | ||
| 31 | |||
| 32 | bool ShouldWait() override { | ||
| 33 | return !signaled; | ||
| 34 | } | ||
| 35 | |||
| 36 | void Acquire() override { | ||
| 37 | _assert_msg_(Kernel, !ShouldWait(), "object unavailable!"); | ||
| 38 | } | ||
| 39 | }; | ||
| 40 | |||
| 41 | /** | ||
| 42 | * Creates a timer. | ||
| 43 | * @param handle Reference to handle for the newly created timer | ||
| 44 | * @param reset_type ResetType describing how to create timer | ||
| 45 | * @param name Optional name of timer | ||
| 46 | * @return Newly created Timer object | ||
| 47 | */ | ||
| 48 | Timer* CreateTimer(Handle& handle, const ResetType reset_type, const std::string& name) { | ||
| 49 | Timer* timer = new Timer; | ||
| 50 | 18 | ||
| 51 | handle = Kernel::g_handle_table.Create(timer).ValueOr(INVALID_HANDLE); | 19 | ResultVal<SharedPtr<Timer>> Timer::Create(ResetType reset_type, std::string name) { |
| 20 | SharedPtr<Timer> timer(new Timer); | ||
| 21 | // TOOD(yuriks): Don't create Handle (see Thread::Create()) | ||
| 22 | CASCADE_RESULT(auto unused, Kernel::g_handle_table.Create(timer)); | ||
| 52 | 23 | ||
| 53 | timer->reset_type = reset_type; | 24 | timer->reset_type = reset_type; |
| 54 | timer->signaled = false; | 25 | timer->signaled = false; |
| 55 | timer->name = name; | 26 | timer->name = std::move(name); |
| 56 | timer->initial_delay = 0; | 27 | timer->initial_delay = 0; |
| 57 | timer->interval_delay = 0; | 28 | timer->interval_delay = 0; |
| 58 | return timer; | 29 | return MakeResult<SharedPtr<Timer>>(timer); |
| 59 | } | 30 | } |
| 60 | 31 | ||
| 61 | ResultCode CreateTimer(Handle* handle, const ResetType reset_type, const std::string& name) { | 32 | bool Timer::ShouldWait() { |
| 62 | CreateTimer(*handle, reset_type, name); | 33 | return !signaled; |
| 63 | return RESULT_SUCCESS; | ||
| 64 | } | 34 | } |
| 65 | 35 | ||
| 66 | ResultCode ClearTimer(Handle handle) { | 36 | void Timer::Acquire() { |
| 67 | SharedPtr<Timer> timer = Kernel::g_handle_table.Get<Timer>(handle); | 37 | _assert_msg_(Kernel, !ShouldWait(), "object unavailable!"); |
| 68 | 38 | } | |
| 69 | if (timer == nullptr) | ||
| 70 | return InvalidHandle(ErrorModule::Kernel); | ||
| 71 | 39 | ||
| 72 | timer->signaled = false; | 40 | void Timer::Set(s64 initial, s64 interval) { |
| 73 | return RESULT_SUCCESS; | 41 | initial_delay = initial; |
| 42 | interval_delay = interval; | ||
| 43 | |||
| 44 | u64 initial_microseconds = initial / 1000; | ||
| 45 | // TODO(yuriks): Figure out a replacement for GetHandle here | ||
| 46 | CoreTiming::ScheduleEvent(usToCycles(initial_microseconds), timer_callback_event_type, | ||
| 47 | GetHandle()); | ||
| 74 | } | 48 | } |
| 75 | 49 | ||
| 76 | /// The event type of the generic timer callback event | 50 | void Timer::Cancel() { |
| 77 | static int TimerCallbackEventType = -1; | 51 | CoreTiming::UnscheduleEvent(timer_callback_event_type, GetHandle()); |
| 52 | } | ||
| 53 | |||
| 54 | void Timer::Clear() { | ||
| 55 | signaled = false; | ||
| 56 | } | ||
| 78 | 57 | ||
| 79 | /// The timer callback event, called when a timer is fired | 58 | /// The timer callback event, called when a timer is fired |
| 80 | static void TimerCallback(u64 timer_handle, int cycles_late) { | 59 | static void TimerCallback(u64 timer_handle, int cycles_late) { |
| 81 | SharedPtr<Timer> timer = Kernel::g_handle_table.Get<Timer>(timer_handle); | 60 | SharedPtr<Timer> timer = Kernel::g_handle_table.Get<Timer>(timer_handle); |
| 82 | 61 | ||
| 83 | if (timer == nullptr) { | 62 | if (timer == nullptr) { |
| 84 | LOG_CRITICAL(Kernel, "Callback fired for invalid timer %u", timer_handle); | 63 | LOG_CRITICAL(Kernel, "Callback fired for invalid timer %08X", timer_handle); |
| 85 | return; | 64 | return; |
| 86 | } | 65 | } |
| 87 | 66 | ||
| @@ -99,36 +78,12 @@ static void TimerCallback(u64 timer_handle, int cycles_late) { | |||
| 99 | // Reschedule the timer with the interval delay | 78 | // Reschedule the timer with the interval delay |
| 100 | u64 interval_microseconds = timer->interval_delay / 1000; | 79 | u64 interval_microseconds = timer->interval_delay / 1000; |
| 101 | CoreTiming::ScheduleEvent(usToCycles(interval_microseconds) - cycles_late, | 80 | CoreTiming::ScheduleEvent(usToCycles(interval_microseconds) - cycles_late, |
| 102 | TimerCallbackEventType, timer_handle); | 81 | timer_callback_event_type, timer_handle); |
| 103 | } | 82 | } |
| 104 | } | 83 | } |
| 105 | 84 | ||
| 106 | ResultCode SetTimer(Handle handle, s64 initial, s64 interval) { | ||
| 107 | SharedPtr<Timer> timer = Kernel::g_handle_table.Get<Timer>(handle); | ||
| 108 | |||
| 109 | if (timer == nullptr) | ||
| 110 | return InvalidHandle(ErrorModule::Kernel); | ||
| 111 | |||
| 112 | timer->initial_delay = initial; | ||
| 113 | timer->interval_delay = interval; | ||
| 114 | |||
| 115 | u64 initial_microseconds = initial / 1000; | ||
| 116 | CoreTiming::ScheduleEvent(usToCycles(initial_microseconds), TimerCallbackEventType, handle); | ||
| 117 | return RESULT_SUCCESS; | ||
| 118 | } | ||
| 119 | |||
| 120 | ResultCode CancelTimer(Handle handle) { | ||
| 121 | SharedPtr<Timer> timer = Kernel::g_handle_table.Get<Timer>(handle); | ||
| 122 | |||
| 123 | if (timer == nullptr) | ||
| 124 | return InvalidHandle(ErrorModule::Kernel); | ||
| 125 | |||
| 126 | CoreTiming::UnscheduleEvent(TimerCallbackEventType, handle); | ||
| 127 | return RESULT_SUCCESS; | ||
| 128 | } | ||
| 129 | |||
| 130 | void TimersInit() { | 85 | void TimersInit() { |
| 131 | TimerCallbackEventType = CoreTiming::RegisterEvent("TimerCallback", TimerCallback); | 86 | timer_callback_event_type = CoreTiming::RegisterEvent("TimerCallback", TimerCallback); |
| 132 | } | 87 | } |
| 133 | 88 | ||
| 134 | void TimersShutdown() { | 89 | 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 @@ | |||
| 11 | 11 | ||
| 12 | namespace Kernel { | 12 | namespace Kernel { |
| 13 | 13 | ||
| 14 | /** | 14 | class Timer final : public WaitObject { |
| 15 | * Cancels a timer | 15 | public: |
| 16 | * @param handle Handle of the timer to cancel | 16 | /** |
| 17 | */ | 17 | * Creates a timer |
| 18 | ResultCode CancelTimer(Handle handle); | 18 | * @param reset_type ResetType describing how to create the timer |
| 19 | 19 | * @param name Optional name of timer | |
| 20 | /** | 20 | * @return The created Timer |
| 21 | * Starts a timer with the specified initial delay and interval | 21 | */ |
| 22 | * @param handle Handle of the timer to start | 22 | static ResultVal<SharedPtr<Timer>> Create(ResetType reset_type, std::string name = "Unknown"); |
| 23 | * @param initial Delay until the timer is first fired | 23 | |
| 24 | * @param interval Delay until the timer is fired after the first time | 24 | std::string GetTypeName() const override { return "Timer"; } |
| 25 | */ | 25 | std::string GetName() const override { return name; } |
| 26 | ResultCode SetTimer(Handle handle, s64 initial, s64 interval); | 26 | |
| 27 | 27 | static const HandleType HANDLE_TYPE = HandleType::Timer; | |
| 28 | /** | 28 | HandleType GetHandleType() const override { return HANDLE_TYPE; } |
| 29 | * Clears a timer | 29 | |
| 30 | * @param handle Handle of the timer to clear | 30 | ResetType reset_type; ///< The ResetType of this timer |
| 31 | */ | 31 | |
| 32 | ResultCode ClearTimer(Handle handle); | 32 | bool signaled; ///< Whether the timer has been signaled or not |
| 33 | 33 | std::string name; ///< Name of timer (optional) | |
| 34 | /** | 34 | |
| 35 | * Creates a timer | 35 | u64 initial_delay; ///< The delay until the timer fires for the first time |
| 36 | * @param handle Handle to the newly created Timer object | 36 | u64 interval_delay; ///< The delay until the timer fires after the first time |
| 37 | * @param reset_type ResetType describing how to create the timer | 37 | |
| 38 | * @param name Optional name of timer | 38 | bool ShouldWait() override; |
| 39 | * @return ResultCode of the error | 39 | void Acquire() override; |
| 40 | */ | 40 | |
| 41 | ResultCode CreateTimer(Handle* handle, const ResetType reset_type, const std::string& name="Unknown"); | 41 | /** |
| 42 | * Starts the timer, with the specified initial delay and interval. | ||
| 43 | * @param initial Delay until the timer is first fired | ||
| 44 | * @param interval Delay until the timer is fired after the first time | ||
| 45 | */ | ||
| 46 | void Set(s64 initial, s64 interval); | ||
| 47 | |||
| 48 | void Cancel(); | ||
| 49 | void Clear(); | ||
| 50 | |||
| 51 | private: | ||
| 52 | Timer() = default; | ||
| 53 | }; | ||
| 42 | 54 | ||
| 43 | /// Initializes the required variables for timers | 55 | /// Initializes the required variables for timers |
| 44 | void TimersInit(); | 56 | void TimersInit(); |
| 45 | /// Tears down the timer variables | 57 | /// Tears down the timer variables |
| 46 | void TimersShutdown(); | 58 | void TimersShutdown(); |
| 59 | |||
| 47 | } // namespace | 60 | } // namespace |