mirror of
https://github.com/skyline-emu/skyline.git
synced 2024-12-28 07:15:30 +03:00
Improve Synchronization SVCs + Fix TLS Page Allocation Race + Fix KProcess::GetHandle<KObject>
This commit is contained in:
parent
ebadc1d1e1
commit
ef52e22cef
@ -48,6 +48,7 @@ add_library(skyline SHARED
|
||||
${source_DIR}/skyline/kernel/types/KThread.cpp
|
||||
${source_DIR}/skyline/kernel/types/KSharedMemory.cpp
|
||||
${source_DIR}/skyline/kernel/types/KPrivateMemory.cpp
|
||||
${source_DIR}/skyline/kernel/types/KSyncObject.cpp
|
||||
${source_DIR}/skyline/audio.cpp
|
||||
${source_DIR}/skyline/audio/track.cpp
|
||||
${source_DIR}/skyline/audio/resampler.cpp
|
||||
|
@ -9,9 +9,7 @@ extern skyline::u16 Fps;
|
||||
extern skyline::u32 FrameTime;
|
||||
|
||||
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)) {
|
||||
vsyncEvent->Signal();
|
||||
}
|
||||
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)) {}
|
||||
|
||||
PresentationEngine::~PresentationEngine() {
|
||||
if (window)
|
||||
|
@ -6,7 +6,7 @@
|
||||
#include "npad.h"
|
||||
|
||||
namespace skyline::input {
|
||||
NpadDevice::NpadDevice(NpadManager &manager, NpadSection §ion, NpadId id) : manager(manager), section(section), id(id), updateEvent(std::make_shared<kernel::type::KEvent>(manager.state)) {}
|
||||
NpadDevice::NpadDevice(NpadManager &manager, NpadSection §ion, NpadId id) : manager(manager), section(section), id(id), updateEvent(std::make_shared<kernel::type::KEvent>(manager.state, false)) {}
|
||||
|
||||
void NpadDevice::Connect(NpadControllerType newType) {
|
||||
if (type == newType) {
|
||||
|
@ -524,11 +524,8 @@ namespace skyline::kernel::svc {
|
||||
auto object{state.process->GetHandle(handle)};
|
||||
switch (object->objectType) {
|
||||
case type::KType::KEvent:
|
||||
std::static_pointer_cast<type::KEvent>(object)->ResetSignal();
|
||||
break;
|
||||
|
||||
case type::KType::KProcess:
|
||||
std::static_pointer_cast<type::KProcess>(object)->ResetSignal();
|
||||
std::static_pointer_cast<type::KSyncObject>(object)->ResetSignal();
|
||||
break;
|
||||
|
||||
default: {
|
||||
@ -552,17 +549,18 @@ namespace skyline::kernel::svc {
|
||||
|
||||
u32 numHandles{state.ctx->gpr.w2};
|
||||
if (numHandles > maxSyncHandles) {
|
||||
state.ctx->gpr.w0 = result::OutOfHandles;
|
||||
state.ctx->gpr.w0 = result::OutOfRange;
|
||||
return;
|
||||
}
|
||||
|
||||
std::string handleStr;
|
||||
std::vector<std::shared_ptr<type::KSyncObject>> objectTable;
|
||||
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) {
|
||||
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)};
|
||||
switch (object->objectType) {
|
||||
@ -574,46 +572,99 @@ namespace skyline::kernel::svc {
|
||||
break;
|
||||
|
||||
default: {
|
||||
state.logger->Debug("svcWaitSynchronization: An invalid handle was supplied: 0x{:X}", handle);
|
||||
state.ctx->gpr.w0 = result::InvalidHandle;
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
u64 timeout{state.ctx->gpr.x3};
|
||||
state.logger->Debug("svcWaitSynchronization: Waiting on handles:\n{}Timeout: 0x{:X} ns", handleStr, timeout);
|
||||
i64 timeout{static_cast<i64>(state.ctx->gpr.x3)};
|
||||
state.logger->Debug("svcWaitSynchronization: Waiting on handles:\n{}Timeout: {}ns", handleString, timeout);
|
||||
|
||||
SchedulerScopedLock schedulerLock(state);
|
||||
auto start{util::GetTimeNs()};
|
||||
while (true) {
|
||||
if (state.thread->cancelSync) {
|
||||
state.thread->cancelSync = false;
|
||||
state.ctx->gpr.w0 = result::Cancelled;
|
||||
std::unique_lock lock(type::KSyncObject::syncObjectMutex);
|
||||
if (state.thread->cancelSync) {
|
||||
state.thread->cancelSync = false;
|
||||
state.ctx->gpr.w0 = result::Cancelled;
|
||||
return;
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
index++;
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
index++;
|
||||
}
|
||||
if (timeout == 0) {
|
||||
state.logger->Debug("svcWaitSynchronization: No handle is currently signalled");
|
||||
state.ctx->gpr.w0 = result::TimedOut;
|
||||
return;
|
||||
}
|
||||
|
||||
if ((util::GetTimeNs() - start) >= timeout) {
|
||||
state.logger->Debug("svcWaitSynchronization: Wait has timed out");
|
||||
state.ctx->gpr.w0 = result::TimedOut;
|
||||
return;
|
||||
}
|
||||
auto priority{state.thread->priority.load()};
|
||||
for (const auto &object : objectTable)
|
||||
object->syncObjectWaiters.insert(std::upper_bound(object->syncObjectWaiters.begin(), object->syncObjectWaiters.end(), priority, type::KThread::IsHigherPriority), state.thread);
|
||||
|
||||
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) {
|
||||
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 &) {
|
||||
state.logger->Warn("svcCancelSynchronization: 'handle' invalid: 0x{:X}", static_cast<u32>(state.ctx->gpr.w0));
|
||||
state.ctx->gpr.w0 = result::InvalidHandle;
|
||||
@ -878,7 +929,7 @@ namespace skyline::kernel::svc {
|
||||
break;
|
||||
|
||||
case InfoState::UserExceptionContextAddr:
|
||||
out = reinterpret_cast<u64>(state.process->tlsPages[0]->Get(0));
|
||||
out = reinterpret_cast<u64>(state.process->tlsExceptionContext);
|
||||
break;
|
||||
|
||||
default:
|
||||
|
@ -12,13 +12,9 @@ namespace skyline::kernel::type {
|
||||
*/
|
||||
class KEvent : public KSyncObject {
|
||||
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() {
|
||||
signalled = false;
|
||||
}
|
||||
KEvent(const DeviceState &state, bool presignalled) : KSyncObject(state, KType::KEvent, presignalled) {}
|
||||
};
|
||||
}
|
||||
|
@ -10,19 +10,9 @@ namespace skyline::kernel::type {
|
||||
KProcess::TlsPage::TlsPage(const std::shared_ptr<KPrivateMemory> &memory) : memory(memory) {}
|
||||
|
||||
u8 *KProcess::TlsPage::ReserveSlot() {
|
||||
if (Full())
|
||||
throw exception("Trying to reserve TLS slot in full page");
|
||||
return Get(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;
|
||||
if (index == constant::TlsSlots)
|
||||
return nullptr;
|
||||
return memory->ptr + (constant::TlsSlotSize * index++);
|
||||
}
|
||||
|
||||
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};
|
||||
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
|
||||
tlsExceptionContext = AllocateTlsSlot();
|
||||
}
|
||||
|
||||
u8 *KProcess::AllocateTlsSlot() {
|
||||
std::lock_guard lock(tlsMutex);
|
||||
u8 *slot;
|
||||
for (auto &tlsPage: tlsPages)
|
||||
if (!tlsPage->Full())
|
||||
return tlsPage->ReserveSlot();
|
||||
if ((slot = tlsPage->ReserveSlot()))
|
||||
return slot;
|
||||
|
||||
u8 *ptr = tlsPages.empty() ? reinterpret_cast<u8 *>(state.process->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))};
|
||||
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, slot, PAGE_SIZE, memory::Permission(true, true, false), memory::states::ThreadLocal))};
|
||||
tlsPages.push_back(tlsPage);
|
||||
|
||||
tlsPage->ReserveSlot(); // User-mode exception handling
|
||||
return tlsPage->ReserveSlot();
|
||||
}
|
||||
|
||||
|
@ -3,7 +3,6 @@
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <list>
|
||||
#include <vfs/npdm.h>
|
||||
#include "KThread.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
|
||||
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
|
||||
SyncWaiters syncWaiters; //!< All threads waiting on process-wide synchronization primitives (Atomic keys + Address Arbiter)
|
||||
|
||||
@ -42,21 +41,23 @@ namespace skyline {
|
||||
*/
|
||||
struct TlsPage {
|
||||
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);
|
||||
|
||||
/**
|
||||
* @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 *Get(u8 slot);
|
||||
|
||||
bool Full();
|
||||
};
|
||||
|
||||
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::vector<std::shared_ptr<TlsPage>> tlsPages;
|
||||
vfs::NPDM npdm;
|
||||
|
||||
private:
|
||||
@ -79,9 +80,10 @@ namespace skyline {
|
||||
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
|
||||
*/
|
||||
void InitializeHeap();
|
||||
void InitializeHeapTls();
|
||||
|
||||
/**
|
||||
* @return A 0x200 TLS slot allocated inside the TLS/IO region
|
||||
@ -177,7 +179,12 @@ namespace skyline {
|
||||
|
||||
template<>
|
||||
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
|
||||
*/
|
||||
void ConditionalVariableSignal(u32 *key, u64 amount);
|
||||
|
||||
/**
|
||||
* @brief Resets the object to an unsignalled state
|
||||
*/
|
||||
inline void ResetSignal() {
|
||||
signalled = false;
|
||||
}
|
||||
};
|
||||
}
|
||||
}
|
||||
|
19
app/src/main/cpp/skyline/kernel/types/KSyncObject.cpp
Normal file
19
app/src/main/cpp/skyline/kernel/types/KSyncObject.cpp
Normal 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);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@ -7,19 +7,31 @@
|
||||
|
||||
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 {
|
||||
public:
|
||||
std::atomic<bool> signalled{false}; //!< If the current object is signalled (Used as object stays signalled till the signal is consumed)
|
||||
|
||||
KSyncObject(const DeviceState &state, skyline::kernel::type::KType type) : KObject(state, type) {};
|
||||
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
|
||||
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() {
|
||||
signalled = true;
|
||||
KSyncObject(const DeviceState &state, skyline::kernel::type::KType type, bool presignalled = false) : KObject(state, type), signalled(presignalled) {};
|
||||
|
||||
/**
|
||||
* @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;
|
||||
|
@ -3,7 +3,6 @@
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <list>
|
||||
#include <csetjmp>
|
||||
#include <nce/guest.h>
|
||||
#include <kernel/scheduler.h>
|
||||
@ -27,7 +26,7 @@ namespace skyline {
|
||||
public:
|
||||
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
|
||||
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;
|
||||
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
|
||||
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
|
||||
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);
|
||||
|
||||
|
@ -36,7 +36,7 @@ namespace skyline::kernel {
|
||||
auto &process{state.process};
|
||||
process = std::make_shared<kernel::type::KProcess>(state);
|
||||
auto entry{state.loader->LoadProcessData(process, state)};
|
||||
process->InitializeHeap();
|
||||
process->InitializeHeapTls();
|
||||
auto thread{process->CreateThread(entry)};
|
||||
if (thread) {
|
||||
state.logger->Debug("Starting main HOS thread");
|
||||
|
@ -7,7 +7,7 @@
|
||||
#include "ILibraryAppletAccessor.h"
|
||||
|
||||
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) {
|
||||
stateChangeEvent->Signal();
|
||||
|
@ -7,7 +7,7 @@
|
||||
#include "IApplicationFunctions.h"
|
||||
|
||||
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) {
|
||||
constexpr u32 LaunchParameterMagic{0xC79497CA}; //!< The magic of the application launch parameters
|
||||
|
@ -11,7 +11,7 @@ namespace skyline::service::am {
|
||||
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"));
|
||||
state.logger->Info("Switch to mode: {}", static_cast<bool>(operationMode) ? "Docked" : "Handheld");
|
||||
QueueMessage(Message::FocusStateChange);
|
||||
|
@ -6,7 +6,7 @@
|
||||
#include "ISelfController.h"
|
||||
|
||||
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) {
|
||||
return {};
|
||||
|
@ -6,7 +6,7 @@
|
||||
#include "IAudioDevice.h"
|
||||
|
||||
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) {
|
||||
span buffer{request.outputBuf.at(0)};
|
||||
|
@ -5,7 +5,7 @@
|
||||
#include "IAudioOut.h"
|
||||
|
||||
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(); });
|
||||
}
|
||||
|
||||
|
@ -6,7 +6,7 @@
|
||||
|
||||
namespace skyline::service::audio::IAudioRenderer {
|
||||
IAudioRenderer::IAudioRenderer(const DeviceState &state, ServiceManager &manager, AudioRendererParameters ¶meters)
|
||||
: 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->Start();
|
||||
|
||||
|
@ -5,7 +5,7 @@
|
||||
#include "INotificationService.h"
|
||||
|
||||
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) {
|
||||
KHandle handle{state.process->InsertItem(notificationEvent)};
|
||||
|
@ -5,7 +5,7 @@
|
||||
#include "IRequest.h"
|
||||
|
||||
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) {
|
||||
constexpr u32 Unsubmitted{1}; //!< The request has not been submitted
|
||||
|
@ -7,7 +7,7 @@
|
||||
#include "nvhost_channel.h"
|
||||
|
||||
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 &hostSyncpoint{driver->hostSyncpoint};
|
||||
|
||||
|
@ -7,17 +7,17 @@
|
||||
#include "nvhost_ctrl.h"
|
||||
|
||||
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() {
|
||||
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
|
||||
if (oldState == State::Waiting)
|
||||
event->Signal();
|
||||
|
||||
state = State::Signaled;
|
||||
state = State::Signalled;
|
||||
}
|
||||
|
||||
void NvHostEvent::Cancel(const std::shared_ptr<gpu::GPU> &gpuState) {
|
||||
@ -46,7 +46,7 @@ namespace skyline::service::nvdrv::device {
|
||||
if (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;
|
||||
|
||||
// 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)};
|
||||
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);
|
||||
event.Wait(state.gpu, data.fence);
|
||||
|
||||
|
@ -26,8 +26,8 @@ namespace skyline {
|
||||
Available = 0,
|
||||
Waiting = 1,
|
||||
Cancelling = 2,
|
||||
Signaling = 3,
|
||||
Signaled = 4,
|
||||
Signalling = 3,
|
||||
Signalled = 4,
|
||||
Cancelled = 5,
|
||||
};
|
||||
|
||||
|
@ -4,7 +4,7 @@
|
||||
#include "nvhost_ctrl_gpu.h"
|
||||
|
||||
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) {
|
||||
buffer.as<u32>() = 0x1;
|
||||
|
Loading…
Reference in New Issue
Block a user