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/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

View File

@ -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)

View File

@ -6,7 +6,7 @@
#include "npad.h"
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) {
if (type == newType) {

View File

@ -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:

View File

@ -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) {}
};
}

View File

@ -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();
}

View File

@ -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;
}
};
}
}

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 {
/**
* @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;

View File

@ -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);

View File

@ -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");

View File

@ -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();

View File

@ -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

View File

@ -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);

View File

@ -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 {};

View File

@ -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)};

View File

@ -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(); });
}

View File

@ -6,7 +6,7 @@
namespace skyline::service::audio::IAudioRenderer {
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->Start();

View File

@ -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)};

View File

@ -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

View File

@ -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};

View File

@ -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);

View File

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

View File

@ -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;