diff --git a/src/xenia/apu/audio_system.cc b/src/xenia/apu/audio_system.cc index e47bcb75e..4e6f82604 100644 --- a/src/xenia/apu/audio_system.cc +++ b/src/xenia/apu/audio_system.cc @@ -104,15 +104,22 @@ X_STATUS AudioSystem::Setup() { // Threads worker_running_ = true; - worker_thread_ = new kernel::XHostThread(emulator()->kernel_state(), - 128 * 1024, 0, [this]() { - this->WorkerThreadMain(); - return 0; - }); + worker_thread_ = + kernel::object_ref(new kernel::XHostThread( + emulator()->kernel_state(), 128 * 1024, 0, [this]() { + this->WorkerThreadMain(); + return 0; + })); worker_thread_->Create(); decoder_running_ = true; - decoder_thread_ = std::thread(std::bind(&AudioSystem::DecoderThreadMain, this)); + decoder_thread_ = + kernel::object_ref(new kernel::XHostThread( + emulator()->kernel_state(), 128 * 1024, 0, [this]() { + DecoderThreadMain(); + return 0; + })); + decoder_thread_->Create(); return X_STATUS_SUCCESS; } @@ -173,7 +180,6 @@ void AudioSystem::WorkerThreadMain() { void AudioSystem::DecoderThreadMain() { xe::threading::set_name("Audio Decoder"); - xe::Profiler::ThreadEnter("Audio Decoder"); while (decoder_running_) { // Wait for the fence @@ -315,8 +321,6 @@ void AudioSystem::DecoderThreadMain() { context.lock.unlock(); } } - - xe::Profiler::ThreadExit(); } void AudioSystem::Initialize() {} @@ -325,10 +329,11 @@ void AudioSystem::Shutdown() { worker_running_ = false; SetEvent(client_wait_handles_[maximum_client_count_]); worker_thread_->Wait(0, 0, 0, nullptr); - worker_thread_->Release(); + worker_thread_.reset(); decoder_running_ = false; decoder_fence_.Signal(); + worker_thread_.reset(); memory()->SystemHeapFree(registers_.xma_context_array_ptr); } diff --git a/src/xenia/apu/audio_system.h b/src/xenia/apu/audio_system.h index 27c748093..f27abb043 100644 --- a/src/xenia/apu/audio_system.h +++ b/src/xenia/apu/audio_system.h @@ -160,10 +160,10 @@ class AudioSystem { cpu::Processor* processor_; std::atomic worker_running_; - kernel::XHostThread* worker_thread_; + kernel::object_ref worker_thread_; std::atomic decoder_running_; - std::thread decoder_thread_; + kernel::object_ref decoder_thread_; xe::threading::Fence decoder_fence_; std::mutex lock_; diff --git a/src/xenia/gpu/gl4/command_processor.cc b/src/xenia/gpu/gl4/command_processor.cc index 4ac0206b4..1a52682fa 100644 --- a/src/xenia/gpu/gl4/command_processor.cc +++ b/src/xenia/gpu/gl4/command_processor.cc @@ -101,11 +101,12 @@ bool CommandProcessor::Initialize(std::unique_ptr context) { context_ = std::move(context); worker_running_ = true; - worker_thread_ = new kernel::XHostThread( - graphics_system_->emulator()->kernel_state(), 128 * 1024, 0, [this]() { + worker_thread_ = kernel::object_ref( + new kernel::XHostThread(graphics_system_->emulator()->kernel_state(), + 128 * 1024, 0, [this]() { WorkerThreadMain(); return 0; - }); + })); worker_thread_->Create(); return true; @@ -117,7 +118,7 @@ void CommandProcessor::Shutdown() { worker_running_ = false; SetEvent(write_ptr_index_event_); worker_thread_->Wait(0, 0, 0, nullptr); - worker_thread_->Release(); + worker_thread_.reset(); all_pipelines_.clear(); all_shaders_.clear(); @@ -163,7 +164,7 @@ void CommandProcessor::EndTracing() { void CommandProcessor::CallInThread(std::function fn) { if (pending_fns_.empty() && - worker_thread_ == kernel::XThread::GetCurrentThread()) { + worker_thread_.get() == kernel::XThread::GetCurrentThread()) { fn(); } else { pending_fns_.push(std::move(fn)); diff --git a/src/xenia/gpu/gl4/command_processor.h b/src/xenia/gpu/gl4/command_processor.h index db96a2e9a..fe045bf13 100644 --- a/src/xenia/gpu/gl4/command_processor.h +++ b/src/xenia/gpu/gl4/command_processor.h @@ -233,7 +233,7 @@ class CommandProcessor { std::wstring trace_frame_path_; std::atomic worker_running_; - kernel::XHostThread* worker_thread_; + kernel::object_ref worker_thread_; std::unique_ptr context_; SwapHandler swap_handler_; diff --git a/src/xenia/kernel/objects/xthread.cc b/src/xenia/kernel/objects/xthread.cc index 7bdc71a13..8ff3e637a 100644 --- a/src/xenia/kernel/objects/xthread.cc +++ b/src/xenia/kernel/objects/xthread.cc @@ -45,7 +45,6 @@ XThread::XThread(KernelState* kernel_state, uint32_t stack_size, pcr_address_(0), thread_state_address_(0), thread_state_(0), - event_(NULL), irql_(0) { creation_params_.stack_size = stack_size; creation_params_.xapi_thread_startup = xapi_thread_startup; @@ -63,7 +62,7 @@ XThread::XThread(KernelState* kernel_state, uint32_t stack_size, apc_list_ = new NativeList(kernel_state->memory()); - event_ = new XEvent(kernel_state); + event_ = object_ref(new XEvent(kernel_state)); event_->Initialize(true, false); // The kernel does not take a reference. We must unregister in the dtor. @@ -76,7 +75,7 @@ XThread::~XThread() { delete apc_list_; - event_->Release(); + event_.reset(); PlatformDestroy(); @@ -294,13 +293,12 @@ X_STATUS XThread::Exit(int exit_code) { #if XE_PLATFORM_WIN32 static uint32_t __stdcall XThreadStartCallbackWin32(void* param) { - XThread* thread = reinterpret_cast(param); + auto thread = object_ref(reinterpret_cast(param)); thread->set_name(thread->name()); xe::Profiler::ThreadEnter(thread->name().c_str()); - current_thread_tls = thread; + current_thread_tls = thread.get(); thread->Execute(); current_thread_tls = nullptr; - thread->Release(); xe::Profiler::ThreadExit(); return 0; } @@ -339,12 +337,11 @@ X_STATUS XThread::PlatformExit(int exit_code) { #else static void* XThreadStartCallbackPthreads(void* param) { - XThread* thread = reinterpret_cast(param); + auto thread = object_ref(reinterpret_cast(param)); xe::Profiler::ThreadEnter(thread->name().c_str()); - current_thread_tls = thread; + current_thread_tls = thread.get(); thread->Execute(); current_thread_tls = nullptr; - thread->Release(); xe::Profiler::ThreadExit(); return 0; } diff --git a/src/xenia/kernel/objects/xthread.h b/src/xenia/kernel/objects/xthread.h index 481ecb26f..bc7c2a701 100644 --- a/src/xenia/kernel/objects/xthread.h +++ b/src/xenia/kernel/objects/xthread.h @@ -100,7 +100,7 @@ class XThread : public XObject { std::mutex apc_lock_; NativeList* apc_list_; - XEvent* event_; + object_ref event_; }; class XHostThread : public XThread { diff --git a/src/xenia/kernel/xobject.h b/src/xenia/kernel/xobject.h index 00fdafc5b..b94fc6b39 100644 --- a/src/xenia/kernel/xobject.h +++ b/src/xenia/kernel/xobject.h @@ -24,6 +24,9 @@ namespace kernel { class KernelState; +template +class object_ref; + // http://www.nirsoft.net/kernel_struct/vista/DISPATCHER_HEADER.html typedef struct { xe::be type_flags; @@ -99,6 +102,124 @@ class XObject { std::string name_; // May be zero length. }; +template +class object_ref { + public: + object_ref() noexcept : value_(nullptr) {} + object_ref(nullptr_t) noexcept : value_(nullptr) {} + object_ref& operator=(nullptr_t) noexcept { + reset(); + return (*this); + } + + explicit object_ref(T* value) noexcept : value_(value) { + // Assumes retained on call. + } + explicit object_ref(const object_ref& right) noexcept { + reset(right.get()); + if (value_) value_->Retain(); + } + template ::value, void>::type> + object_ref(const object_ref& right) noexcept { + reset(right.get()); + if (value_) value_->Retain(); + } + + object_ref(object_ref&& right) noexcept : value_(right.release()) {} + object_ref& operator=(object_ref&& right) noexcept { + object_ref(std::move(right)).swap(*this); + return (*this); + } + template + object_ref& operator=(object_ref&& right) noexcept { + object_ref(std::move(right)).swap(*this); + return (*this); + } + + object_ref& operator=(const object_ref& right) noexcept { + object_ref(right).swap(*this); + return (*this); + } + template + object_ref& operator=(const object_ref& right) noexcept { + object_ref(right).swap(*this); + return (*this); + } + + void swap(object_ref& right) noexcept { + std::_Swap_adl(value_, right.value_); + } + + ~object_ref() noexcept { + if (value_) { + value_->Release(); + value_ = nullptr; + } + } + + typename std::add_lvalue_reference::type operator*() const { + return (*get()); + } + + T* operator->() const noexcept { + return std::pointer_traits::pointer_to(**this); + } + + T* get() const noexcept { return value_; } + + template + V* get() const noexcept { + return reinterpret_cast(value_); + } + + explicit operator bool() const noexcept { return value_ != nullptr; } + + T* release() noexcept { + T* value = value_; + value_ = nullptr; + return value; + } + + static void accept(T* value) { + reset(value); + value->Release(); + } + + void reset() noexcept { object_ref().swap(*this); } + + void reset(T* value) noexcept { object_ref(value).swap(*this); } + + private: + T* value_ = nullptr; +}; + +template +bool operator==(const object_ref<_Ty>& _Left, nullptr_t) noexcept { + return (_Left.get() == (_Ty*)0); +} + +template +bool operator==(nullptr_t, const object_ref<_Ty>& _Right) noexcept { + return ((_Ty*)0 == _Right.get()); +} + +template +bool operator!=(const object_ref<_Ty>& _Left, nullptr_t _Right) noexcept { + return (!(_Left == _Right)); +} + +template +bool operator!=(nullptr_t _Left, const object_ref<_Ty>& _Right) noexcept { + return (!(_Left == _Right)); +} + +template +object_ref retain_object(T* ptr) { + if (ptr) ptr->Retain(); + return object_ref(ptr); +} + } // namespace kernel } // namespace xe