/** ****************************************************************************** * Xenia : Xbox 360 Emulator Research Project * ****************************************************************************** * Copyright 2022 Ben Vanik. All rights reserved. * * Released under the BSD license - see LICENSE in the root for more details. * ****************************************************************************** * * @modified Tom Clay, 2026 - Adapted for ReXGlue runtime */ #include #include #include namespace rex::system { XEvent::XEvent(KernelState* kernel_state) : XObject(kernel_state, kObjectType) {} XEvent::~XEvent() = default; void XEvent::Initialize(bool manual_reset, bool initial_state) { assert_false(event_); this->CreateNative(); if (manual_reset) { event_ = rex::thread::Event::CreateManualResetEvent(initial_state); } else { event_ = rex::thread::Event::CreateAutoResetEvent(initial_state); } assert_not_null(event_); } void XEvent::InitializeNative(void* native_ptr, X_DISPATCH_HEADER* header) { assert_false(event_); switch (header->type) { case 0x00: // EventNotificationObject (manual reset) manual_reset_ = true; break; case 0x01: // EventSynchronizationObject (auto reset) manual_reset_ = false; break; default: assert_always(); return; } bool initial_state = header->signal_state ? true : false; if (manual_reset_) { event_ = rex::thread::Event::CreateManualResetEvent(initial_state); } else { event_ = rex::thread::Event::CreateAutoResetEvent(initial_state); } assert_not_null(event_); } void XEvent::Query(uint32_t* out_type, uint32_t* out_state) { if (out_type) { *out_type = manual_reset_ ? 0x00 : 0x01; } if (out_state) { // Query the live host event, not the stale guest header auto result = rex::thread::Wait(event_.get(), false, std::chrono::milliseconds(0)); if (result == rex::thread::WaitResult::kSuccess) { *out_state = 1; // Re-signal since we consumed the signal by waiting event_->Set(); } else { *out_state = 0; } } } int32_t XEvent::Set(uint32_t priority_increment, bool wait) { event_->Set(); return 1; } int32_t XEvent::Pulse(uint32_t priority_increment, bool wait) { event_->Pulse(); return 1; } int32_t XEvent::Reset() { event_->Reset(); return 1; } void XEvent::Clear() { event_->Reset(); } bool XEvent::Save(stream::ByteStream* stream) { REXSYS_DEBUG("XEvent {:08X} ({})", handle(), manual_reset_ ? "manual" : "auto"); SaveObject(stream); bool signaled = true; auto result = rex::thread::Wait(event_.get(), false, std::chrono::milliseconds(0)); if (result == rex::thread::WaitResult::kSuccess) { signaled = true; } else if (result == rex::thread::WaitResult::kTimeout) { signaled = false; } else { assert_always(); } if (signaled) { // Reset the event in-case it's an auto-reset. event_->Set(); } stream->Write(signaled); stream->Write(manual_reset_); return true; } object_ref XEvent::Restore(KernelState* kernel_state, stream::ByteStream* stream) { auto evt = new XEvent(nullptr); evt->kernel_state_ = kernel_state; evt->RestoreObject(stream); bool signaled = stream->Read(); evt->manual_reset_ = stream->Read(); if (evt->manual_reset_) { evt->event_ = rex::thread::Event::CreateManualResetEvent(false); } else { evt->event_ = rex::thread::Event::CreateAutoResetEvent(false); } assert_not_null(evt->event_); if (signaled) { evt->event_->Set(); } return object_ref(evt); } } // namespace rex::system