diff --git a/.idea/inspectionProfiles/Project_Default.xml b/.idea/inspectionProfiles/Project_Default.xml
index da936f8e..ef2d25b4 100644
--- a/.idea/inspectionProfiles/Project_Default.xml
+++ b/.idea/inspectionProfiles/Project_Default.xml
@@ -171,10 +171,7 @@
-
-
-
-
+
diff --git a/app/src/main/cpp/skyline/kernel/svc.cpp b/app/src/main/cpp/skyline/kernel/svc.cpp
index 7d93901d..10eff2b6 100644
--- a/app/src/main/cpp/skyline/kernel/svc.cpp
+++ b/app/src/main/cpp/skyline/kernel/svc.cpp
@@ -288,7 +288,7 @@ namespace skyline::kernel::svc {
i64 in{static_cast(state.ctx->gpr.x0)};
if (in > 0) {
- state.logger->Debug("svcSleepThread: Thread sleeping for {} ns", in);
+ state.logger->Debug("svcSleepThread: Sleeping for {}ns", in);
struct timespec spec{
.tv_sec = static_cast(in / 1000000000),
@@ -302,6 +302,8 @@ namespace skyline::kernel::svc {
case yieldWithCoreMigration:
state.logger->Debug("svcSleepThread: Waking any appropriate parked threads");
state.scheduler->WakeParkedThread();
+ break;
+
case yieldWithoutCoreMigration:
state.logger->Debug("svcSleepThread: Cooperative Yield");
state.scheduler->Rotate();
@@ -447,7 +449,7 @@ namespace skyline::kernel::svc {
KHandle handle{state.ctx->gpr.w0};
try {
std::static_pointer_cast(state.process->GetHandle(handle))->ResetSignal();
- state.logger->Debug("svcClearEvent: Clearing event: 0x{:X}", handle);
+ state.logger->Debug("svcClearEvent: Clearing 0x{:X}", handle);
state.ctx->gpr.w0 = Result{};
} catch (const std::out_of_range &) {
state.logger->Warn("svcClearEvent: 'handle' invalid: 0x{:X}", handle);
@@ -525,7 +527,7 @@ namespace skyline::kernel::svc {
KHandle handle{static_cast(state.ctx->gpr.w0)};
try {
state.process->CloseHandle(handle);
- state.logger->Debug("svcCloseHandle: Closing handle: 0x{:X}", handle);
+ state.logger->Debug("svcCloseHandle: Closing 0x{:X}", handle);
state.ctx->gpr.w0 = Result{};
} catch (const std::out_of_range &) {
state.logger->Warn("svcCloseHandle: 'handle' invalid: 0x{:X}", handle);
@@ -540,7 +542,7 @@ namespace skyline::kernel::svc {
switch (object->objectType) {
case type::KType::KEvent:
case type::KType::KProcess:
- std::static_pointer_cast(object)->ResetSignal();
+ state.ctx->gpr.w0 = std::static_pointer_cast(object)->ResetSignal() ? Result{} : result::InvalidState;
break;
default: {
@@ -550,7 +552,7 @@ namespace skyline::kernel::svc {
}
}
- state.logger->Debug("svcResetSignal: Resetting signal: 0x{:X}", handle);
+ state.logger->Debug("svcResetSignal: Resetting 0x{:X}", handle);
state.ctx->gpr.w0 = Result{};
} catch (const std::out_of_range &) {
state.logger->Warn("svcResetSignal: 'handle' invalid: 0x{:X}", handle);
@@ -572,11 +574,7 @@ namespace skyline::kernel::svc {
std::vector> objectTable;
objectTable.reserve(numHandles);
- std::string handleString;
for (const auto &handle : waitHandles) {
- if (Logger::LogLevel::Debug <= state.logger->configLevel)
- handleString += fmt::format("* 0x{:X}\n", handle);
-
auto object{state.process->GetHandle(handle)};
switch (object->objectType) {
case type::KType::KProcess:
@@ -595,7 +593,14 @@ namespace skyline::kernel::svc {
}
i64 timeout{static_cast(state.ctx->gpr.x3)};
- state.logger->Debug("svcWaitSynchronization: Waiting on handles:\n{}Timeout: {}ns", handleString, timeout);
+ if (waitHandles.size() == 1) {
+ state.logger->Debug("svcWaitSynchronization: Waiting on 0x{:X} for {}ns", waitHandles[0], timeout);
+ } else if (Logger::LogLevel::Debug <= state.logger->configLevel) {
+ std::string handleString;
+ for (const auto &handle : waitHandles)
+ handleString += fmt::format("* 0x{:X}\n", handle);
+ state.logger->Debug("svcWaitSynchronization: Waiting on handles:\n{}Timeout: {}ns", handleString, timeout);
+ }
std::unique_lock lock(type::KSyncObject::syncObjectMutex);
if (state.thread->cancelSync) {
@@ -607,7 +612,7 @@ namespace skyline::kernel::svc {
u32 index{};
for (const auto &object : objectTable) {
if (object->signalled) {
- state.logger->Debug("svcWaitSynchronization: Signalled handle: 0x{:X}", waitHandles[index]);
+ state.logger->Debug("svcWaitSynchronization: Signalled 0x{:X}", waitHandles[index]);
state.ctx->gpr.w0 = Result{};
state.ctx->gpr.w1 = index;
return;
@@ -655,7 +660,7 @@ namespace skyline::kernel::svc {
}
if (wakeObject) {
- state.logger->Debug("svcWaitSynchronization: Signalled handle: 0x{:X}", waitHandles[wakeIndex]);
+ state.logger->Debug("svcWaitSynchronization: Signalled 0x{:X}", waitHandles[wakeIndex]);
state.ctx->gpr.w0 = Result{};
state.ctx->gpr.w1 = wakeIndex;
} else if (state.thread->cancelSync) {
@@ -680,6 +685,7 @@ namespace skyline::kernel::svc {
thread->isCancellable = false;
state.scheduler->InsertThread(thread);
}
+ state.ctx->gpr.w0 = Result{};
} catch (const std::out_of_range &) {
state.logger->Warn("svcCancelSynchronization: 'handle' invalid: 0x{:X}", static_cast(state.ctx->gpr.w0));
state.ctx->gpr.w0 = result::InvalidHandle;
@@ -687,24 +693,24 @@ namespace skyline::kernel::svc {
}
void ArbitrateLock(const DeviceState &state) {
- auto pointer{reinterpret_cast(state.ctx->gpr.x1)};
- if (!util::WordAligned(pointer)) {
- state.logger->Warn("svcArbitrateLock: 'pointer' not word aligned: 0x{:X}", pointer);
+ auto mutex{reinterpret_cast(state.ctx->gpr.x1)};
+ if (!util::WordAligned(mutex)) {
+ state.logger->Warn("svcArbitrateLock: 'mutex' not word aligned: 0x{:X}", mutex);
state.ctx->gpr.w0 = result::InvalidAddress;
return;
}
- state.logger->Debug("svcArbitrateLock: Locking mutex at 0x{:X}", pointer);
+ state.logger->Debug("svcArbitrateLock: Locking 0x{:X}", mutex);
KHandle ownerHandle{state.ctx->gpr.w0};
KHandle requesterHandle{state.ctx->gpr.w2};
- auto result{state.process->MutexLock(pointer, ownerHandle, requesterHandle)};
+ auto result{state.process->MutexLock(mutex, ownerHandle, requesterHandle)};
if (result == Result{})
- state.logger->Debug("svcArbitrateLock: Locked mutex at 0x{:X}", pointer);
+ state.logger->Debug("svcArbitrateLock: Locked 0x{:X}", mutex);
+ else if (result == result::InvalidCurrentMemory)
+ result = Result{}; // If the mutex value isn't expected then it's still successful
else if (result == result::InvalidHandle)
state.logger->Warn("svcArbitrateLock: 'ownerHandle' invalid: 0x{:X}", ownerHandle);
- else if (result == result::InvalidCurrentMemory)
- state.logger->Debug("svcArbitrateLock: Owner handle did not match current owner for mutex or didn't have waiter flag at 0x{:X}", pointer);
state.ctx->gpr.w0 = result;
}
@@ -717,9 +723,9 @@ namespace skyline::kernel::svc {
return;
}
- state.logger->Debug("svcArbitrateUnlock: Unlocking mutex at 0x{:X}", mutex);
+ state.logger->Debug("svcArbitrateUnlock: Unlocking 0x{:X}", mutex);
state.process->MutexUnlock(mutex);
- state.logger->Debug("svcArbitrateUnlock: Unlocked mutex at 0x{:X}", mutex);
+ state.logger->Debug("svcArbitrateUnlock: Unlocked 0x{:X}", mutex);
state.ctx->gpr.w0 = Result{};
}
@@ -736,22 +742,22 @@ namespace skyline::kernel::svc {
KHandle requesterHandle{state.ctx->gpr.w2};
i64 timeout{static_cast(state.ctx->gpr.x3)};
- state.logger->Debug("svcWaitProcessWideKeyAtomic: Mutex: 0x{:X}, Conditional-Variable: 0x{:X}, Timeout: {}ns", mutex, conditional, timeout);
+ state.logger->Debug("svcWaitProcessWideKeyAtomic: Waiting on 0x{:X} with 0x{:X} for {}ns", conditional, mutex, timeout);
auto result{state.process->ConditionalVariableWait(conditional, mutex, requesterHandle, timeout)};
if (result == Result{})
- state.logger->Debug("svcWaitProcessWideKeyAtomic: Waited for conditional variable (0x{:X}) and reacquired mutex", conditional);
+ state.logger->Debug("svcWaitProcessWideKeyAtomic: Waited for 0x{:X} and reacquired 0x{:X}", conditional, mutex);
else if (result == result::TimedOut)
- state.logger->Debug("svcWaitProcessWideKeyAtomic: Wait has timed out ({}ns) for 0x{:X}", timeout, conditional);
+ state.logger->Debug("svcWaitProcessWideKeyAtomic: Wait on 0x{:X} has timed out after {}ns", conditional, timeout);
state.ctx->gpr.w0 = result;
}
void SignalProcessWideKey(const DeviceState &state) {
- auto key{reinterpret_cast(state.ctx->gpr.x0)};
- KHandle count{state.ctx->gpr.w1};
+ auto conditional{reinterpret_cast(state.ctx->gpr.x0)};
+ i32 count{static_cast(state.ctx->gpr.w1)};
- state.logger->Debug("svcSignalProcessWideKey: Signalling Conditional-Variable at 0x{:X} for {}", key, count);
- state.process->ConditionalVariableSignal(key, count);
+ state.logger->Debug("svcSignalProcessWideKey: Signalling 0x{:X} for {} waiters", conditional, count);
+ state.process->ConditionalVariableSignal(conditional, count);
state.ctx->gpr.w0 = Result{};
}
diff --git a/app/src/main/cpp/skyline/kernel/types/KProcess.cpp b/app/src/main/cpp/skyline/kernel/types/KProcess.cpp
index e9ff5977..41097463 100644
--- a/app/src/main/cpp/skyline/kernel/types/KProcess.cpp
+++ b/app/src/main/cpp/skyline/kernel/types/KProcess.cpp
@@ -245,7 +245,6 @@ namespace skyline::kernel::type {
state.scheduler->RemoveThread();
MutexUnlock(mutex);
- __sync_synchronize();
}
if (timeout > 0 && !state.scheduler->TimedWaitSchedule(std::chrono::nanoseconds(timeout))) {
@@ -255,9 +254,11 @@ namespace skyline::kernel::type {
if (iterator != queue.second)
if (syncWaiters.erase(iterator) == queue.second)
__atomic_store_n(key, false, __ATOMIC_SEQ_CST);
+
lock.unlock();
state.scheduler->InsertThread(state.thread);
state.scheduler->WaitSchedule();
+
return result::TimedOut;
} else {
state.scheduler->WaitSchedule(false);
@@ -275,13 +276,15 @@ namespace skyline::kernel::type {
}
}
- void KProcess::ConditionalVariableSignal(u32 *key, u64 amount) {
+ void KProcess::ConditionalVariableSignal(u32 *key, i32 amount) {
std::lock_guard lock(syncWaiterMutex);
auto queue{syncWaiters.equal_range(key)};
+
auto it{queue.first};
if (queue.first != queue.second)
- for (; it != queue.second && amount; it = syncWaiters.erase(it), amount--)
+ for (i32 waiterCount{amount}; it != queue.second && (amount <= 0 || waiterCount); it = syncWaiters.erase(it), waiterCount--)
state.scheduler->InsertThread(it->second);
+
if (it == queue.second)
__atomic_store_n(key, false, __ATOMIC_SEQ_CST); // We need to update the boolean flag denoting that there are no more threads waiting on this conditional variable
}
diff --git a/app/src/main/cpp/skyline/kernel/types/KProcess.h b/app/src/main/cpp/skyline/kernel/types/KProcess.h
index 0eca5ae9..f632c896 100644
--- a/app/src/main/cpp/skyline/kernel/types/KProcess.h
+++ b/app/src/main/cpp/skyline/kernel/types/KProcess.h
@@ -221,7 +221,7 @@ namespace skyline {
/**
* @brief Signals the conditional variable at the specified address
*/
- void ConditionalVariableSignal(u32 *key, u64 amount);
+ void ConditionalVariableSignal(u32 *key, i32 amount);
/**
* @brief Waits on the supplied address with the specified arbitration function
diff --git a/app/src/main/cpp/skyline/kernel/types/KSyncObject.h b/app/src/main/cpp/skyline/kernel/types/KSyncObject.h
index 47a16d33..3fff7085 100644
--- a/app/src/main/cpp/skyline/kernel/types/KSyncObject.h
+++ b/app/src/main/cpp/skyline/kernel/types/KSyncObject.h
@@ -14,7 +14,7 @@ namespace skyline::kernel::type {
public:
inline static std::mutex syncObjectMutex; //!< A global lock used for locking all signalling to avoid races
std::list> syncObjectWaiters; //!< A list of threads waiting on this object to be signalled
- std::atomic signalled; //!< If the current object is signalled (An object stays signalled till the signal has been explicitly reset)
+ bool signalled; //!< If the current object is signalled (An object stays signalled till the signal has been explicitly reset)
/**
* @param presignalled If this object should be signalled initially or not
@@ -28,10 +28,15 @@ namespace skyline::kernel::type {
/**
* @brief Resets the object to an unsignalled state
+ * @return If the signal was reset or not
*/
- inline void ResetSignal() {
+ inline bool ResetSignal() {
std::lock_guard lock(syncObjectMutex);
- signalled = false;
+ if (signalled) {
+ signalled = false;
+ return true;
+ }
+ return false;
}
virtual ~KSyncObject() = default;
diff --git a/app/src/main/cpp/skyline/nce.cpp b/app/src/main/cpp/skyline/nce.cpp
index 46912ca1..12c199cf 100644
--- a/app/src/main/cpp/skyline/nce.cpp
+++ b/app/src/main/cpp/skyline/nce.cpp
@@ -18,14 +18,14 @@ namespace skyline::nce {
const auto &state{*ctx->state};
try {
auto function{kernel::svc::SvcTable[svc]};
- if (function) {
+ if (function) [[likely]] {
state.logger->Debug("SVC called 0x{:X}", svc);
(*function)(state);
- } else {
+ } else [[unlikely]] {
throw exception("Unimplemented SVC 0x{:X}", svc);
}
- while (kernel::Scheduler::YieldPending) {
+ while (kernel::Scheduler::YieldPending) [[unlikely]] {
state.scheduler->Rotate(false);
kernel::Scheduler::YieldPending = false;
state.scheduler->WaitSchedule();
diff --git a/app/src/main/cpp/skyline/services/settings/ISystemSettingsServer.cpp b/app/src/main/cpp/skyline/services/settings/ISystemSettingsServer.cpp
index 0a5ee6eb..228fcf40 100644
--- a/app/src/main/cpp/skyline/services/settings/ISystemSettingsServer.cpp
+++ b/app/src/main/cpp/skyline/services/settings/ISystemSettingsServer.cpp
@@ -7,7 +7,7 @@ namespace skyline::service::settings {
ISystemSettingsServer::ISystemSettingsServer(const DeviceState &state, ServiceManager &manager) : BaseService(state, manager) {}
Result ISystemSettingsServer::GetFirmwareVersion(type::KSession &session, ipc::IpcRequest &request, ipc::IpcResponse &response) {
- request.outputBuf.at(0).as() = {.major=5, .minor=0, .micro=0, .revMajor=4, .revMinor=0, .platform="NX", .verHash="4de65c071fd0869695b7629f75eb97b2551dbf2f", .dispVer="9.0.0", .dispTitle="NintendoSDK Firmware for NX 9.0.0-4.0"};
+ request.outputBuf.at(0).as() = {.major=9, .minor=0, .micro=0, .revMajor=4, .revMinor=0, .platform="NX", .verHash="4de65c071fd0869695b7629f75eb97b2551dbf2f", .dispVer="9.0.0", .dispTitle="NintendoSDK Firmware for NX 9.0.0-4.0"};
return {};
}
}