Switching audio system to platform-agnostic primitives.
This commit is contained in:
parent
345fe60da0
commit
a6012b73f4
|
@ -73,19 +73,14 @@ AudioSystem::AudioSystem(Emulator* emulator)
|
|||
}
|
||||
for (size_t i = 0; i < kMaximumClientCount; ++i) {
|
||||
client_semaphores_[i] =
|
||||
CreateSemaphore(NULL, 0, kMaximumQueuedFrames, NULL);
|
||||
wait_handles_[i] = client_semaphores_[i];
|
||||
xe::threading::Semaphore::Create(0, kMaximumQueuedFrames);
|
||||
wait_handles_[i] = client_semaphores_[i].get();
|
||||
}
|
||||
shutdown_event_ = CreateEvent(NULL, TRUE, FALSE, NULL);
|
||||
wait_handles_[kMaximumClientCount] = shutdown_event_;
|
||||
shutdown_event_ = xe::threading::Event::CreateManualResetEvent(false);
|
||||
wait_handles_[kMaximumClientCount] = shutdown_event_.get();
|
||||
}
|
||||
|
||||
AudioSystem::~AudioSystem() {
|
||||
for (size_t i = 0; i < kMaximumClientCount; ++i) {
|
||||
CloseHandle(client_semaphores_[i]);
|
||||
}
|
||||
CloseHandle(shutdown_event_);
|
||||
}
|
||||
AudioSystem::~AudioSystem() = default;
|
||||
|
||||
X_STATUS AudioSystem::Setup() {
|
||||
processor_ = emulator_->processor();
|
||||
|
@ -111,18 +106,17 @@ void AudioSystem::WorkerThreadMain() {
|
|||
|
||||
// Main run loop.
|
||||
while (worker_running_) {
|
||||
auto result =
|
||||
WaitForMultipleObjectsEx(DWORD(xe::countof(wait_handles_)),
|
||||
wait_handles_, FALSE, INFINITE, FALSE);
|
||||
if (result == WAIT_FAILED ||
|
||||
result == WAIT_OBJECT_0 + kMaximumClientCount) {
|
||||
auto result = xe::threading::WaitAny(
|
||||
wait_handles_, DWORD(xe::countof(wait_handles_)), true);
|
||||
if (result.first == xe::threading::WaitResult::kFailed ||
|
||||
(result.first == xe::threading::WaitResult::kSuccess &&
|
||||
result.second == kMaximumClientCount)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
size_t pumped = 0;
|
||||
if (result >= WAIT_OBJECT_0 &&
|
||||
result <= WAIT_OBJECT_0 + (kMaximumClientCount - 1)) {
|
||||
size_t index = result - WAIT_OBJECT_0;
|
||||
if (result.first == xe::threading::WaitResult::kSuccess) {
|
||||
size_t index = result.second;
|
||||
do {
|
||||
lock_.lock();
|
||||
uint32_t client_callback = clients_[index].callback;
|
||||
|
@ -138,8 +132,9 @@ void AudioSystem::WorkerThreadMain() {
|
|||
pumped++;
|
||||
index++;
|
||||
} while (index < kMaximumClientCount &&
|
||||
WaitForSingleObject(client_semaphores_[index], 0) ==
|
||||
WAIT_OBJECT_0);
|
||||
xe::threading::Wait(client_semaphores_[index].get(), false,
|
||||
std::chrono::milliseconds(0)) ==
|
||||
xe::threading::WaitResult::kSuccess);
|
||||
}
|
||||
|
||||
if (!worker_running_) {
|
||||
|
@ -160,7 +155,7 @@ void AudioSystem::Initialize() {}
|
|||
|
||||
void AudioSystem::Shutdown() {
|
||||
worker_running_ = false;
|
||||
SetEvent(shutdown_event_);
|
||||
shutdown_event_->Set();
|
||||
worker_thread_->Wait(0, 0, 0, nullptr);
|
||||
worker_thread_.reset();
|
||||
}
|
||||
|
@ -172,9 +167,9 @@ X_STATUS AudioSystem::RegisterClient(uint32_t callback, uint32_t callback_arg,
|
|||
|
||||
auto index = unused_clients_.front();
|
||||
|
||||
auto client_semaphore = client_semaphores_[index];
|
||||
BOOL ret = ReleaseSemaphore(client_semaphore, kMaximumQueuedFrames, NULL);
|
||||
assert_true(ret == TRUE);
|
||||
auto client_semaphore = client_semaphores_[index].get();
|
||||
auto ret = client_semaphore->Release(kMaximumQueuedFrames, nullptr);
|
||||
assert_true(ret);
|
||||
|
||||
AudioDriver* driver;
|
||||
auto result = CreateDriver(index, client_semaphore, &driver);
|
||||
|
@ -215,13 +210,14 @@ void AudioSystem::UnregisterClient(size_t index) {
|
|||
clients_[index] = {0};
|
||||
unused_clients_.push(index);
|
||||
|
||||
// drain the semaphore of its count
|
||||
auto client_semaphore = client_semaphores_[index];
|
||||
DWORD wait_result;
|
||||
// Drain the semaphore of its count.
|
||||
auto client_semaphore = client_semaphores_[index].get();
|
||||
xe::threading::WaitResult wait_result;
|
||||
do {
|
||||
wait_result = WaitForSingleObject(client_semaphore, 0);
|
||||
} while (wait_result == WAIT_OBJECT_0);
|
||||
assert_true(wait_result == WAIT_TIMEOUT);
|
||||
wait_result = xe::threading::Wait(client_semaphore, false,
|
||||
std::chrono::milliseconds(0));
|
||||
} while (wait_result == xe::threading::WaitResult::kSuccess);
|
||||
assert_true(wait_result == xe::threading::WaitResult::kTimeout);
|
||||
}
|
||||
|
||||
} // namespace apu
|
||||
|
|
|
@ -14,11 +14,10 @@
|
|||
#include <mutex>
|
||||
#include <queue>
|
||||
|
||||
#include "xenia/base/threading.h"
|
||||
#include "xenia/emulator.h"
|
||||
#include "xenia/xbox.h"
|
||||
|
||||
typedef void* HANDLE;
|
||||
|
||||
namespace xe {
|
||||
namespace kernel {
|
||||
class XHostThread;
|
||||
|
@ -48,7 +47,15 @@ class AudioSystem {
|
|||
void UnregisterClient(size_t index);
|
||||
void SubmitFrame(size_t index, uint32_t samples_ptr);
|
||||
|
||||
virtual X_STATUS CreateDriver(size_t index, HANDLE semaphore,
|
||||
protected:
|
||||
AudioSystem(Emulator* emulator);
|
||||
|
||||
virtual void Initialize();
|
||||
|
||||
void WorkerThreadMain();
|
||||
|
||||
virtual X_STATUS CreateDriver(size_t index,
|
||||
xe::threading::Semaphore* semaphore,
|
||||
AudioDriver** out_driver) = 0;
|
||||
virtual void DestroyDriver(AudioDriver* driver) = 0;
|
||||
|
||||
|
@ -56,15 +63,6 @@ class AudioSystem {
|
|||
// XAUDIO2_MAX_QUEUED_BUFFERS))
|
||||
static const size_t kMaximumQueuedFrames = 64;
|
||||
|
||||
protected:
|
||||
virtual void Initialize();
|
||||
|
||||
private:
|
||||
void WorkerThreadMain();
|
||||
|
||||
protected:
|
||||
AudioSystem(Emulator* emulator);
|
||||
|
||||
Emulator* emulator_;
|
||||
Memory* memory_;
|
||||
cpu::Processor* processor_;
|
||||
|
@ -83,9 +81,11 @@ class AudioSystem {
|
|||
uint32_t wrapped_callback_arg;
|
||||
} clients_[kMaximumClientCount];
|
||||
|
||||
HANDLE client_semaphores_[kMaximumClientCount];
|
||||
HANDLE shutdown_event_; // Event is always there in case we have no clients.
|
||||
HANDLE wait_handles_[kMaximumClientCount + 1];
|
||||
std::unique_ptr<xe::threading::Semaphore>
|
||||
client_semaphores_[kMaximumClientCount];
|
||||
// Event is always there in case we have no clients.
|
||||
std::unique_ptr<xe::threading::Event> shutdown_event_;
|
||||
xe::threading::WaitHandle* wait_handles_[kMaximumClientCount + 1];
|
||||
std::queue<size_t> unused_clients_;
|
||||
};
|
||||
|
||||
|
|
|
@ -23,7 +23,8 @@ NopAudioSystem::NopAudioSystem(Emulator* emulator) : AudioSystem(emulator) {}
|
|||
|
||||
NopAudioSystem::~NopAudioSystem() = default;
|
||||
|
||||
X_STATUS NopAudioSystem::CreateDriver(size_t index, HANDLE wait_handle,
|
||||
X_STATUS NopAudioSystem::CreateDriver(size_t index,
|
||||
xe::threading::Semaphore* semaphore,
|
||||
AudioDriver** out_driver) {
|
||||
return X_STATUS_NOT_IMPLEMENTED;
|
||||
}
|
||||
|
|
|
@ -23,7 +23,7 @@ class NopAudioSystem : public AudioSystem {
|
|||
|
||||
static std::unique_ptr<AudioSystem> Create(Emulator* emulator);
|
||||
|
||||
X_STATUS CreateDriver(size_t index, HANDLE wait_handle,
|
||||
X_STATUS CreateDriver(size_t index, xe::threading::Semaphore* semaphore,
|
||||
AudioDriver** out_driver) override;
|
||||
void DestroyDriver(AudioDriver* driver) override;
|
||||
};
|
||||
|
|
|
@ -24,32 +24,27 @@ namespace xaudio2 {
|
|||
|
||||
class XAudio2AudioDriver::VoiceCallback : public IXAudio2VoiceCallback {
|
||||
public:
|
||||
VoiceCallback(HANDLE semaphore) : semaphore_(semaphore) {}
|
||||
VoiceCallback(xe::threading::Semaphore* semaphore) : semaphore_(semaphore) {}
|
||||
~VoiceCallback() {}
|
||||
|
||||
void OnStreamEnd() {}
|
||||
void OnVoiceProcessingPassEnd() {}
|
||||
void OnVoiceProcessingPassStart(uint32_t samples_required) {}
|
||||
void OnBufferEnd(void* context) {
|
||||
BOOL ret = ReleaseSemaphore(semaphore_, 1, NULL);
|
||||
assert_true(ret == TRUE);
|
||||
auto ret = semaphore_->Release(1, nullptr);
|
||||
assert_true(ret);
|
||||
}
|
||||
void OnBufferStart(void* context) {}
|
||||
void OnLoopEnd(void* context) {}
|
||||
void OnVoiceError(void* context, HRESULT result) {}
|
||||
|
||||
private:
|
||||
HANDLE semaphore_;
|
||||
xe::threading::Semaphore* semaphore_ = nullptr;
|
||||
};
|
||||
|
||||
XAudio2AudioDriver::XAudio2AudioDriver(Emulator* emulator, HANDLE semaphore)
|
||||
: AudioDriver(emulator),
|
||||
audio_(nullptr),
|
||||
mastering_voice_(nullptr),
|
||||
pcm_voice_(nullptr),
|
||||
semaphore_(semaphore),
|
||||
voice_callback_(nullptr),
|
||||
current_frame_(0) {
|
||||
XAudio2AudioDriver::XAudio2AudioDriver(Emulator* emulator,
|
||||
xe::threading::Semaphore* semaphore)
|
||||
: AudioDriver(emulator), semaphore_(semaphore) {
|
||||
static_assert(frame_count_ == XAUDIO2_MAX_QUEUED_BUFFERS,
|
||||
"xaudio header differs");
|
||||
}
|
||||
|
|
|
@ -22,7 +22,7 @@ namespace xaudio2 {
|
|||
|
||||
class XAudio2AudioDriver : public AudioDriver {
|
||||
public:
|
||||
XAudio2AudioDriver(Emulator* emulator, HANDLE semaphore);
|
||||
XAudio2AudioDriver(Emulator* emulator, xe::threading::Semaphore* semaphore);
|
||||
~XAudio2AudioDriver() override;
|
||||
|
||||
void Initialize();
|
||||
|
@ -30,13 +30,13 @@ class XAudio2AudioDriver : public AudioDriver {
|
|||
void Shutdown();
|
||||
|
||||
private:
|
||||
IXAudio2* audio_;
|
||||
IXAudio2MasteringVoice* mastering_voice_;
|
||||
IXAudio2SourceVoice* pcm_voice_;
|
||||
HANDLE semaphore_;
|
||||
IXAudio2* audio_ = nullptr;
|
||||
IXAudio2MasteringVoice* mastering_voice_ = nullptr;
|
||||
IXAudio2SourceVoice* pcm_voice_ = nullptr;
|
||||
xe::threading::Semaphore* semaphore_ = nullptr;
|
||||
|
||||
class VoiceCallback;
|
||||
VoiceCallback* voice_callback_;
|
||||
VoiceCallback* voice_callback_ = nullptr;
|
||||
|
||||
static const uint32_t frame_count_ = 64;
|
||||
static const uint32_t frame_channels_ = 6;
|
||||
|
@ -44,7 +44,7 @@ class XAudio2AudioDriver : public AudioDriver {
|
|||
static const uint32_t frame_samples_ = frame_channels_ * channel_samples_;
|
||||
static const uint32_t frame_size_ = sizeof(float) * frame_samples_;
|
||||
float frames_[frame_count_][frame_samples_];
|
||||
uint32_t current_frame_;
|
||||
uint32_t current_frame_ = 0;
|
||||
};
|
||||
|
||||
} // namespace xaudio2
|
||||
|
|
|
@ -30,7 +30,8 @@ XAudio2AudioSystem::~XAudio2AudioSystem() {}
|
|||
|
||||
void XAudio2AudioSystem::Initialize() { AudioSystem::Initialize(); }
|
||||
|
||||
X_STATUS XAudio2AudioSystem::CreateDriver(size_t index, HANDLE semaphore,
|
||||
X_STATUS XAudio2AudioSystem::CreateDriver(size_t index,
|
||||
xe::threading::Semaphore* semaphore,
|
||||
AudioDriver** out_driver) {
|
||||
assert_not_null(out_driver);
|
||||
auto driver = new XAudio2AudioDriver(emulator_, semaphore);
|
||||
|
|
|
@ -23,7 +23,7 @@ class XAudio2AudioSystem : public AudioSystem {
|
|||
|
||||
static std::unique_ptr<AudioSystem> Create(Emulator* emulator);
|
||||
|
||||
X_RESULT CreateDriver(size_t index, HANDLE semaphore,
|
||||
X_RESULT CreateDriver(size_t index, xe::threading::Semaphore* semaphore,
|
||||
AudioDriver** out_driver) override;
|
||||
void DestroyDriver(AudioDriver* driver) override;
|
||||
|
||||
|
|
|
@ -111,83 +111,73 @@ class WaitHandle {
|
|||
public:
|
||||
virtual ~WaitHandle() = default;
|
||||
|
||||
// Waits until the wait handle is in the signaled state, an alert triggers and
|
||||
// a user callback is queued to the thread, or the timeout interval elapses.
|
||||
// If timeout is zero the call will return immediately instead of waiting and
|
||||
// if the timeout is max() the wait will not time out.
|
||||
inline WaitResult Wait(
|
||||
bool is_alertable,
|
||||
std::chrono::milliseconds timeout = std::chrono::milliseconds::max()) {
|
||||
return WaitHandle::Wait(this, is_alertable, timeout);
|
||||
}
|
||||
|
||||
// Waits until the wait handle is in the signaled state, an alert triggers and
|
||||
// a user callback is queued to the thread, or the timeout interval elapses.
|
||||
// If timeout is zero the call will return immediately instead of waiting and
|
||||
// if the timeout is max() the wait will not time out.
|
||||
static WaitResult Wait(
|
||||
WaitHandle* wait_handle, bool is_alertable,
|
||||
std::chrono::milliseconds timeout = std::chrono::milliseconds::max());
|
||||
|
||||
// Signals one object and waits on another object as a single operation.
|
||||
// Waits until the wait handle is in the signaled state, an alert triggers and
|
||||
// a user callback is queued to the thread, or the timeout interval elapses.
|
||||
// If timeout is zero the call will return immediately instead of waiting and
|
||||
// if the timeout is max() the wait will not time out.
|
||||
static WaitResult SignalAndWait(
|
||||
WaitHandle* wait_handle_to_signal, WaitHandle* wait_handle_to_wait_on,
|
||||
bool is_alertable,
|
||||
std::chrono::milliseconds timeout = std::chrono::milliseconds::max());
|
||||
|
||||
// Waits until all of the specified objects are in the signaled state, a
|
||||
// user callback is queued to the thread, or the time-out interval elapses.
|
||||
// If timeout is zero the call will return immediately instead of waiting and
|
||||
// if the timeout is max() the wait will not time out.
|
||||
inline static WaitResult WaitAll(
|
||||
WaitHandle* wait_handles[], size_t wait_handle_count, bool is_alertable,
|
||||
std::chrono::milliseconds timeout = std::chrono::milliseconds::max()) {
|
||||
return WaitMultiple(wait_handles, wait_handle_count, true, is_alertable,
|
||||
timeout).first;
|
||||
}
|
||||
inline static WaitResult WaitAll(
|
||||
std::vector<WaitHandle*> wait_handles, bool is_alertable,
|
||||
std::chrono::milliseconds timeout = std::chrono::milliseconds::max()) {
|
||||
return WaitAll(wait_handles.data(), wait_handles.size(), is_alertable,
|
||||
timeout);
|
||||
}
|
||||
|
||||
// Waits until any of the specified objects are in the signaled state, a
|
||||
// user callback is queued to the thread, or the time-out interval elapses.
|
||||
// If timeout is zero the call will return immediately instead of waiting and
|
||||
// if the timeout is max() the wait will not time out.
|
||||
// The second argument of the return tuple indicates which wait handle caused
|
||||
// the wait to be satisfied or abandoned.
|
||||
inline static std::pair<WaitResult, size_t> WaitAny(
|
||||
WaitHandle* wait_handles[], size_t wait_handle_count, bool is_alertable,
|
||||
std::chrono::milliseconds timeout = std::chrono::milliseconds::max()) {
|
||||
return WaitMultiple(wait_handles, wait_handle_count, false, is_alertable,
|
||||
timeout);
|
||||
}
|
||||
inline static std::pair<WaitResult, size_t> WaitAny(
|
||||
std::vector<WaitHandle*> wait_handles, bool is_alertable,
|
||||
std::chrono::milliseconds timeout = std::chrono::milliseconds::max()) {
|
||||
return WaitAny(wait_handles.data(), wait_handles.size(), is_alertable,
|
||||
timeout);
|
||||
}
|
||||
|
||||
protected:
|
||||
WaitHandle() = default;
|
||||
|
||||
// Returns the native handle of the object on the host system.
|
||||
// This value is platform specific.
|
||||
virtual void* native_handle() const = 0;
|
||||
|
||||
static std::pair<WaitResult, size_t> WaitMultiple(
|
||||
WaitHandle* wait_handles[], size_t wait_handle_count, bool wait_all,
|
||||
bool is_alertable,
|
||||
std::chrono::milliseconds timeout = std::chrono::milliseconds::max());
|
||||
protected:
|
||||
WaitHandle() = default;
|
||||
};
|
||||
|
||||
// Waits until the wait handle is in the signaled state, an alert triggers and
|
||||
// a user callback is queued to the thread, or the timeout interval elapses.
|
||||
// If timeout is zero the call will return immediately instead of waiting and
|
||||
// if the timeout is max() the wait will not time out.
|
||||
WaitResult Wait(
|
||||
WaitHandle* wait_handle, bool is_alertable,
|
||||
std::chrono::milliseconds timeout = std::chrono::milliseconds::max());
|
||||
|
||||
// Signals one object and waits on another object as a single operation.
|
||||
// Waits until the wait handle is in the signaled state, an alert triggers and
|
||||
// a user callback is queued to the thread, or the timeout interval elapses.
|
||||
// If timeout is zero the call will return immediately instead of waiting and
|
||||
// if the timeout is max() the wait will not time out.
|
||||
WaitResult SignalAndWait(
|
||||
WaitHandle* wait_handle_to_signal, WaitHandle* wait_handle_to_wait_on,
|
||||
bool is_alertable,
|
||||
std::chrono::milliseconds timeout = std::chrono::milliseconds::max());
|
||||
|
||||
std::pair<WaitResult, size_t> WaitMultiple(
|
||||
WaitHandle* wait_handles[], size_t wait_handle_count, bool wait_all,
|
||||
bool is_alertable,
|
||||
std::chrono::milliseconds timeout = std::chrono::milliseconds::max());
|
||||
|
||||
// Waits until all of the specified objects are in the signaled state, a
|
||||
// user callback is queued to the thread, or the time-out interval elapses.
|
||||
// If timeout is zero the call will return immediately instead of waiting and
|
||||
// if the timeout is max() the wait will not time out.
|
||||
inline WaitResult WaitAll(
|
||||
WaitHandle* wait_handles[], size_t wait_handle_count, bool is_alertable,
|
||||
std::chrono::milliseconds timeout = std::chrono::milliseconds::max()) {
|
||||
return WaitMultiple(wait_handles, wait_handle_count, true, is_alertable,
|
||||
timeout).first;
|
||||
}
|
||||
inline WaitResult WaitAll(
|
||||
std::vector<WaitHandle*> wait_handles, bool is_alertable,
|
||||
std::chrono::milliseconds timeout = std::chrono::milliseconds::max()) {
|
||||
return WaitAll(wait_handles.data(), wait_handles.size(), is_alertable,
|
||||
timeout);
|
||||
}
|
||||
|
||||
// Waits until any of the specified objects are in the signaled state, a
|
||||
// user callback is queued to the thread, or the time-out interval elapses.
|
||||
// If timeout is zero the call will return immediately instead of waiting and
|
||||
// if the timeout is max() the wait will not time out.
|
||||
// The second argument of the return tuple indicates which wait handle caused
|
||||
// the wait to be satisfied or abandoned.
|
||||
inline std::pair<WaitResult, size_t> WaitAny(
|
||||
WaitHandle* wait_handles[], size_t wait_handle_count, bool is_alertable,
|
||||
std::chrono::milliseconds timeout = std::chrono::milliseconds::max()) {
|
||||
return WaitMultiple(wait_handles, wait_handle_count, false, is_alertable,
|
||||
timeout);
|
||||
}
|
||||
inline std::pair<WaitResult, size_t> WaitAny(
|
||||
std::vector<WaitHandle*> wait_handles, bool is_alertable,
|
||||
std::chrono::milliseconds timeout = std::chrono::milliseconds::max()) {
|
||||
return WaitAny(wait_handles.data(), wait_handles.size(), is_alertable,
|
||||
timeout);
|
||||
}
|
||||
|
||||
// Models a Win32-like event object.
|
||||
// https://msdn.microsoft.com/en-us/library/windows/desktop/ms682396(v=vs.85).aspx
|
||||
class Event : public WaitHandle {
|
||||
|
|
|
@ -102,8 +102,8 @@ class Win32Handle : public T {
|
|||
HANDLE handle_ = nullptr;
|
||||
};
|
||||
|
||||
WaitResult WaitHandle::Wait(WaitHandle* wait_handle, bool is_alertable,
|
||||
std::chrono::milliseconds timeout) {
|
||||
WaitResult Wait(WaitHandle* wait_handle, bool is_alertable,
|
||||
std::chrono::milliseconds timeout) {
|
||||
HANDLE handle = wait_handle->native_handle();
|
||||
DWORD result = WaitForSingleObjectEx(handle, DWORD(timeout.count()),
|
||||
is_alertable ? TRUE : FALSE);
|
||||
|
@ -122,10 +122,9 @@ WaitResult WaitHandle::Wait(WaitHandle* wait_handle, bool is_alertable,
|
|||
}
|
||||
}
|
||||
|
||||
WaitResult WaitHandle::SignalAndWait(WaitHandle* wait_handle_to_signal,
|
||||
WaitHandle* wait_handle_to_wait_on,
|
||||
bool is_alertable,
|
||||
std::chrono::milliseconds timeout) {
|
||||
WaitResult SignalAndWait(WaitHandle* wait_handle_to_signal,
|
||||
WaitHandle* wait_handle_to_wait_on, bool is_alertable,
|
||||
std::chrono::milliseconds timeout) {
|
||||
HANDLE handle_to_signal = wait_handle_to_signal->native_handle();
|
||||
HANDLE handle_to_wait_on = wait_handle_to_wait_on->native_handle();
|
||||
DWORD result =
|
||||
|
@ -146,9 +145,10 @@ WaitResult WaitHandle::SignalAndWait(WaitHandle* wait_handle_to_signal,
|
|||
}
|
||||
}
|
||||
|
||||
std::pair<WaitResult, size_t> WaitHandle::WaitMultiple(
|
||||
WaitHandle* wait_handles[], size_t wait_handle_count, bool wait_all,
|
||||
bool is_alertable, std::chrono::milliseconds timeout) {
|
||||
std::pair<WaitResult, size_t> WaitMultiple(WaitHandle* wait_handles[],
|
||||
size_t wait_handle_count,
|
||||
bool wait_all, bool is_alertable,
|
||||
std::chrono::milliseconds timeout) {
|
||||
std::vector<HANDLE> handles(wait_handle_count);
|
||||
for (size_t i = 0; i < wait_handle_count; ++i) {
|
||||
handles[i] = wait_handles[i]->native_handle();
|
||||
|
|
|
@ -17,9 +17,9 @@ namespace xe {
|
|||
namespace kernel {
|
||||
|
||||
typedef struct {
|
||||
xe::be<DWORD> count;
|
||||
xe::be<DWORD> state[5];
|
||||
xe::be<BYTE> buffer[64];
|
||||
xe::be<uint32_t> count;
|
||||
xe::be<uint32_t> state[5];
|
||||
uint8_t buffer[64];
|
||||
} XECRYPT_SHA_STATE;
|
||||
|
||||
void XeCryptShaInit(pointer_t<XECRYPT_SHA_STATE> sha_state) {
|
||||
|
|
|
@ -7,6 +7,7 @@
|
|||
******************************************************************************
|
||||
*/
|
||||
|
||||
#include "xenia/base/debugging.h"
|
||||
#include "xenia/base/logging.h"
|
||||
#include "xenia/kernel/kernel_state.h"
|
||||
#include "xenia/kernel/objects/xthread.h"
|
||||
|
@ -17,7 +18,7 @@
|
|||
namespace xe {
|
||||
namespace kernel {
|
||||
|
||||
void DbgBreakPoint() { DebugBreak(); }
|
||||
void DbgBreakPoint() { xe::debugging::Break(); }
|
||||
DECLARE_XBOXKRNL_EXPORT(DbgBreakPoint, ExportTag::kImportant);
|
||||
|
||||
// https://msdn.microsoft.com/en-us/library/xcb2z8hs.aspx
|
||||
|
@ -79,13 +80,13 @@ void RtlRaiseException(pointer_t<X_EXCEPTION_RECORD> record) {
|
|||
if (record->exception_code == 0xE06D7363) {
|
||||
// C++ exception.
|
||||
// http://blogs.msdn.com/b/oldnewthing/archive/2010/07/30/10044061.aspx
|
||||
DebugBreak();
|
||||
xe::debugging::Break();
|
||||
return;
|
||||
}
|
||||
|
||||
// TODO(benvanik): unwinding.
|
||||
// This is going to suck.
|
||||
DebugBreak();
|
||||
xe::debugging::Break();
|
||||
}
|
||||
DECLARE_XBOXKRNL_EXPORT(RtlRaiseException, ExportTag::kImportant);
|
||||
|
||||
|
@ -94,7 +95,7 @@ void KeBugCheckEx(dword_t code, dword_t param1, dword_t param2, dword_t param3,
|
|||
XELOGD("*** STOP: 0x%.8X (0x%.8X, 0x%.8X, 0x%.8X, 0x%.8X)", code, param1,
|
||||
param2, param3, param4);
|
||||
fflush(stdout);
|
||||
DebugBreak();
|
||||
xe::debugging::Break();
|
||||
assert_always();
|
||||
}
|
||||
DECLARE_XBOXKRNL_EXPORT(KeBugCheckEx, ExportTag::kImportant);
|
||||
|
|
|
@ -128,7 +128,8 @@ X_STATUS XObject::Wait(uint32_t wait_reason, uint32_t processor_mode,
|
|||
TimeoutTicksToMs(*opt_timeout)))
|
||||
: std::chrono::milliseconds::max();
|
||||
|
||||
auto result = wait_handle->Wait(alertable ? true : false, timeout_ms);
|
||||
auto result =
|
||||
xe::threading::Wait(wait_handle, alertable ? true : false, timeout_ms);
|
||||
switch (result) {
|
||||
case xe::threading::WaitResult::kSuccess:
|
||||
return X_STATUS_SUCCESS;
|
||||
|
@ -136,7 +137,7 @@ X_STATUS XObject::Wait(uint32_t wait_reason, uint32_t processor_mode,
|
|||
// Or X_STATUS_ALERTED?
|
||||
return X_STATUS_USER_APC;
|
||||
case xe::threading::WaitResult::kTimeout:
|
||||
YieldProcessor();
|
||||
xe::threading::MaybeYield();
|
||||
return X_STATUS_TIMEOUT;
|
||||
default:
|
||||
case xe::threading::WaitResult::kAbandoned:
|
||||
|
@ -153,7 +154,7 @@ X_STATUS XObject::SignalAndWait(XObject* signal_object, XObject* wait_object,
|
|||
TimeoutTicksToMs(*opt_timeout)))
|
||||
: std::chrono::milliseconds::max();
|
||||
|
||||
auto result = xe::threading::WaitHandle::SignalAndWait(
|
||||
auto result = xe::threading::SignalAndWait(
|
||||
signal_object->GetWaitHandle(), wait_object->GetWaitHandle(),
|
||||
alertable ? true : false, timeout_ms);
|
||||
switch (result) {
|
||||
|
@ -163,7 +164,7 @@ X_STATUS XObject::SignalAndWait(XObject* signal_object, XObject* wait_object,
|
|||
// Or X_STATUS_ALERTED?
|
||||
return X_STATUS_USER_APC;
|
||||
case xe::threading::WaitResult::kTimeout:
|
||||
YieldProcessor();
|
||||
xe::threading::MaybeYield();
|
||||
return X_STATUS_TIMEOUT;
|
||||
default:
|
||||
case xe::threading::WaitResult::kAbandoned:
|
||||
|
@ -188,8 +189,8 @@ X_STATUS XObject::WaitMultiple(uint32_t count, XObject** objects,
|
|||
: std::chrono::milliseconds::max();
|
||||
|
||||
if (wait_type) {
|
||||
auto result = xe::threading::WaitHandle::WaitAny(
|
||||
std::move(wait_handles), alertable ? true : false, timeout_ms);
|
||||
auto result = xe::threading::WaitAny(std::move(wait_handles),
|
||||
alertable ? true : false, timeout_ms);
|
||||
switch (result.first) {
|
||||
case xe::threading::WaitResult::kSuccess:
|
||||
return X_STATUS(result.second);
|
||||
|
@ -197,7 +198,7 @@ X_STATUS XObject::WaitMultiple(uint32_t count, XObject** objects,
|
|||
// Or X_STATUS_ALERTED?
|
||||
return X_STATUS_USER_APC;
|
||||
case xe::threading::WaitResult::kTimeout:
|
||||
YieldProcessor();
|
||||
xe::threading::MaybeYield();
|
||||
return X_STATUS_TIMEOUT;
|
||||
default:
|
||||
case xe::threading::WaitResult::kAbandoned:
|
||||
|
@ -206,8 +207,8 @@ X_STATUS XObject::WaitMultiple(uint32_t count, XObject** objects,
|
|||
return X_STATUS_UNSUCCESSFUL;
|
||||
}
|
||||
} else {
|
||||
auto result = xe::threading::WaitHandle::WaitAll(
|
||||
std::move(wait_handles), alertable ? true : false, timeout_ms);
|
||||
auto result = xe::threading::WaitAll(std::move(wait_handles),
|
||||
alertable ? true : false, timeout_ms);
|
||||
switch (result) {
|
||||
case xe::threading::WaitResult::kSuccess:
|
||||
return X_STATUS_SUCCESS;
|
||||
|
@ -215,7 +216,7 @@ X_STATUS XObject::WaitMultiple(uint32_t count, XObject** objects,
|
|||
// Or X_STATUS_ALERTED?
|
||||
return X_STATUS_USER_APC;
|
||||
case xe::threading::WaitResult::kTimeout:
|
||||
YieldProcessor();
|
||||
xe::threading::MaybeYield();
|
||||
return X_STATUS_TIMEOUT;
|
||||
default:
|
||||
case xe::threading::WaitResult::kAbandoned:
|
||||
|
|
Loading…
Reference in New Issue