diff --git a/include/stratosphere/dd.hpp b/include/stratosphere/dd.hpp
index 8d8c9bbe..d82cd874 100644
--- a/include/stratosphere/dd.hpp
+++ b/include/stratosphere/dd.hpp
@@ -17,3 +17,4 @@
#pragma once
#include "dd/dd_io_mappings.hpp"
+#include "dd/dd_process_handle.hpp"
diff --git a/include/stratosphere/dd/dd_io_mappings.hpp b/include/stratosphere/dd/dd_io_mappings.hpp
index 4105751d..22f3db41 100644
--- a/include/stratosphere/dd/dd_io_mappings.hpp
+++ b/include/stratosphere/dd/dd_io_mappings.hpp
@@ -32,4 +32,5 @@ namespace ams::dd {
AMS_ASSERT(io_mapping);
return io_mapping;
}
+
}
diff --git a/include/stratosphere/dd/dd_process_handle.hpp b/include/stratosphere/dd/dd_process_handle.hpp
new file mode 100644
index 00000000..a3e7f8c0
--- /dev/null
+++ b/include/stratosphere/dd/dd_process_handle.hpp
@@ -0,0 +1,24 @@
+/*
+ * Copyright (c) 2018-2019 Atmosphère-NX
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms and conditions of the GNU General Public License,
+ * version 2, as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see .
+ */
+
+#pragma once
+#include
+
+namespace ams::dd {
+
+ ::Handle GetCurrentProcessHandle();
+
+}
diff --git a/include/stratosphere/os.hpp b/include/stratosphere/os.hpp
index 04664b12..d899759b 100644
--- a/include/stratosphere/os.hpp
+++ b/include/stratosphere/os.hpp
@@ -18,8 +18,10 @@
#include "os/os_common_types.hpp"
#include "os/os_managed_handle.hpp"
+#include "os/os_process_handle.hpp"
#include "os/os_mutex.hpp"
#include "os/os_condvar.hpp"
+#include "os/os_rw_lock.hpp"
#include "os/os_semaphore.hpp"
#include "os/os_timeout_helper.hpp"
#include "os/os_event.hpp"
diff --git a/include/stratosphere/os/os_common_types.hpp b/include/stratosphere/os/os_common_types.hpp
index f88c3ba1..dc10018a 100644
--- a/include/stratosphere/os/os_common_types.hpp
+++ b/include/stratosphere/os/os_common_types.hpp
@@ -54,10 +54,6 @@ namespace ams::os {
return process_id;
}
- NX_INLINE ProcessId GetCurrentProcessId() {
- return GetProcessId(CUR_PROCESS_HANDLE);
- }
-
inline constexpr bool operator==(const ProcessId &lhs, const ProcessId &rhs) {
return lhs.value == rhs.value;
}
diff --git a/include/stratosphere/os/os_condvar.hpp b/include/stratosphere/os/os_condvar.hpp
index 4e00ade0..26b18bf5 100644
--- a/include/stratosphere/os/os_condvar.hpp
+++ b/include/stratosphere/os/os_condvar.hpp
@@ -19,6 +19,11 @@
namespace ams::os {
+ enum class ConditionVariableStatus {
+ TimedOut = 0,
+ Success = 1,
+ };
+
class ConditionVariable {
NON_COPYABLE(ConditionVariable);
NON_MOVEABLE(ConditionVariable);
@@ -29,40 +34,36 @@ namespace ams::os {
condvarInit(&cv);
}
- Result TimedWait(::Mutex *m, u64 timeout) {
- return condvarWaitTimeout(&cv, m, timeout);
+ ConditionVariableStatus TimedWait(::Mutex *m, u64 timeout) {
+ if (timeout > 0) {
+ /* Abort on any error other than timed out/success. */
+ R_TRY_CATCH(condvarWaitTimeout(&this->cv, m, timeout)) {
+ R_CATCH(svc::ResultTimedOut) { return ConditionVariableStatus::TimedOut; }
+ } R_END_TRY_CATCH_WITH_ASSERT;
+
+ return ConditionVariableStatus::Success;
+ }
+ return ConditionVariableStatus::TimedOut;
}
- Result Wait(::Mutex *m) {
- return condvarWait(&cv, m);
+ void Wait(::Mutex *m) {
+ R_ASSERT(condvarWait(&this->cv, m));
}
- Result TimedWait(os::Mutex *m, u64 timeout) {
- return TimedWait(m->GetMutex(), timeout);
+ ConditionVariableStatus TimedWait(os::Mutex *m, u64 timeout) {
+ return this->TimedWait(m->GetMutex(), timeout);
}
- Result Wait(os::Mutex *m) {
- return Wait(m->GetMutex());
+ void Wait(os::Mutex *m) {
+ return this->Wait(m->GetMutex());
}
- Result Wake(int num) {
- return condvarWake(&cv, num);
+ void Signal() {
+ condvarWakeOne(&this->cv);
}
- Result WakeOne() {
- return condvarWakeOne(&cv);
- }
-
- Result WakeAll() {
- return condvarWakeAll(&cv);
- }
-
- Result Signal() {
- return this->WakeOne();
- }
-
- Result Broadcast() {
- return this->WakeAll();
+ void Broadcast() {
+ condvarWakeAll(&this->cv);
}
};
diff --git a/include/stratosphere/os/os_message_queue.hpp b/include/stratosphere/os/os_message_queue.hpp
index 5c24bf5e..ab0733e3 100644
--- a/include/stratosphere/os/os_message_queue.hpp
+++ b/include/stratosphere/os/os_message_queue.hpp
@@ -35,21 +35,22 @@ namespace ams::os {
NON_COPYABLE(MessageQueue);
NON_MOVEABLE(MessageQueue);
private:
- util::TypedStorage waitable_object_list_storage;
+ util::TypedStorage waitlist_not_empty;
+ util::TypedStorage waitlist_not_full;
Mutex queue_lock;
ConditionVariable cv_not_full;
ConditionVariable cv_not_empty;
std::unique_ptr buffer;
size_t capacity;
- size_t count = 0;
- size_t offset = 0;
+ size_t count;
+ size_t offset;
private:
- bool IsFull() const {
+ constexpr inline bool IsFull() const {
return this->count >= this->capacity;
}
- bool IsEmpty() const {
+ constexpr inline bool IsEmpty() const {
return this->count == 0;
}
diff --git a/include/stratosphere/os/os_process_handle.hpp b/include/stratosphere/os/os_process_handle.hpp
new file mode 100644
index 00000000..1b5eac0a
--- /dev/null
+++ b/include/stratosphere/os/os_process_handle.hpp
@@ -0,0 +1,28 @@
+/*
+ * Copyright (c) 2018-2019 Atmosphère-NX
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms and conditions of the GNU General Public License,
+ * version 2, as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see .
+ */
+
+#pragma once
+#include "os_managed_handle.hpp"
+
+namespace ams::os {
+
+ ::Handle GetCurrentProcessHandle();
+
+ NX_INLINE ProcessId GetCurrentProcessId() {
+ return GetProcessId(GetCurrentProcessHandle());
+ }
+
+}
diff --git a/include/stratosphere/os/os_rw_lock.hpp b/include/stratosphere/os/os_rw_lock.hpp
new file mode 100644
index 00000000..674d056e
--- /dev/null
+++ b/include/stratosphere/os/os_rw_lock.hpp
@@ -0,0 +1,89 @@
+/*
+ * Copyright (c) 2018-2019 Atmosphère-NX
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms and conditions of the GNU General Public License,
+ * version 2, as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see .
+ */
+
+#pragma once
+#include "os_common_types.hpp"
+
+namespace ams::os {
+
+ class ReadWriteLock {
+ NON_COPYABLE(ReadWriteLock);
+ NON_MOVEABLE(ReadWriteLock);
+ private:
+ ::RwLock r;
+ public:
+ ReadWriteLock() {
+ rwlockInit(&this->r);
+ }
+
+ bool IsWriteLockHeldByCurrentThread() const {
+ return rwlockIsWriteLockHeldByCurrentThread(const_cast<::RwLock *>(&this->r));
+ }
+
+ bool IsLockOwner() const {
+ return rwlockIsOwnedByCurrentThread(const_cast<::RwLock *>(&this->r));
+ }
+
+ void AcquireReadLock() {
+ rwlockReadLock(&this->r);
+ }
+
+ void ReleaseReadLock() {
+ rwlockReadUnlock(&this->r);
+ }
+
+ bool TryAcquireReadLock() {
+ return rwlockTryReadLock(&this->r);
+ }
+
+ void AcquireWriteLock() {
+ rwlockWriteLock(&this->r);
+ }
+
+ void ReleaseWriteLock() {
+ rwlockWriteUnlock(&this->r);
+ }
+
+ bool TryAcquireWriteLock() {
+ return rwlockTryWriteLock(&this->r);
+ }
+
+ void lock_shared() {
+ this->AcquireReadLock();
+ }
+
+ void unlock_shared() {
+ this->ReleaseReadLock();
+ }
+
+ bool try_lock_shared() {
+ return this->TryAcquireReadLock();
+ }
+
+ void lock() {
+ this->AcquireWriteLock();
+ }
+
+ void unlock() {
+ this->ReleaseWriteLock();
+ }
+
+ bool try_lock() {
+ return this->TryAcquireWriteLock();
+ }
+ };
+
+}
\ No newline at end of file
diff --git a/include/stratosphere/os/os_timeout_helper.hpp b/include/stratosphere/os/os_timeout_helper.hpp
index 650a3e3e..5f5bf408 100644
--- a/include/stratosphere/os/os_timeout_helper.hpp
+++ b/include/stratosphere/os/os_timeout_helper.hpp
@@ -41,7 +41,7 @@ namespace ams::os {
return (tick * 625) / 12;
}
- bool TimedOut() const {
+ inline bool TimedOut() const {
if (this->end_tick == 0) {
return true;
}
@@ -49,7 +49,7 @@ namespace ams::os {
return armGetSystemTick() >= this->end_tick;
}
- u64 NsUntilTimeout() const {
+ inline u64 NsUntilTimeout() const {
u64 diff = TickToNs(this->end_tick - armGetSystemTick());
if (this->TimedOut()) {
diff --git a/source/map/map_api.cpp b/source/map/map_api.cpp
index ca239272..1e8614d8 100644
--- a/source/map/map_api.cpp
+++ b/source/map/map_api.cpp
@@ -31,7 +31,7 @@ namespace ams::map {
uintptr_t cur_base = 0;
AddressSpaceInfo address_space;
- R_TRY(GetProcessAddressSpaceInfo(&address_space, CUR_PROCESS_HANDLE));
+ R_TRY(GetProcessAddressSpaceInfo(&address_space, dd::GetCurrentProcessHandle()));
cur_base = address_space.aslr_base;
do {
@@ -57,7 +57,7 @@ namespace ams::map {
uintptr_t cur_base = 0, cur_end = 0;
AddressSpaceInfo address_space;
- R_TRY(GetProcessAddressSpaceInfo(&address_space, CUR_PROCESS_HANDLE));
+ R_TRY(GetProcessAddressSpaceInfo(&address_space, dd::GetCurrentProcessHandle()));
cur_base = address_space.aslr_base;
cur_end = cur_base + size;
diff --git a/source/os/impl/os_waitable_holder_of_message_queue.hpp b/source/os/impl/os_waitable_holder_of_message_queue.hpp
index ff5aefa6..cba2b099 100644
--- a/source/os/impl/os_waitable_holder_of_message_queue.hpp
+++ b/source/os/impl/os_waitable_holder_of_message_queue.hpp
@@ -25,13 +25,25 @@ namespace ams::os::impl {
private:
MessageQueue *message_queue;
private:
- TriBool IsSignaledImpl() const {
+ constexpr inline TriBool IsSignaledImpl() const {
if constexpr (WaitKind == MessageQueueWaitKind::ForNotEmpty) {
/* ForNotEmpty. */
return this->message_queue->IsEmpty() ? TriBool::False : TriBool::True;
- } else /* if constexpr (WaitKind == MessageQueueWaitKind::ForNotFull) */ {
+ } else if constexpr (WaitKind == MessageQueueWaitKind::ForNotFull) {
/* ForNotFull */
return this->message_queue->IsFull() ? TriBool::False : TriBool::True;
+ } else {
+ static_assert(WaitKind != WaitKind);
+ }
+ }
+
+ constexpr inline WaitableObjectList &GetObjectList() const {
+ if constexpr (WaitKind == MessageQueueWaitKind::ForNotEmpty) {
+ return GetReference(this->message_queue->waitlist_not_empty);
+ } else if constexpr (WaitKind == MessageQueueWaitKind::ForNotFull) {
+ return GetReference(this->message_queue->waitlist_not_full);
+ } else {
+ static_assert(WaitKind != WaitKind);
}
}
public:
@@ -46,14 +58,14 @@ namespace ams::os::impl {
virtual TriBool LinkToObjectList() override {
std::scoped_lock lk(this->message_queue->queue_lock);
- GetReference(this->message_queue->waitable_object_list_storage).LinkWaitableHolder(*this);
+ this->GetObjectList().LinkWaitableHolder(*this);
return this->IsSignaledImpl();
}
virtual void UnlinkFromObjectList() override {
std::scoped_lock lk(this->message_queue->queue_lock);
- GetReference(this->message_queue->waitable_object_list_storage).UnlinkWaitableHolder(*this);
+ this->GetObjectList().UnlinkWaitableHolder(*this);
}
};
diff --git a/source/os/impl/os_waitable_object_list.hpp b/source/os/impl/os_waitable_object_list.hpp
index 71660ad3..ec0a83cc 100644
--- a/source/os/impl/os_waitable_object_list.hpp
+++ b/source/os/impl/os_waitable_object_list.hpp
@@ -31,7 +31,7 @@ namespace ams::os::impl {
}
}
- void WakeupAllThreads() {
+ void BroadcastAllThreads() {
for (WaitableHolderBase &holder_base : this->object_list) {
holder_base.GetManager()->SignalAndWakeupThread(nullptr);
}
diff --git a/source/os/os_event.cpp b/source/os/os_event.cpp
index 1e146b9e..fdb61a22 100644
--- a/source/os/os_event.cpp
+++ b/source/os/os_event.cpp
@@ -90,7 +90,7 @@ namespace ams::os {
if (this->counter != cur_counter) {
break;
}
- if (R_FAILED(this->cv.TimedWait(&this->lock, timeout_helper.NsUntilTimeout()))) {
+ if (this->cv.TimedWait(&this->lock, timeout_helper.NsUntilTimeout()) == ConditionVariableStatus::TimedOut) {
return false;
}
}
diff --git a/source/os/os_message_queue.cpp b/source/os/os_message_queue.cpp
index 17accc8a..ab38b891 100644
--- a/source/os/os_message_queue.cpp
+++ b/source/os/os_message_queue.cpp
@@ -17,12 +17,14 @@
namespace ams::os {
- MessageQueue::MessageQueue(std::unique_ptr buf, size_t c): buffer(std::move(buf)), capacity(c) {
- new (GetPointer(this->waitable_object_list_storage)) impl::WaitableObjectList();
+ MessageQueue::MessageQueue(std::unique_ptr buf, size_t c): buffer(std::move(buf)), capacity(c), count(0), offset(0) {
+ new (GetPointer(this->waitlist_not_empty)) impl::WaitableObjectList();
+ new (GetPointer(this->waitlist_not_full)) impl::WaitableObjectList();
}
MessageQueue::~MessageQueue() {
- GetReference(this->waitable_object_list_storage).~WaitableObjectList();
+ GetReference(this->waitlist_not_empty).~WaitableObjectList();
+ GetReference(this->waitlist_not_full).~WaitableObjectList();
}
void MessageQueue::SendInternal(uintptr_t data) {
@@ -53,7 +55,7 @@ namespace ams::os {
return data;
}
- uintptr_t MessageQueue::PeekInternal() {
+ inline uintptr_t MessageQueue::PeekInternal() {
/* Ensure we don't corrupt the queue, but this should never happen. */
AMS_ASSERT(this->count > 0);
@@ -70,7 +72,8 @@ namespace ams::os {
/* Send, signal. */
this->SendInternal(data);
- this->cv_not_empty.WakeAll();
+ this->cv_not_empty.Broadcast();
+ GetReference(this->waitlist_not_empty).SignalAllThreads();
}
bool MessageQueue::TrySend(uintptr_t data) {
@@ -81,7 +84,8 @@ namespace ams::os {
/* Send, signal. */
this->SendInternal(data);
- this->cv_not_empty.WakeAll();
+ this->cv_not_empty.Broadcast();
+ GetReference(this->waitlist_not_empty).SignalAllThreads();
return true;
}
@@ -94,12 +98,13 @@ namespace ams::os {
return false;
}
- this->cv_not_full.TimedWait(&this->queue_lock, timeout);
+ this->cv_not_full.TimedWait(&this->queue_lock, timeout_helper.NsUntilTimeout());
}
/* Send, signal. */
this->SendInternal(data);
- this->cv_not_empty.WakeAll();
+ this->cv_not_empty.Broadcast();
+ GetReference(this->waitlist_not_empty).SignalAllThreads();
return true;
}
@@ -113,7 +118,8 @@ namespace ams::os {
/* Send, signal. */
this->SendNextInternal(data);
- this->cv_not_empty.WakeAll();
+ this->cv_not_empty.Broadcast();
+ GetReference(this->waitlist_not_empty).SignalAllThreads();
}
bool MessageQueue::TrySendNext(uintptr_t data) {
@@ -124,7 +130,8 @@ namespace ams::os {
/* Send, signal. */
this->SendNextInternal(data);
- this->cv_not_empty.WakeAll();
+ this->cv_not_empty.Broadcast();
+ GetReference(this->waitlist_not_empty).SignalAllThreads();
return true;
}
@@ -137,12 +144,13 @@ namespace ams::os {
return false;
}
- this->cv_not_full.TimedWait(&this->queue_lock, timeout);
+ this->cv_not_full.TimedWait(&this->queue_lock, timeout_helper.NsUntilTimeout());
}
/* Send, signal. */
this->SendNextInternal(data);
- this->cv_not_empty.WakeAll();
+ this->cv_not_empty.Broadcast();
+ GetReference(this->waitlist_not_empty).SignalAllThreads();
return true;
}
@@ -156,8 +164,10 @@ namespace ams::os {
/* Receive, signal. */
*out = this->ReceiveInternal();
- this->cv_not_full.WakeAll();
+ this->cv_not_full.Broadcast();
+ GetReference(this->waitlist_not_full).SignalAllThreads();
}
+
bool MessageQueue::TryReceive(uintptr_t *out) {
/* Acquire mutex, wait receivable. */
std::scoped_lock lock(this->queue_lock);
@@ -168,7 +178,8 @@ namespace ams::os {
/* Receive, signal. */
*out = this->ReceiveInternal();
- this->cv_not_full.WakeAll();
+ this->cv_not_full.Broadcast();
+ GetReference(this->waitlist_not_full).SignalAllThreads();
return true;
}
@@ -181,12 +192,13 @@ namespace ams::os {
return false;
}
- this->cv_not_empty.TimedWait(&this->queue_lock, timeout);
+ this->cv_not_empty.TimedWait(&this->queue_lock, timeout_helper.NsUntilTimeout());
}
/* Receive, signal. */
*out = this->ReceiveInternal();
- this->cv_not_full.WakeAll();
+ this->cv_not_full.Broadcast();
+ GetReference(this->waitlist_not_full).SignalAllThreads();
return true;
}
@@ -224,7 +236,7 @@ namespace ams::os {
return false;
}
- this->cv_not_empty.TimedWait(&this->queue_lock, timeout);
+ this->cv_not_empty.TimedWait(&this->queue_lock, timeout_helper.NsUntilTimeout());
}
/* Peek. */
diff --git a/source/os/os_process_handle.cpp b/source/os/os_process_handle.cpp
new file mode 100644
index 00000000..c5d3736c
--- /dev/null
+++ b/source/os/os_process_handle.cpp
@@ -0,0 +1,44 @@
+/*
+ * Copyright (c) 2018-2019 Atmosphère-NX
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms and conditions of the GNU General Public License,
+ * version 2, as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see .
+ */
+#include
+
+namespace ams {
+
+ namespace {
+
+ constexpr inline ::Handle GetCurrentProcessHandleImpl() {
+ return CUR_PROCESS_HANDLE;
+ }
+
+ }
+
+ namespace os {
+
+ ::Handle __attribute__((const)) GetCurrentProcessHandle() {
+ return GetCurrentProcessHandleImpl();
+ }
+
+ }
+
+ namespace dd {
+
+ ::Handle __attribute__((const)) GetCurrentProcessHandle() {
+ return GetCurrentProcessHandleImpl();
+ }
+
+ }
+
+}