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