rexglue-skate3/src/system/xevent.cpp
2026-05-18 22:41:13 +01:00

142 lines
3.7 KiB
C++

/**
******************************************************************************
* 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 <rex/logging.h>
#include <rex/stream.h>
#include <rex/system/xevent.h>
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<X_KEVENT>();
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<bool>(signaled);
stream->Write<bool>(manual_reset_);
return true;
}
object_ref<XEvent> 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<bool>();
evt->manual_reset_ = stream->Read<bool>();
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<XEvent>(evt);
}
} // namespace rex::system