diff --git a/src/core/hle/kernel/event.cpp b/src/core/hle/kernel/event.cpp index 1489c7002..eac2dfa8b 100644 --- a/src/core/hle/kernel/event.cpp +++ b/src/core/hle/kernel/event.cpp @@ -3,15 +3,23 @@ // Refer to the license.txt file included. #include +#include #include #include #include "common/assert.h" +#include "core/core_timing.h" #include "core/hle/kernel/event.h" #include "core/hle/kernel/kernel.h" #include "core/hle/kernel/thread.h" namespace Kernel { +/// The event type of the generic event callback +static int event_callback_event_type; +// TODO(yuriks): This can be removed if Event objects are explicitly pooled in the future, allowing +// us to simply use a pool index or similar. +static Kernel::HandleTable event_callback_handle_table; + Event::Event() {} Event::~Event() {} @@ -21,6 +29,7 @@ SharedPtr Event::Create(ResetType reset_type, std::string name) { evt->signaled = false; evt->reset_type = reset_type; evt->name = std::move(name); + evt->callback_handle = event_callback_handle_table.Create(evt).MoveFrom(); return evt; } @@ -37,6 +46,16 @@ void Event::Acquire() { signaled = false; } +void Event::Delay(u64 delay) { + // Ensure we get rid of any previous scheduled event + Cancel(); + + u64 microseconds = delay / 1000; + CoreTiming::ScheduleEvent(usToCycles(microseconds), event_callback_event_type, callback_handle); + + HLE::Reschedule(__func__); +} + void Event::Signal() { signaled = true; WakeupAllWaitingThreads(); @@ -46,4 +65,35 @@ void Event::Clear() { signaled = false; } +void Event::Cancel() { + CoreTiming::UnscheduleEvent(event_callback_event_type, callback_handle); + + HLE::Reschedule(__func__); +} + +/// The event callback event +static void EventCallback(u64 event_handle, int /*cycles_late*/) { + SharedPtr event = + event_callback_handle_table.Get(static_cast(event_handle)); + + if (event == nullptr) { + LOG_CRITICAL(Kernel, "Callback fired for invalid event %08" PRIx64, event_handle); + return; + } + + LOG_TRACE(Kernel, "Event %08" PRIx64 " signaled", event_handle); + + event->signaled = true; + + // Resume all waiting threads + event->WakeupAllWaitingThreads(); +} + +void EventsInit() { + event_callback_handle_table.Clear(); + event_callback_event_type = CoreTiming::RegisterEvent("EventCallback", EventCallback); +} + +void EventsShutdown() {} + } // namespace diff --git a/src/core/hle/kernel/event.h b/src/core/hle/kernel/event.h index 8dcd23edb..bc5f3b46f 100644 --- a/src/core/hle/kernel/event.h +++ b/src/core/hle/kernel/event.h @@ -38,12 +38,22 @@ public: bool ShouldWait() override; void Acquire() override; + void Delay(u64 delay); void Signal(); void Clear(); + void Cancel(); private: Event(); ~Event() override; + + /// Handle used as userdata to reference this object when inserting into the CoreTiming queue. + Handle callback_handle; }; +/// Initializes the required variables for events +void EventsInit(); +/// Tears down the event variables +void EventsShutdown(); + } // namespace diff --git a/src/core/hle/kernel/kernel.cpp b/src/core/hle/kernel/kernel.cpp index 9e1795927..118a4b74f 100644 --- a/src/core/hle/kernel/kernel.cpp +++ b/src/core/hle/kernel/kernel.cpp @@ -6,6 +6,7 @@ #include "common/assert.h" #include "common/logging/log.h" #include "core/hle/config_mem.h" +#include "core/hle/kernel/event.h" #include "core/hle/kernel/kernel.h" #include "core/hle/kernel/memory.h" #include "core/hle/kernel/process.h" @@ -135,6 +136,7 @@ void Init() { Kernel::ResourceLimitsInit(); Kernel::ThreadingInit(); Kernel::TimersInit(); + Kernel::EventsInit(); Object::next_object_id = 0; // TODO(Subv): Start the process ids from 10 for now, as lower PIDs are @@ -149,6 +151,7 @@ void Shutdown() { Kernel::ThreadingShutdown(); g_current_process = nullptr; + Kernel::EventsShutdown(); Kernel::TimersShutdown(); Kernel::ResourceLimitsShutdown(); Kernel::MemoryShutdown(); diff --git a/src/core/hle/service/y2r_u.cpp b/src/core/hle/service/y2r_u.cpp index 097e09d28..8ef4ffcca 100644 --- a/src/core/hle/service/y2r_u.cpp +++ b/src/core/hle/service/y2r_u.cpp @@ -247,7 +247,7 @@ static void SetTransferEndInterrupt(Service::Interface* self) { cmd_buff[0] = IPC::MakeHeader(0xD, 1, 0); cmd_buff[1] = RESULT_SUCCESS.raw; - LOG_WARNING(Service_Y2R, "(STUBBED) called"); + LOG_WARNING(Service_Y2R, "(STUBBED) called, enabled = %u", transfer_end_interrupt_enabled); } /** @@ -591,7 +591,7 @@ static void StartConversion(Service::Interface* self) { HW::Y2R::PerformConversion(conversion); - completion_event->Signal(); + completion_event->Delay(1000); cmd_buff[0] = IPC::MakeHeader(0x26, 1, 0); cmd_buff[1] = RESULT_SUCCESS.raw;