Improve Synchronization SVCs + Fix TLS Page Allocation Race + Fix KProcess::GetHandle<KObject>

This commit is contained in:
◱ PixelyIon 2021-01-12 00:47:06 +05:30 committed by ◱ Mark
parent ebadc1d1e1
commit ef52e22cef
24 changed files with 179 additions and 109 deletions

View File

@ -48,6 +48,7 @@ add_library(skyline SHARED
${source_DIR}/skyline/kernel/types/KThread.cpp ${source_DIR}/skyline/kernel/types/KThread.cpp
${source_DIR}/skyline/kernel/types/KSharedMemory.cpp ${source_DIR}/skyline/kernel/types/KSharedMemory.cpp
${source_DIR}/skyline/kernel/types/KPrivateMemory.cpp ${source_DIR}/skyline/kernel/types/KPrivateMemory.cpp
${source_DIR}/skyline/kernel/types/KSyncObject.cpp
${source_DIR}/skyline/audio.cpp ${source_DIR}/skyline/audio.cpp
${source_DIR}/skyline/audio/track.cpp ${source_DIR}/skyline/audio/track.cpp
${source_DIR}/skyline/audio/resampler.cpp ${source_DIR}/skyline/audio/resampler.cpp

View File

@ -9,9 +9,7 @@ extern skyline::u16 Fps;
extern skyline::u32 FrameTime; extern skyline::u32 FrameTime;
namespace skyline::gpu { namespace skyline::gpu {
PresentationEngine::PresentationEngine(const DeviceState &state) : state(state), vsyncEvent(std::make_shared<kernel::type::KEvent>(state)), bufferEvent(std::make_shared<kernel::type::KEvent>(state)) { PresentationEngine::PresentationEngine(const DeviceState &state) : state(state), vsyncEvent(std::make_shared<kernel::type::KEvent>(state, true)), bufferEvent(std::make_shared<kernel::type::KEvent>(state, true)) {}
vsyncEvent->Signal();
}
PresentationEngine::~PresentationEngine() { PresentationEngine::~PresentationEngine() {
if (window) if (window)

View File

@ -6,7 +6,7 @@
#include "npad.h" #include "npad.h"
namespace skyline::input { namespace skyline::input {
NpadDevice::NpadDevice(NpadManager &manager, NpadSection &section, NpadId id) : manager(manager), section(section), id(id), updateEvent(std::make_shared<kernel::type::KEvent>(manager.state)) {} NpadDevice::NpadDevice(NpadManager &manager, NpadSection &section, NpadId id) : manager(manager), section(section), id(id), updateEvent(std::make_shared<kernel::type::KEvent>(manager.state, false)) {}
void NpadDevice::Connect(NpadControllerType newType) { void NpadDevice::Connect(NpadControllerType newType) {
if (type == newType) { if (type == newType) {

View File

@ -524,11 +524,8 @@ namespace skyline::kernel::svc {
auto object{state.process->GetHandle(handle)}; auto object{state.process->GetHandle(handle)};
switch (object->objectType) { switch (object->objectType) {
case type::KType::KEvent: case type::KType::KEvent:
std::static_pointer_cast<type::KEvent>(object)->ResetSignal();
break;
case type::KType::KProcess: case type::KType::KProcess:
std::static_pointer_cast<type::KProcess>(object)->ResetSignal(); std::static_pointer_cast<type::KSyncObject>(object)->ResetSignal();
break; break;
default: { default: {
@ -552,17 +549,18 @@ namespace skyline::kernel::svc {
u32 numHandles{state.ctx->gpr.w2}; u32 numHandles{state.ctx->gpr.w2};
if (numHandles > maxSyncHandles) { if (numHandles > maxSyncHandles) {
state.ctx->gpr.w0 = result::OutOfHandles; state.ctx->gpr.w0 = result::OutOfRange;
return; return;
} }
std::string handleStr;
std::vector<std::shared_ptr<type::KSyncObject>> objectTable;
span waitHandles(reinterpret_cast<KHandle *>(state.ctx->gpr.x1), numHandles); span waitHandles(reinterpret_cast<KHandle *>(state.ctx->gpr.x1), numHandles);
std::vector<std::shared_ptr<type::KSyncObject>> objectTable;
objectTable.reserve(numHandles);
std::string handleString;
for (const auto &handle : waitHandles) { for (const auto &handle : waitHandles) {
if (Logger::LogLevel::Debug <= state.logger->configLevel) if (Logger::LogLevel::Debug <= state.logger->configLevel)
handleStr += fmt::format("* 0x{:X}\n", handle); handleString += fmt::format("* 0x{:X}\n", handle);
auto object{state.process->GetHandle(handle)}; auto object{state.process->GetHandle(handle)};
switch (object->objectType) { switch (object->objectType) {
@ -574,46 +572,99 @@ namespace skyline::kernel::svc {
break; break;
default: { default: {
state.logger->Debug("svcWaitSynchronization: An invalid handle was supplied: 0x{:X}", handle);
state.ctx->gpr.w0 = result::InvalidHandle; state.ctx->gpr.w0 = result::InvalidHandle;
return; return;
} }
} }
} }
u64 timeout{state.ctx->gpr.x3}; i64 timeout{static_cast<i64>(state.ctx->gpr.x3)};
state.logger->Debug("svcWaitSynchronization: Waiting on handles:\n{}Timeout: 0x{:X} ns", handleStr, timeout); state.logger->Debug("svcWaitSynchronization: Waiting on handles:\n{}Timeout: {}ns", handleString, timeout);
SchedulerScopedLock schedulerLock(state); std::unique_lock lock(type::KSyncObject::syncObjectMutex);
auto start{util::GetTimeNs()}; if (state.thread->cancelSync) {
while (true) { state.thread->cancelSync = false;
if (state.thread->cancelSync) { state.ctx->gpr.w0 = result::Cancelled;
state.thread->cancelSync = false; return;
state.ctx->gpr.w0 = result::Cancelled; }
u32 index{};
for (const auto &object : objectTable) {
if (object->signalled) {
state.logger->Debug("svcWaitSynchronization: Signalled handle: 0x{:X}", waitHandles[index]);
state.ctx->gpr.w0 = Result{};
state.ctx->gpr.w1 = index;
return; return;
} }
index++;
}
u32 index{}; if (timeout == 0) {
for (const auto &object : objectTable) { state.logger->Debug("svcWaitSynchronization: No handle is currently signalled");
if (object->signalled) { state.ctx->gpr.w0 = result::TimedOut;
state.logger->Debug("svcWaitSynchronization: Signalled handle: 0x{:X}", waitHandles[index]); return;
state.ctx->gpr.w0 = Result{}; }
state.ctx->gpr.w1 = index;
return;
}
index++;
}
if ((util::GetTimeNs() - start) >= timeout) { auto priority{state.thread->priority.load()};
state.logger->Debug("svcWaitSynchronization: Wait has timed out"); for (const auto &object : objectTable)
state.ctx->gpr.w0 = result::TimedOut; object->syncObjectWaiters.insert(std::upper_bound(object->syncObjectWaiters.begin(), object->syncObjectWaiters.end(), priority, type::KThread::IsHigherPriority), state.thread);
return;
} state.thread->isCancellable = true;
state.thread->wakeObject = nullptr;
state.scheduler->RemoveThread();
lock.unlock();
if (timeout > 0)
state.scheduler->TimedWaitSchedule(std::chrono::nanoseconds(timeout));
else
state.scheduler->WaitSchedule(false);
lock.lock();
state.thread->isCancellable = false;
auto wakeObject{state.thread->wakeObject};
u32 wakeIndex{};
index = 0;
for (const auto &object : objectTable) {
if (object.get() == wakeObject)
wakeIndex = index;
auto it{std::find(object->syncObjectWaiters.begin(), object->syncObjectWaiters.end(), state.thread)};
if (it != object->syncObjectWaiters.end())
object->syncObjectWaiters.erase(it);
else
throw exception("svcWaitSynchronization: An object (0x{:X}) has been removed from the syncObjectWaiters queue incorrectly", waitHandles[index]);
index++;
}
if (wakeObject) {
state.logger->Debug("svcWaitSynchronization: Signalled handle: 0x{:X}", waitHandles[index]);
state.ctx->gpr.w0 = Result{};
state.ctx->gpr.w1 = wakeIndex;
} else if (state.thread->cancelSync) {
state.thread->cancelSync = false;
state.logger->Debug("svcWaitSynchronization: Wait has been cancelled");
state.ctx->gpr.w0 = result::Cancelled;
} else {
state.logger->Debug("svcWaitSynchronization: Wait has timed out");
state.ctx->gpr.w0 = result::TimedOut;
lock.unlock();
state.scheduler->InsertThread(state.thread);
state.scheduler->WaitSchedule();
} }
} }
void CancelSynchronization(const DeviceState &state) { void CancelSynchronization(const DeviceState &state) {
try { try {
state.process->GetHandle<type::KThread>(state.ctx->gpr.w0)->cancelSync = true; std::unique_lock lock(type::KSyncObject::syncObjectMutex);
auto thread{state.process->GetHandle<type::KThread>(state.ctx->gpr.w0)};
thread->cancelSync = true;
if (thread->isCancellable) {
thread->isCancellable = false;
state.scheduler->InsertThread(thread);
}
} catch (const std::out_of_range &) { } catch (const std::out_of_range &) {
state.logger->Warn("svcCancelSynchronization: 'handle' invalid: 0x{:X}", static_cast<u32>(state.ctx->gpr.w0)); state.logger->Warn("svcCancelSynchronization: 'handle' invalid: 0x{:X}", static_cast<u32>(state.ctx->gpr.w0));
state.ctx->gpr.w0 = result::InvalidHandle; state.ctx->gpr.w0 = result::InvalidHandle;
@ -878,7 +929,7 @@ namespace skyline::kernel::svc {
break; break;
case InfoState::UserExceptionContextAddr: case InfoState::UserExceptionContextAddr:
out = reinterpret_cast<u64>(state.process->tlsPages[0]->Get(0)); out = reinterpret_cast<u64>(state.process->tlsExceptionContext);
break; break;
default: default:

View File

@ -12,13 +12,9 @@ namespace skyline::kernel::type {
*/ */
class KEvent : public KSyncObject { class KEvent : public KSyncObject {
public: public:
KEvent(const DeviceState &state) : KSyncObject(state, KType::KEvent) {}
/** /**
* @brief Resets the KEvent to an unsignalled state * @param presignalled If this object should be signalled initially or not
*/ */
inline void ResetSignal() { KEvent(const DeviceState &state, bool presignalled) : KSyncObject(state, KType::KEvent, presignalled) {}
signalled = false;
}
}; };
} }

View File

@ -10,19 +10,9 @@ namespace skyline::kernel::type {
KProcess::TlsPage::TlsPage(const std::shared_ptr<KPrivateMemory> &memory) : memory(memory) {} KProcess::TlsPage::TlsPage(const std::shared_ptr<KPrivateMemory> &memory) : memory(memory) {}
u8 *KProcess::TlsPage::ReserveSlot() { u8 *KProcess::TlsPage::ReserveSlot() {
if (Full()) if (index == constant::TlsSlots)
throw exception("Trying to reserve TLS slot in full page"); return nullptr;
return Get(index++); return memory->ptr + (constant::TlsSlotSize * index++);
}
u8 *KProcess::TlsPage::Get(u8 slot) {
if (slot >= constant::TlsSlots)
throw exception("TLS slot is out of range");
return memory->ptr + (constant::TlsSlotSize * slot);
}
bool KProcess::TlsPage::Full() {
return index == constant::TlsSlots;
} }
KProcess::KProcess(const DeviceState &state) : memory(state), KSyncObject(state, KType::KProcess) {} KProcess::KProcess(const DeviceState &state) : memory(state), KSyncObject(state, KType::KProcess) {}
@ -52,22 +42,23 @@ namespace skyline::kernel::type {
} }
} }
void KProcess::InitializeHeap() { void KProcess::InitializeHeapTls() {
constexpr size_t DefaultHeapSize{0x200000}; constexpr size_t DefaultHeapSize{0x200000};
heap = heap.make_shared(state, reinterpret_cast<u8 *>(state.process->memory.heap.address), DefaultHeapSize, memory::Permission{true, true, false}, memory::states::Heap); heap = heap.make_shared(state, reinterpret_cast<u8 *>(state.process->memory.heap.address), DefaultHeapSize, memory::Permission{true, true, false}, memory::states::Heap);
InsertItem(heap); // Insert it into the handle table so GetMemoryObject will contain it InsertItem(heap); // Insert it into the handle table so GetMemoryObject will contain it
tlsExceptionContext = AllocateTlsSlot();
} }
u8 *KProcess::AllocateTlsSlot() { u8 *KProcess::AllocateTlsSlot() {
std::lock_guard lock(tlsMutex);
u8 *slot;
for (auto &tlsPage: tlsPages) for (auto &tlsPage: tlsPages)
if (!tlsPage->Full()) if ((slot = tlsPage->ReserveSlot()))
return tlsPage->ReserveSlot(); return slot;
u8 *ptr = tlsPages.empty() ? reinterpret_cast<u8 *>(state.process->memory.tlsIo.address) : ((*(tlsPages.end() - 1))->memory->ptr + PAGE_SIZE); slot = tlsPages.empty() ? reinterpret_cast<u8 *>(memory.tlsIo.address) : ((*(tlsPages.end() - 1))->memory->ptr + PAGE_SIZE);
auto tlsPage{std::make_shared<TlsPage>(std::make_shared<KPrivateMemory>(state, ptr, PAGE_SIZE, memory::Permission(true, true, false), memory::states::ThreadLocal))}; auto tlsPage{std::make_shared<TlsPage>(std::make_shared<KPrivateMemory>(state, slot, PAGE_SIZE, memory::Permission(true, true, false), memory::states::ThreadLocal))};
tlsPages.push_back(tlsPage); tlsPages.push_back(tlsPage);
tlsPage->ReserveSlot(); // User-mode exception handling
return tlsPage->ReserveSlot(); return tlsPage->ReserveSlot();
} }

View File

@ -3,7 +3,6 @@
#pragma once #pragma once
#include <list>
#include <vfs/npdm.h> #include <vfs/npdm.h>
#include "KThread.h" #include "KThread.h"
#include "KTransferMemory.h" #include "KTransferMemory.h"
@ -30,7 +29,7 @@ namespace skyline {
bool disableThreadCreation{}; //!< If to disable thread creation, we use this to prevent thread creation after all threads have been killed bool disableThreadCreation{}; //!< If to disable thread creation, we use this to prevent thread creation after all threads have been killed
std::vector<std::shared_ptr<KThread>> threads; std::vector<std::shared_ptr<KThread>> threads;
using SyncWaiters = std::multimap<void*, std::shared_ptr<KThread>>; using SyncWaiters = std::multimap<void *, std::shared_ptr<KThread>>;
std::mutex syncWaiterMutex; //!< Synchronizes all mutations to the map to prevent races std::mutex syncWaiterMutex; //!< Synchronizes all mutations to the map to prevent races
SyncWaiters syncWaiters; //!< All threads waiting on process-wide synchronization primitives (Atomic keys + Address Arbiter) SyncWaiters syncWaiters; //!< All threads waiting on process-wide synchronization primitives (Atomic keys + Address Arbiter)
@ -42,21 +41,23 @@ namespace skyline {
*/ */
struct TlsPage { struct TlsPage {
u8 index{}; //!< The slots are assigned sequentially, this holds the index of the last TLS slot reserved u8 index{}; //!< The slots are assigned sequentially, this holds the index of the last TLS slot reserved
std::shared_ptr<KPrivateMemory> memory; std::shared_ptr<KPrivateMemory> memory; //!< A single page sized memory allocation for this TLS page
TlsPage(const std::shared_ptr<KPrivateMemory> &memory); TlsPage(const std::shared_ptr<KPrivateMemory> &memory);
/**
* @return A non-null pointer to a TLS page slot on success, a nullptr will be returned if this page is full
* @note This function is not thread-safe and should be called by exclusively one thread at a time
*/
u8 *ReserveSlot(); u8 *ReserveSlot();
u8 *Get(u8 slot);
bool Full();
}; };
public: public:
std::shared_ptr<KPrivateMemory> mainThreadStack; u8* tlsExceptionContext{}; //!< A pointer to the TLS Exception Handling Context slot
std::mutex tlsMutex; //!< A mutex to synchronize allocation of TLS pages to prevent extra pages from being created
std::vector<std::shared_ptr<TlsPage>> tlsPages; //!< All TLS pages allocated by this process
std::shared_ptr<KPrivateMemory> mainThreadStack; //!< The stack memory of the main thread stack is owned by the KProcess itself
std::shared_ptr<KPrivateMemory> heap; std::shared_ptr<KPrivateMemory> heap;
std::vector<std::shared_ptr<TlsPage>> tlsPages;
vfs::NPDM npdm; vfs::NPDM npdm;
private: private:
@ -79,9 +80,10 @@ namespace skyline {
void Kill(bool join, bool all = false, bool disableCreation = false); void Kill(bool join, bool all = false, bool disableCreation = false);
/** /**
* @brief This initializes the process heap and TLS Error Context slot pointer, it should be called prior to creating the first thread
* @note This requires VMM regions to be initialized, it will map heap at an arbitrary location otherwise * @note This requires VMM regions to be initialized, it will map heap at an arbitrary location otherwise
*/ */
void InitializeHeap(); void InitializeHeapTls();
/** /**
* @return A 0x200 TLS slot allocated inside the TLS/IO region * @return A 0x200 TLS slot allocated inside the TLS/IO region
@ -177,7 +179,12 @@ namespace skyline {
template<> template<>
std::shared_ptr<KObject> GetHandle<KObject>(KHandle handle) { std::shared_ptr<KObject> GetHandle<KObject>(KHandle handle) {
return handles.at(handle - constant::BaseHandleIndex); std::shared_lock lock(handleMutex);
auto &item{handles.at(handle - constant::BaseHandleIndex)};
if (item != nullptr)
return item;
else
throw std::out_of_range(fmt::format("GetHandle was called with a deleted handle: 0x{:X}", handle));
} }
/** /**
@ -215,13 +222,6 @@ namespace skyline {
* @brief Signals the conditional variable at the specified address * @brief Signals the conditional variable at the specified address
*/ */
void ConditionalVariableSignal(u32 *key, u64 amount); void ConditionalVariableSignal(u32 *key, u64 amount);
/**
* @brief Resets the object to an unsignalled state
*/
inline void ResetSignal() {
signalled = false;
}
}; };
} }
} }

View File

@ -0,0 +1,19 @@
// SPDX-License-Identifier: MPL-2.0
// Copyright © 2020 Skyline Team and Contributors (https://github.com/skyline-emu/)
#include "KSyncObject.h"
#include "KThread.h"
namespace skyline::kernel::type {
void KSyncObject::Signal() {
std::lock_guard lock(syncObjectMutex);
signalled = true;
for (auto& waiter : syncObjectWaiters) {
if (waiter->isCancellable) {
waiter->isCancellable = false;
waiter->wakeObject = this;
state.scheduler->InsertThread(waiter);
}
}
}
}

View File

@ -7,19 +7,31 @@
namespace skyline::kernel::type { namespace skyline::kernel::type {
/** /**
* @brief KSyncObject holds the state of a waitable object * @brief KSyncObject is an abstract class which holds everything necessary for an object to be synchronizable
* @note This abstraction is roughly equivalent to KSynchronizationObject on HOS
*/ */
class KSyncObject : public KObject { class KSyncObject : public KObject {
public: public:
std::atomic<bool> signalled{false}; //!< If the current object is signalled (Used as object stays signalled till the signal is consumed) inline static std::mutex syncObjectMutex; //!< A global lock used for locking all signalling to avoid races
std::list<std::shared_ptr<KThread>> syncObjectWaiters; //!< A list of threads waiting on this object to be signalled
KSyncObject(const DeviceState &state, skyline::kernel::type::KType type) : KObject(state, type) {}; std::atomic<bool> signalled; //!< If the current object is signalled (An object stays signalled till the signal has been explicitly reset)
/** /**
* @brief A function for calling when a particular KSyncObject is signalled * @param presignalled If this object should be signalled initially or not
*/ */
virtual void Signal() { KSyncObject(const DeviceState &state, skyline::kernel::type::KType type, bool presignalled = false) : KObject(state, type), signalled(presignalled) {};
signalled = true;
/**
* @brief Wakes up any waiters on this object and flips the 'signalled' flag
*/
void Signal();
/**
* @brief Resets the object to an unsignalled state
*/
inline void ResetSignal() {
std::lock_guard lock(syncObjectMutex);
signalled = false;
} }
virtual ~KSyncObject() = default; virtual ~KSyncObject() = default;

View File

@ -3,7 +3,6 @@
#pragma once #pragma once
#include <list>
#include <csetjmp> #include <csetjmp>
#include <nce/guest.h> #include <nce/guest.h>
#include <kernel/scheduler.h> #include <kernel/scheduler.h>
@ -27,7 +26,7 @@ namespace skyline {
public: public:
std::mutex mutex; //!< Synchronizes all thread state changes std::mutex mutex; //!< Synchronizes all thread state changes
bool running{false}; //!< If the host thread that corresponds to this thread is running, this doesn't reflect guest scheduling changes bool running{false}; //!< If the host thread that corresponds to this thread is running, this doesn't reflect guest scheduling changes
std::atomic<bool> cancelSync{false}; //!< This is to flag to a thread to cancel a synchronization call it currently is in bool killed{false}; //!< If this thread was previously running and has been killed
KHandle handle; KHandle handle;
size_t id; //!< Index of thread in parent process's KThread vector size_t id; //!< Index of thread in parent process's KThread vector
@ -54,6 +53,9 @@ namespace skyline {
KHandle waitTag; //!< The handle of the thread which requested the mutex lock KHandle waitTag; //!< The handle of the thread which requested the mutex lock
std::shared_ptr<KThread> waitThread; //!< The thread which this thread is waiting on std::shared_ptr<KThread> waitThread; //!< The thread which this thread is waiting on
std::list<std::shared_ptr<type::KThread>> waiters; //!< A queue of threads waiting on this thread sorted by priority std::list<std::shared_ptr<type::KThread>> waiters; //!< A queue of threads waiting on this thread sorted by priority
bool isCancellable{false}; //!< If the thread is currently in a position where it is cancellable
bool cancelSync{false}; //!< If to cancel a SvcWaitSynchronization call this thread currently is in/the next one it joins
type::KSyncObject* wakeObject{}; //!< A pointer to the synchronization object responsible for waking this thread up
KThread(const DeviceState &state, KHandle handle, KProcess *parent, size_t id, void *entry, u64 argument, void *stackTop, u8 priority, i8 idealCore); KThread(const DeviceState &state, KHandle handle, KProcess *parent, size_t id, void *entry, u64 argument, void *stackTop, u8 priority, i8 idealCore);

View File

@ -36,7 +36,7 @@ namespace skyline::kernel {
auto &process{state.process}; auto &process{state.process};
process = std::make_shared<kernel::type::KProcess>(state); process = std::make_shared<kernel::type::KProcess>(state);
auto entry{state.loader->LoadProcessData(process, state)}; auto entry{state.loader->LoadProcessData(process, state)};
process->InitializeHeap(); process->InitializeHeapTls();
auto thread{process->CreateThread(entry)}; auto thread{process->CreateThread(entry)};
if (thread) { if (thread) {
state.logger->Debug("Starting main HOS thread"); state.logger->Debug("Starting main HOS thread");

View File

@ -7,7 +7,7 @@
#include "ILibraryAppletAccessor.h" #include "ILibraryAppletAccessor.h"
namespace skyline::service::am { namespace skyline::service::am {
ILibraryAppletAccessor::ILibraryAppletAccessor(const DeviceState &state, ServiceManager &manager) : stateChangeEvent(std::make_shared<type::KEvent>(state)), BaseService(state, manager) {} ILibraryAppletAccessor::ILibraryAppletAccessor(const DeviceState &state, ServiceManager &manager) : stateChangeEvent(std::make_shared<type::KEvent>(state, false)), BaseService(state, manager) {}
Result ILibraryAppletAccessor::GetAppletStateChangedEvent(type::KSession &session, ipc::IpcRequest &request, ipc::IpcResponse &response) { Result ILibraryAppletAccessor::GetAppletStateChangedEvent(type::KSession &session, ipc::IpcRequest &request, ipc::IpcResponse &response) {
stateChangeEvent->Signal(); stateChangeEvent->Signal();

View File

@ -7,7 +7,7 @@
#include "IApplicationFunctions.h" #include "IApplicationFunctions.h"
namespace skyline::service::am { namespace skyline::service::am {
IApplicationFunctions::IApplicationFunctions(const DeviceState &state, ServiceManager &manager) : gpuErrorEvent(std::make_shared<type::KEvent>(state)), BaseService(state, manager) {} IApplicationFunctions::IApplicationFunctions(const DeviceState &state, ServiceManager &manager) : gpuErrorEvent(std::make_shared<type::KEvent>(state, false)), BaseService(state, manager) {}
Result IApplicationFunctions::PopLaunchParameter(type::KSession &session, ipc::IpcRequest &request, ipc::IpcResponse &response) { Result IApplicationFunctions::PopLaunchParameter(type::KSession &session, ipc::IpcRequest &request, ipc::IpcResponse &response) {
constexpr u32 LaunchParameterMagic{0xC79497CA}; //!< The magic of the application launch parameters constexpr u32 LaunchParameterMagic{0xC79497CA}; //!< The magic of the application launch parameters

View File

@ -11,7 +11,7 @@ namespace skyline::service::am {
messageEvent->Signal(); messageEvent->Signal();
} }
ICommonStateGetter::ICommonStateGetter(const DeviceState &state, ServiceManager &manager) : messageEvent(std::make_shared<type::KEvent>(state)), BaseService(state, manager) { ICommonStateGetter::ICommonStateGetter(const DeviceState &state, ServiceManager &manager) : messageEvent(std::make_shared<type::KEvent>(state, false)), BaseService(state, manager) {
operationMode = static_cast<OperationMode>(state.settings->GetBool("operation_mode")); operationMode = static_cast<OperationMode>(state.settings->GetBool("operation_mode"));
state.logger->Info("Switch to mode: {}", static_cast<bool>(operationMode) ? "Docked" : "Handheld"); state.logger->Info("Switch to mode: {}", static_cast<bool>(operationMode) ? "Docked" : "Handheld");
QueueMessage(Message::FocusStateChange); QueueMessage(Message::FocusStateChange);

View File

@ -6,7 +6,7 @@
#include "ISelfController.h" #include "ISelfController.h"
namespace skyline::service::am { namespace skyline::service::am {
ISelfController::ISelfController(const DeviceState &state, ServiceManager &manager) : libraryAppletLaunchableEvent(std::make_shared<type::KEvent>(state)), accumulatedSuspendedTickChangedEvent(std::make_shared<type::KEvent>(state)), BaseService(state, manager) {} ISelfController::ISelfController(const DeviceState &state, ServiceManager &manager) : libraryAppletLaunchableEvent(std::make_shared<type::KEvent>(state, false)), accumulatedSuspendedTickChangedEvent(std::make_shared<type::KEvent>(state, false)), BaseService(state, manager) {}
Result ISelfController::LockExit(type::KSession &session, ipc::IpcRequest &request, ipc::IpcResponse &response) { Result ISelfController::LockExit(type::KSession &session, ipc::IpcRequest &request, ipc::IpcResponse &response) {
return {}; return {};

View File

@ -6,7 +6,7 @@
#include "IAudioDevice.h" #include "IAudioDevice.h"
namespace skyline::service::audio { namespace skyline::service::audio {
IAudioDevice::IAudioDevice(const DeviceState &state, ServiceManager &manager) : systemEvent(std::make_shared<type::KEvent>(state)), BaseService(state, manager) {} IAudioDevice::IAudioDevice(const DeviceState &state, ServiceManager &manager) : systemEvent(std::make_shared<type::KEvent>(state, true)), BaseService(state, manager) {}
Result IAudioDevice::ListAudioDeviceName(type::KSession &session, ipc::IpcRequest &request, ipc::IpcResponse &response) { Result IAudioDevice::ListAudioDeviceName(type::KSession &session, ipc::IpcRequest &request, ipc::IpcResponse &response) {
span buffer{request.outputBuf.at(0)}; span buffer{request.outputBuf.at(0)};

View File

@ -5,7 +5,7 @@
#include "IAudioOut.h" #include "IAudioOut.h"
namespace skyline::service::audio { namespace skyline::service::audio {
IAudioOut::IAudioOut(const DeviceState &state, ServiceManager &manager, u8 channelCount, u32 sampleRate) : sampleRate(sampleRate), channelCount(channelCount), releaseEvent(std::make_shared<type::KEvent>(state)), BaseService(state, manager) { IAudioOut::IAudioOut(const DeviceState &state, ServiceManager &manager, u8 channelCount, u32 sampleRate) : sampleRate(sampleRate), channelCount(channelCount), releaseEvent(std::make_shared<type::KEvent>(state, false)), BaseService(state, manager) {
track = state.audio->OpenTrack(channelCount, constant::SampleRate, [this]() { this->releaseEvent->Signal(); }); track = state.audio->OpenTrack(channelCount, constant::SampleRate, [this]() { this->releaseEvent->Signal(); });
} }

View File

@ -6,7 +6,7 @@
namespace skyline::service::audio::IAudioRenderer { namespace skyline::service::audio::IAudioRenderer {
IAudioRenderer::IAudioRenderer(const DeviceState &state, ServiceManager &manager, AudioRendererParameters &parameters) IAudioRenderer::IAudioRenderer(const DeviceState &state, ServiceManager &manager, AudioRendererParameters &parameters)
: systemEvent(std::make_shared<type::KEvent>(state)), parameters(parameters), BaseService(state, manager) { : systemEvent(std::make_shared<type::KEvent>(state, true)), parameters(parameters), BaseService(state, manager) {
track = state.audio->OpenTrack(constant::ChannelCount, constant::SampleRate, []() {}); track = state.audio->OpenTrack(constant::ChannelCount, constant::SampleRate, []() {});
track->Start(); track->Start();

View File

@ -5,7 +5,7 @@
#include "INotificationService.h" #include "INotificationService.h"
namespace skyline::service::friends { namespace skyline::service::friends {
INotificationService::INotificationService(const DeviceState &state, ServiceManager &manager) : notificationEvent(std::make_shared<type::KEvent>(state)), BaseService(state, manager) {} INotificationService::INotificationService(const DeviceState &state, ServiceManager &manager) : notificationEvent(std::make_shared<type::KEvent>(state, false)), BaseService(state, manager) {}
Result INotificationService::GetEvent(type::KSession &session, ipc::IpcRequest &request, ipc::IpcResponse &response) { Result INotificationService::GetEvent(type::KSession &session, ipc::IpcRequest &request, ipc::IpcResponse &response) {
KHandle handle{state.process->InsertItem(notificationEvent)}; KHandle handle{state.process->InsertItem(notificationEvent)};

View File

@ -5,7 +5,7 @@
#include "IRequest.h" #include "IRequest.h"
namespace skyline::service::nifm { namespace skyline::service::nifm {
IRequest::IRequest(const DeviceState &state, ServiceManager &manager) : event0(std::make_shared<type::KEvent>(state)), event1(std::make_shared<type::KEvent>(state)), BaseService(state, manager) {} IRequest::IRequest(const DeviceState &state, ServiceManager &manager) : event0(std::make_shared<type::KEvent>(state, false)), event1(std::make_shared<type::KEvent>(state, false)), BaseService(state, manager) {}
Result IRequest::GetRequestState(type::KSession &session, ipc::IpcRequest &request, ipc::IpcResponse &response) { Result IRequest::GetRequestState(type::KSession &session, ipc::IpcRequest &request, ipc::IpcResponse &response) {
constexpr u32 Unsubmitted{1}; //!< The request has not been submitted constexpr u32 Unsubmitted{1}; //!< The request has not been submitted

View File

@ -7,7 +7,7 @@
#include "nvhost_channel.h" #include "nvhost_channel.h"
namespace skyline::service::nvdrv::device { namespace skyline::service::nvdrv::device {
NvHostChannel::NvHostChannel(const DeviceState &state) : smExceptionBreakpointIntReportEvent(std::make_shared<type::KEvent>(state)), smExceptionBreakpointPauseReportEvent(std::make_shared<type::KEvent>(state)), errorNotifierEvent(std::make_shared<type::KEvent>(state)), NvDevice(state) { NvHostChannel::NvHostChannel(const DeviceState &state) : smExceptionBreakpointIntReportEvent(std::make_shared<type::KEvent>(state, false)), smExceptionBreakpointPauseReportEvent(std::make_shared<type::KEvent>(state, false)), errorNotifierEvent(std::make_shared<type::KEvent>(state, false)), NvDevice(state) {
auto driver{nvdrv::driver.lock()}; auto driver{nvdrv::driver.lock()};
auto &hostSyncpoint{driver->hostSyncpoint}; auto &hostSyncpoint{driver->hostSyncpoint};

View File

@ -7,17 +7,17 @@
#include "nvhost_ctrl.h" #include "nvhost_ctrl.h"
namespace skyline::service::nvdrv::device { namespace skyline::service::nvdrv::device {
NvHostEvent::NvHostEvent(const DeviceState &state) : event(std::make_shared<type::KEvent>(state)) {} NvHostEvent::NvHostEvent(const DeviceState &state) : event(std::make_shared<type::KEvent>(state, false)) {}
void NvHostEvent::Signal() { void NvHostEvent::Signal() {
auto oldState{state}; auto oldState{state};
state = State::Signaling; state = State::Signalling;
// This is to ensure that the HOS event isn't signalled when the nvhost event is cancelled // This is to ensure that the HOS event isn't signalled when the nvhost event is cancelled
if (oldState == State::Waiting) if (oldState == State::Waiting)
event->Signal(); event->Signal();
state = State::Signaled; state = State::Signalled;
} }
void NvHostEvent::Cancel(const std::shared_ptr<gpu::GPU> &gpuState) { void NvHostEvent::Cancel(const std::shared_ptr<gpu::GPU> &gpuState) {
@ -46,7 +46,7 @@ namespace skyline::service::nvdrv::device {
if (events[i]) { if (events[i]) {
const auto &event{*events[i]}; const auto &event{*events[i]};
if (event.state == NvHostEvent::State::Cancelled || event.state == NvHostEvent::State::Available || event.state == NvHostEvent::State::Signaled) { if (event.state == NvHostEvent::State::Cancelled || event.state == NvHostEvent::State::Available || event.state == NvHostEvent::State::Signalled) {
eventIndex = i; eventIndex = i;
// This event is already attached to the requested syncpoint, so use it // This event is already attached to the requested syncpoint, so use it
@ -113,7 +113,7 @@ namespace skyline::service::nvdrv::device {
} }
auto &event{*events.at(userEventId)}; auto &event{*events.at(userEventId)};
if (event.state == NvHostEvent::State::Cancelled || event.state == NvHostEvent::State::Available || event.state == NvHostEvent::State::Signaled) { if (event.state == NvHostEvent::State::Cancelled || event.state == NvHostEvent::State::Available || event.state == NvHostEvent::State::Signalled) {
state.logger->Debug("Waiting on nvhost event: {} with fence: {}", userEventId, data.fence.id); state.logger->Debug("Waiting on nvhost event: {} with fence: {}", userEventId, data.fence.id);
event.Wait(state.gpu, data.fence); event.Wait(state.gpu, data.fence);

View File

@ -26,8 +26,8 @@ namespace skyline {
Available = 0, Available = 0,
Waiting = 1, Waiting = 1,
Cancelling = 2, Cancelling = 2,
Signaling = 3, Signalling = 3,
Signaled = 4, Signalled = 4,
Cancelled = 5, Cancelled = 5,
}; };

View File

@ -4,7 +4,7 @@
#include "nvhost_ctrl_gpu.h" #include "nvhost_ctrl_gpu.h"
namespace skyline::service::nvdrv::device { namespace skyline::service::nvdrv::device {
NvHostCtrlGpu::NvHostCtrlGpu(const DeviceState &state) : errorNotifierEvent(std::make_shared<type::KEvent>(state)), unknownEvent(std::make_shared<type::KEvent>(state)), NvDevice(state) {} NvHostCtrlGpu::NvHostCtrlGpu(const DeviceState &state) : errorNotifierEvent(std::make_shared<type::KEvent>(state, false)), unknownEvent(std::make_shared<type::KEvent>(state, false)), NvDevice(state) {}
NvStatus NvHostCtrlGpu::ZCullGetCtxSize(IoctlType type, span<u8> buffer, span<u8> inlineBuffer) { NvStatus NvHostCtrlGpu::ZCullGetCtxSize(IoctlType type, span<u8> buffer, span<u8> inlineBuffer) {
buffer.as<u32>() = 0x1; buffer.as<u32>() = 0x1;