[linux_platform] Implement a bunch of missing functions necessaries to make Xenia build correctly under Linux
With this part fixed and a function readapted from the original codebase to fix the different signature, we should have a compiling Linux build now.
This commit is contained in:
parent
3f196f4b62
commit
753698ea20
|
@ -53,4 +53,5 @@ uint64_t Clock::QueryHostUptimeMillis() {
|
||||||
return host_tick_count_platform() * 1000 / host_tick_frequency_platform();
|
return host_tick_count_platform() * 1000 / host_tick_frequency_platform();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
uint64_t Clock::QueryHostInterruptTime() { return host_tick_count_platform(); }
|
||||||
} // namespace xe
|
} // namespace xe
|
||||||
|
|
|
@ -0,0 +1,46 @@
|
||||||
|
/**
|
||||||
|
******************************************************************************
|
||||||
|
* Xenia : Xbox 360 Emulator Research Project *
|
||||||
|
******************************************************************************
|
||||||
|
* Copyright 2023 Ben Vanik. All rights reserved. *
|
||||||
|
* Released under the BSD license - see LICENSE in the root for more details. *
|
||||||
|
******************************************************************************
|
||||||
|
*/
|
||||||
|
#include <gdk/gdk.h>
|
||||||
|
#include <gtk/gtk.h>
|
||||||
|
#include <xbyak/xbyak/xbyak_util.h>
|
||||||
|
|
||||||
|
#include "xenia/ui/window_gtk.h"
|
||||||
|
|
||||||
|
class StartupCpuFeatureCheck {
|
||||||
|
public:
|
||||||
|
StartupCpuFeatureCheck() {
|
||||||
|
Xbyak::util::Cpu cpu;
|
||||||
|
const char* error_message = nullptr;
|
||||||
|
if (!cpu.has(Xbyak::util::Cpu::tAVX)) {
|
||||||
|
error_message =
|
||||||
|
"Your CPU does not support AVX, which is required by Xenia. See "
|
||||||
|
"the "
|
||||||
|
"FAQ for system requirements at https://xenia.jp";
|
||||||
|
}
|
||||||
|
if (error_message == nullptr) {
|
||||||
|
return;
|
||||||
|
} else {
|
||||||
|
GtkDialogFlags flags = GTK_DIALOG_DESTROY_WITH_PARENT;
|
||||||
|
auto dialog =
|
||||||
|
gtk_message_dialog_new(nullptr, flags, GTK_MESSAGE_ERROR,
|
||||||
|
GTK_BUTTONS_CLOSE, "%s", error_message);
|
||||||
|
gtk_dialog_run(GTK_DIALOG(dialog));
|
||||||
|
gtk_widget_destroy(dialog);
|
||||||
|
exit(1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
// This is a hack to get an instance of StartupAvxCheck
|
||||||
|
// constructed before any initialization code,
|
||||||
|
// where the AVX check then happens in the constructor.
|
||||||
|
// Ref:
|
||||||
|
// https://reviews.llvm.org/D12689#243295
|
||||||
|
__attribute__((
|
||||||
|
init_priority(101))) static StartupCpuFeatureCheck gStartupAvxCheck;
|
|
@ -82,8 +82,7 @@ void AndroidShutdown() {
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
template <typename _Rep, typename _Period>
|
template <typename _Rep, typename _Period>
|
||||||
inline timespec DurationToTimeSpec(
|
timespec DurationToTimeSpec(std::chrono::duration<_Rep, _Period> duration) {
|
||||||
std::chrono::duration<_Rep, _Period> duration) {
|
|
||||||
auto nanoseconds =
|
auto nanoseconds =
|
||||||
std::chrono::duration_cast<std::chrono::nanoseconds>(duration);
|
std::chrono::duration_cast<std::chrono::nanoseconds>(duration);
|
||||||
auto div = ldiv(nanoseconds.count(), 1000000000L);
|
auto div = ldiv(nanoseconds.count(), 1000000000L);
|
||||||
|
@ -161,6 +160,8 @@ void Sleep(std::chrono::microseconds duration) {
|
||||||
} while (ret == -1 && errno == EINTR);
|
} while (ret == -1 && errno == EINTR);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void NanoSleep(int64_t duration) { Sleep(std::chrono::nanoseconds(duration)); }
|
||||||
|
|
||||||
// TODO(bwrsandman) Implement by allowing alert interrupts from IO operations
|
// TODO(bwrsandman) Implement by allowing alert interrupts from IO operations
|
||||||
thread_local bool alertable_state_ = false;
|
thread_local bool alertable_state_ = false;
|
||||||
SleepResult AlertableSleep(std::chrono::microseconds duration) {
|
SleepResult AlertableSleep(std::chrono::microseconds duration) {
|
||||||
|
@ -178,28 +179,25 @@ TlsHandle AllocateTlsHandle() {
|
||||||
return static_cast<TlsHandle>(key);
|
return static_cast<TlsHandle>(key);
|
||||||
}
|
}
|
||||||
|
|
||||||
bool FreeTlsHandle(TlsHandle handle) {
|
bool FreeTlsHandle(TlsHandle handle) { return pthread_key_delete(handle) == 0; }
|
||||||
return pthread_key_delete(static_cast<pthread_key_t>(handle)) == 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
uintptr_t GetTlsValue(TlsHandle handle) {
|
uintptr_t GetTlsValue(TlsHandle handle) {
|
||||||
return reinterpret_cast<uintptr_t>(
|
return reinterpret_cast<uintptr_t>(pthread_getspecific(handle));
|
||||||
pthread_getspecific(static_cast<pthread_key_t>(handle)));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
bool SetTlsValue(TlsHandle handle, uintptr_t value) {
|
bool SetTlsValue(TlsHandle handle, uintptr_t value) {
|
||||||
return pthread_setspecific(static_cast<pthread_key_t>(handle),
|
return pthread_setspecific(handle, reinterpret_cast<void*>(value)) == 0;
|
||||||
reinterpret_cast<void*>(value)) == 0;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
class PosixConditionBase {
|
class PosixConditionBase {
|
||||||
public:
|
public:
|
||||||
|
virtual ~PosixConditionBase() = default;
|
||||||
virtual bool Signal() = 0;
|
virtual bool Signal() = 0;
|
||||||
|
|
||||||
WaitResult Wait(std::chrono::milliseconds timeout) {
|
WaitResult Wait(std::chrono::milliseconds timeout) {
|
||||||
bool executed;
|
bool executed;
|
||||||
auto predicate = [this] { return this->signaled(); };
|
auto predicate = [this] { return this->signaled(); };
|
||||||
auto lock = std::unique_lock<std::mutex>(mutex_);
|
auto lock = std::unique_lock(mutex_);
|
||||||
if (predicate()) {
|
if (predicate()) {
|
||||||
executed = true;
|
executed = true;
|
||||||
} else {
|
} else {
|
||||||
|
@ -213,15 +211,14 @@ class PosixConditionBase {
|
||||||
if (executed) {
|
if (executed) {
|
||||||
post_execution();
|
post_execution();
|
||||||
return WaitResult::kSuccess;
|
return WaitResult::kSuccess;
|
||||||
} else {
|
|
||||||
return WaitResult::kTimeout;
|
|
||||||
}
|
}
|
||||||
|
return WaitResult::kTimeout;
|
||||||
}
|
}
|
||||||
|
|
||||||
static std::pair<WaitResult, size_t> WaitMultiple(
|
static std::pair<WaitResult, size_t> WaitMultiple(
|
||||||
std::vector<PosixConditionBase*>&& handles, bool wait_all,
|
std::vector<PosixConditionBase*>&& handles, bool wait_all,
|
||||||
std::chrono::milliseconds timeout) {
|
std::chrono::milliseconds timeout) {
|
||||||
assert_true(handles.size() > 0);
|
assert_true(!handles.empty());
|
||||||
|
|
||||||
// Construct a condition for all or any depending on wait_all
|
// Construct a condition for all or any depending on wait_all
|
||||||
std::function<bool()> predicate;
|
std::function<bool()> predicate;
|
||||||
|
@ -239,17 +236,16 @@ class PosixConditionBase {
|
||||||
// TODO(bwrsandman, Triang3l) This is controversial, see issue #1677
|
// TODO(bwrsandman, Triang3l) This is controversial, see issue #1677
|
||||||
// This will probably cause a deadlock on the next thread doing any waiting
|
// This will probably cause a deadlock on the next thread doing any waiting
|
||||||
// if the thread is suspended between locking and waiting
|
// if the thread is suspended between locking and waiting
|
||||||
std::unique_lock<std::mutex> lock(PosixConditionBase::mutex_);
|
std::unique_lock lock(mutex_);
|
||||||
|
|
||||||
bool wait_success = true;
|
bool wait_success = true;
|
||||||
// If the timeout is infinite, wait without timeout.
|
// If the timeout is infinite, wait without timeout.
|
||||||
// The predicate will be checked before beginning the wait
|
// The predicate will be checked before beginning the wait
|
||||||
if (timeout == std::chrono::milliseconds::max()) {
|
if (timeout == std::chrono::milliseconds::max()) {
|
||||||
PosixConditionBase::cond_.wait(lock, predicate);
|
cond_.wait(lock, predicate);
|
||||||
} else {
|
} else {
|
||||||
// Wait with timeout.
|
// Wait with timeout.
|
||||||
wait_success =
|
wait_success = cond_.wait_for(lock, timeout, predicate);
|
||||||
PosixConditionBase::cond_.wait_for(lock, timeout, predicate);
|
|
||||||
}
|
}
|
||||||
if (wait_success) {
|
if (wait_success) {
|
||||||
auto first_signaled = std::numeric_limits<size_t>::max();
|
auto first_signaled = std::numeric_limits<size_t>::max();
|
||||||
|
@ -264,15 +260,16 @@ class PosixConditionBase {
|
||||||
}
|
}
|
||||||
assert_true(std::numeric_limits<size_t>::max() != first_signaled);
|
assert_true(std::numeric_limits<size_t>::max() != first_signaled);
|
||||||
return std::make_pair(WaitResult::kSuccess, first_signaled);
|
return std::make_pair(WaitResult::kSuccess, first_signaled);
|
||||||
} else {
|
|
||||||
return std::make_pair<WaitResult, size_t>(WaitResult::kTimeout, 0);
|
|
||||||
}
|
}
|
||||||
|
return std::make_pair<WaitResult, size_t>(WaitResult::kTimeout, 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
virtual void* native_handle() const { return cond_.native_handle(); }
|
[[nodiscard]] virtual void* native_handle() const {
|
||||||
|
return cond_.native_handle();
|
||||||
|
}
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
inline virtual bool signaled() const = 0;
|
[[nodiscard]] inline virtual bool signaled() const = 0;
|
||||||
inline virtual void post_execution() = 0;
|
inline virtual void post_execution() = 0;
|
||||||
static std::condition_variable cond_;
|
static std::condition_variable cond_;
|
||||||
static std::mutex mutex_;
|
static std::mutex mutex_;
|
||||||
|
@ -293,23 +290,23 @@ class PosixCondition<Event> : public PosixConditionBase {
|
||||||
public:
|
public:
|
||||||
PosixCondition(bool manual_reset, bool initial_state)
|
PosixCondition(bool manual_reset, bool initial_state)
|
||||||
: signal_(initial_state), manual_reset_(manual_reset) {}
|
: signal_(initial_state), manual_reset_(manual_reset) {}
|
||||||
virtual ~PosixCondition() = default;
|
~PosixCondition() override = default;
|
||||||
|
|
||||||
bool Signal() override {
|
bool Signal() override {
|
||||||
auto lock = std::unique_lock<std::mutex>(mutex_);
|
auto lock = std::unique_lock(mutex_);
|
||||||
signal_ = true;
|
signal_ = true;
|
||||||
cond_.notify_all();
|
cond_.notify_all();
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
void Reset() {
|
void Reset() {
|
||||||
auto lock = std::unique_lock<std::mutex>(mutex_);
|
auto lock = std::unique_lock(mutex_);
|
||||||
signal_ = false;
|
signal_ = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
private:
|
private:
|
||||||
inline bool signaled() const override { return signal_; }
|
[[nodiscard]] bool signaled() const override { return signal_; }
|
||||||
inline void post_execution() override {
|
void post_execution() override {
|
||||||
if (!manual_reset_) {
|
if (!manual_reset_) {
|
||||||
signal_ = false;
|
signal_ = false;
|
||||||
}
|
}
|
||||||
|
@ -319,7 +316,7 @@ class PosixCondition<Event> : public PosixConditionBase {
|
||||||
};
|
};
|
||||||
|
|
||||||
template <>
|
template <>
|
||||||
class PosixCondition<Semaphore> : public PosixConditionBase {
|
class PosixCondition<Semaphore> final : public PosixConditionBase {
|
||||||
public:
|
public:
|
||||||
PosixCondition(uint32_t initial_count, uint32_t maximum_count)
|
PosixCondition(uint32_t initial_count, uint32_t maximum_count)
|
||||||
: count_(initial_count), maximum_count_(maximum_count) {}
|
: count_(initial_count), maximum_count_(maximum_count) {}
|
||||||
|
@ -328,7 +325,7 @@ class PosixCondition<Semaphore> : public PosixConditionBase {
|
||||||
|
|
||||||
bool Release(uint32_t release_count, int* out_previous_count) {
|
bool Release(uint32_t release_count, int* out_previous_count) {
|
||||||
if (maximum_count_ - count_ >= release_count) {
|
if (maximum_count_ - count_ >= release_count) {
|
||||||
auto lock = std::unique_lock<std::mutex>(mutex_);
|
auto lock = std::unique_lock(mutex_);
|
||||||
if (out_previous_count) *out_previous_count = count_;
|
if (out_previous_count) *out_previous_count = count_;
|
||||||
count_ += release_count;
|
count_ += release_count;
|
||||||
cond_.notify_all();
|
cond_.notify_all();
|
||||||
|
@ -338,8 +335,8 @@ class PosixCondition<Semaphore> : public PosixConditionBase {
|
||||||
}
|
}
|
||||||
|
|
||||||
private:
|
private:
|
||||||
inline bool signaled() const override { return count_ > 0; }
|
[[nodiscard]] bool signaled() const override { return count_ > 0; }
|
||||||
inline void post_execution() override {
|
void post_execution() override {
|
||||||
count_--;
|
count_--;
|
||||||
cond_.notify_all();
|
cond_.notify_all();
|
||||||
}
|
}
|
||||||
|
@ -348,7 +345,7 @@ class PosixCondition<Semaphore> : public PosixConditionBase {
|
||||||
};
|
};
|
||||||
|
|
||||||
template <>
|
template <>
|
||||||
class PosixCondition<Mutant> : public PosixConditionBase {
|
class PosixCondition<Mutant> final : public PosixConditionBase {
|
||||||
public:
|
public:
|
||||||
explicit PosixCondition(bool initial_owner) : count_(0) {
|
explicit PosixCondition(bool initial_owner) : count_(0) {
|
||||||
if (initial_owner) {
|
if (initial_owner) {
|
||||||
|
@ -361,7 +358,7 @@ class PosixCondition<Mutant> : public PosixConditionBase {
|
||||||
|
|
||||||
bool Release() {
|
bool Release() {
|
||||||
if (owner_ == std::this_thread::get_id() && count_ > 0) {
|
if (owner_ == std::this_thread::get_id() && count_ > 0) {
|
||||||
auto lock = std::unique_lock<std::mutex>(mutex_);
|
auto lock = std::unique_lock(mutex_);
|
||||||
--count_;
|
--count_;
|
||||||
// Free to be acquired by another thread
|
// Free to be acquired by another thread
|
||||||
if (count_ == 0) {
|
if (count_ == 0) {
|
||||||
|
@ -372,13 +369,15 @@ class PosixCondition<Mutant> : public PosixConditionBase {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
void* native_handle() const override { return mutex_.native_handle(); }
|
[[nodiscard]] void* native_handle() const override {
|
||||||
|
return mutex_.native_handle();
|
||||||
|
}
|
||||||
|
|
||||||
private:
|
private:
|
||||||
inline bool signaled() const override {
|
[[nodiscard]] bool signaled() const override {
|
||||||
return count_ == 0 || owner_ == std::this_thread::get_id();
|
return count_ == 0 || owner_ == std::this_thread::get_id();
|
||||||
}
|
}
|
||||||
inline void post_execution() override {
|
void post_execution() override {
|
||||||
count_++;
|
count_++;
|
||||||
owner_ = std::this_thread::get_id();
|
owner_ = std::this_thread::get_id();
|
||||||
}
|
}
|
||||||
|
@ -387,15 +386,15 @@ class PosixCondition<Mutant> : public PosixConditionBase {
|
||||||
};
|
};
|
||||||
|
|
||||||
template <>
|
template <>
|
||||||
class PosixCondition<Timer> : public PosixConditionBase {
|
class PosixCondition<Timer> final : public PosixConditionBase {
|
||||||
public:
|
public:
|
||||||
explicit PosixCondition(bool manual_reset)
|
explicit PosixCondition(bool manual_reset)
|
||||||
: callback_(nullptr), signal_(false), manual_reset_(manual_reset) {}
|
: callback_(nullptr), signal_(false), manual_reset_(manual_reset) {}
|
||||||
|
|
||||||
virtual ~PosixCondition() { Cancel(); }
|
~PosixCondition() override { Cancel(); }
|
||||||
|
|
||||||
bool Signal() override {
|
bool Signal() override {
|
||||||
std::lock_guard<std::mutex> lock(mutex_);
|
std::lock_guard lock(mutex_);
|
||||||
signal_ = true;
|
signal_ = true;
|
||||||
cond_.notify_all();
|
cond_.notify_all();
|
||||||
return true;
|
return true;
|
||||||
|
@ -405,7 +404,7 @@ class PosixCondition<Timer> : public PosixConditionBase {
|
||||||
std::function<void()> opt_callback) {
|
std::function<void()> opt_callback) {
|
||||||
Cancel();
|
Cancel();
|
||||||
|
|
||||||
std::lock_guard<std::mutex> lock(mutex_);
|
std::lock_guard lock(mutex_);
|
||||||
|
|
||||||
callback_ = std::move(opt_callback);
|
callback_ = std::move(opt_callback);
|
||||||
signal_ = false;
|
signal_ = false;
|
||||||
|
@ -417,7 +416,7 @@ class PosixCondition<Timer> : public PosixConditionBase {
|
||||||
std::function<void()> opt_callback) {
|
std::function<void()> opt_callback) {
|
||||||
Cancel();
|
Cancel();
|
||||||
|
|
||||||
std::lock_guard<std::mutex> lock(mutex_);
|
std::lock_guard lock(mutex_);
|
||||||
|
|
||||||
callback_ = std::move(opt_callback);
|
callback_ = std::move(opt_callback);
|
||||||
signal_ = false;
|
signal_ = false;
|
||||||
|
@ -425,13 +424,13 @@ class PosixCondition<Timer> : public PosixConditionBase {
|
||||||
QueueTimerRecurring(&CompletionRoutine, this, due_time, period);
|
QueueTimerRecurring(&CompletionRoutine, this, due_time, period);
|
||||||
}
|
}
|
||||||
|
|
||||||
void Cancel() {
|
void Cancel() const {
|
||||||
if (auto wait_item = wait_item_.lock()) {
|
if (auto wait_item = wait_item_.lock()) {
|
||||||
wait_item->Disarm();
|
wait_item->Disarm();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void* native_handle() const override {
|
[[nodiscard]] void* native_handle() const override {
|
||||||
assert_always();
|
assert_always();
|
||||||
return nullptr;
|
return nullptr;
|
||||||
}
|
}
|
||||||
|
@ -439,12 +438,12 @@ class PosixCondition<Timer> : public PosixConditionBase {
|
||||||
private:
|
private:
|
||||||
static void CompletionRoutine(void* userdata) {
|
static void CompletionRoutine(void* userdata) {
|
||||||
assert_not_null(userdata);
|
assert_not_null(userdata);
|
||||||
auto timer = reinterpret_cast<PosixCondition<Timer>*>(userdata);
|
auto timer = static_cast<PosixCondition*>(userdata);
|
||||||
timer->Signal();
|
timer->Signal();
|
||||||
// As the callback may reset the timer, store local.
|
// As the callback may reset the timer, store local.
|
||||||
std::function<void()> callback;
|
std::function<void()> callback;
|
||||||
{
|
{
|
||||||
std::lock_guard<std::mutex> lock(timer->mutex_);
|
std::lock_guard lock(timer->mutex_);
|
||||||
callback = timer->callback_;
|
callback = timer->callback_;
|
||||||
}
|
}
|
||||||
if (callback) {
|
if (callback) {
|
||||||
|
@ -452,9 +451,8 @@ class PosixCondition<Timer> : public PosixConditionBase {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private:
|
[[nodiscard]] bool signaled() const override { return signal_; }
|
||||||
inline bool signaled() const override { return signal_; }
|
void post_execution() override {
|
||||||
inline void post_execution() override {
|
|
||||||
if (!manual_reset_) {
|
if (!manual_reset_) {
|
||||||
signal_ = false;
|
signal_ = false;
|
||||||
}
|
}
|
||||||
|
@ -472,7 +470,7 @@ struct ThreadStartData {
|
||||||
};
|
};
|
||||||
|
|
||||||
template <>
|
template <>
|
||||||
class PosixCondition<Thread> : public PosixConditionBase {
|
class PosixCondition<Thread> final : public PosixConditionBase {
|
||||||
enum class State {
|
enum class State {
|
||||||
kUninitialized,
|
kUninitialized,
|
||||||
kRunning,
|
kRunning,
|
||||||
|
@ -526,13 +524,14 @@ class PosixCondition<Thread> : public PosixConditionBase {
|
||||||
: thread_(thread),
|
: thread_(thread),
|
||||||
signaled_(false),
|
signaled_(false),
|
||||||
exit_code_(0),
|
exit_code_(0),
|
||||||
state_(State::kRunning) {
|
state_(State::kRunning),
|
||||||
|
suspend_count_(0) {
|
||||||
#if XE_PLATFORM_ANDROID
|
#if XE_PLATFORM_ANDROID
|
||||||
android_pre_api_26_name_[0] = '\0';
|
android_pre_api_26_name_[0] = '\0';
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
virtual ~PosixCondition() {
|
~PosixCondition() override {
|
||||||
// FIXME(RodoMa92): This causes random crashes.
|
// FIXME(RodoMa92): This causes random crashes.
|
||||||
// The proper way to handle them according to the webs is properly shutdown
|
// The proper way to handle them according to the webs is properly shutdown
|
||||||
// instead on relying on killing them using pthread_cancel.
|
// instead on relying on killing them using pthread_cancel.
|
||||||
|
@ -560,7 +559,7 @@ class PosixCondition<Thread> : public PosixConditionBase {
|
||||||
std::string name() const {
|
std::string name() const {
|
||||||
WaitStarted();
|
WaitStarted();
|
||||||
auto result = std::array<char, 17>{'\0'};
|
auto result = std::array<char, 17>{'\0'};
|
||||||
std::unique_lock<std::mutex> lock(state_mutex_);
|
std::unique_lock lock(state_mutex_);
|
||||||
if (state_ != State::kUninitialized && state_ != State::kFinished) {
|
if (state_ != State::kUninitialized && state_ != State::kFinished) {
|
||||||
#if XE_PLATFORM_ANDROID
|
#if XE_PLATFORM_ANDROID
|
||||||
// pthread_getname_np was added in API 26 - below that, store the name in
|
// pthread_getname_np was added in API 26 - below that, store the name in
|
||||||
|
@ -584,7 +583,7 @@ class PosixCondition<Thread> : public PosixConditionBase {
|
||||||
return std::string(result.data());
|
return std::string(result.data());
|
||||||
}
|
}
|
||||||
|
|
||||||
void set_name(const std::string& name) {
|
void set_name(const std::string& name) const {
|
||||||
WaitStarted();
|
WaitStarted();
|
||||||
std::unique_lock<std::mutex> lock(state_mutex_);
|
std::unique_lock<std::mutex> lock(state_mutex_);
|
||||||
if (state_ != State::kUninitialized && state_ != State::kFinished) {
|
if (state_ != State::kUninitialized && state_ != State::kFinished) {
|
||||||
|
@ -608,7 +607,7 @@ class PosixCondition<Thread> : public PosixConditionBase {
|
||||||
|
|
||||||
uint32_t system_id() const { return static_cast<uint32_t>(thread_); }
|
uint32_t system_id() const { return static_cast<uint32_t>(thread_); }
|
||||||
|
|
||||||
uint64_t affinity_mask() {
|
uint64_t affinity_mask() const {
|
||||||
WaitStarted();
|
WaitStarted();
|
||||||
cpu_set_t cpu_set;
|
cpu_set_t cpu_set;
|
||||||
#if XE_PLATFORM_ANDROID
|
#if XE_PLATFORM_ANDROID
|
||||||
|
@ -630,7 +629,7 @@ class PosixCondition<Thread> : public PosixConditionBase {
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
void set_affinity_mask(uint64_t mask) {
|
void set_affinity_mask(uint64_t mask) const {
|
||||||
WaitStarted();
|
WaitStarted();
|
||||||
cpu_set_t cpu_set;
|
cpu_set_t cpu_set;
|
||||||
CPU_ZERO(&cpu_set);
|
CPU_ZERO(&cpu_set);
|
||||||
|
@ -651,7 +650,7 @@ class PosixCondition<Thread> : public PosixConditionBase {
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
int priority() {
|
int priority() const {
|
||||||
WaitStarted();
|
WaitStarted();
|
||||||
int policy;
|
int policy;
|
||||||
sched_param param{};
|
sched_param param{};
|
||||||
|
@ -663,7 +662,7 @@ class PosixCondition<Thread> : public PosixConditionBase {
|
||||||
return param.sched_priority;
|
return param.sched_priority;
|
||||||
}
|
}
|
||||||
|
|
||||||
void set_priority(int new_priority) {
|
void set_priority(int new_priority) const {
|
||||||
WaitStarted();
|
WaitStarted();
|
||||||
sched_param param{};
|
sched_param param{};
|
||||||
param.sched_priority = new_priority;
|
param.sched_priority = new_priority;
|
||||||
|
@ -683,7 +682,7 @@ class PosixCondition<Thread> : public PosixConditionBase {
|
||||||
|
|
||||||
void QueueUserCallback(std::function<void()> callback) {
|
void QueueUserCallback(std::function<void()> callback) {
|
||||||
WaitStarted();
|
WaitStarted();
|
||||||
std::unique_lock<std::mutex> lock(callback_mutex_);
|
std::unique_lock lock(callback_mutex_);
|
||||||
user_callback_ = std::move(callback);
|
user_callback_ = std::move(callback);
|
||||||
sigval value{};
|
sigval value{};
|
||||||
value.sival_ptr = this;
|
value.sival_ptr = this;
|
||||||
|
@ -696,8 +695,8 @@ class PosixCondition<Thread> : public PosixConditionBase {
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
void CallUserCallback() {
|
void CallUserCallback() const {
|
||||||
std::unique_lock<std::mutex> lock(callback_mutex_);
|
std::unique_lock lock(callback_mutex_);
|
||||||
user_callback_();
|
user_callback_();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -706,7 +705,7 @@ class PosixCondition<Thread> : public PosixConditionBase {
|
||||||
*out_previous_suspend_count = 0;
|
*out_previous_suspend_count = 0;
|
||||||
}
|
}
|
||||||
WaitStarted();
|
WaitStarted();
|
||||||
std::unique_lock<std::mutex> lock(state_mutex_);
|
std::unique_lock lock(state_mutex_);
|
||||||
if (state_ != State::kSuspended) return false;
|
if (state_ != State::kSuspended) return false;
|
||||||
if (out_previous_suspend_count) {
|
if (out_previous_suspend_count) {
|
||||||
*out_previous_suspend_count = suspend_count_;
|
*out_previous_suspend_count = suspend_count_;
|
||||||
|
@ -736,7 +735,7 @@ class PosixCondition<Thread> : public PosixConditionBase {
|
||||||
void Terminate(int exit_code) {
|
void Terminate(int exit_code) {
|
||||||
bool is_current_thread = pthread_self() == thread_;
|
bool is_current_thread = pthread_self() == thread_;
|
||||||
{
|
{
|
||||||
std::unique_lock<std::mutex> lock(state_mutex_);
|
std::unique_lock lock(state_mutex_);
|
||||||
if (state_ == State::kFinished) {
|
if (state_ == State::kFinished) {
|
||||||
if (is_current_thread) {
|
if (is_current_thread) {
|
||||||
// This is really bad. Some thread must have called Terminate() on us
|
// This is really bad. Some thread must have called Terminate() on us
|
||||||
|
@ -752,7 +751,7 @@ class PosixCondition<Thread> : public PosixConditionBase {
|
||||||
}
|
}
|
||||||
|
|
||||||
{
|
{
|
||||||
std::lock_guard<std::mutex> lock(mutex_);
|
std::lock_guard lock(mutex_);
|
||||||
|
|
||||||
exit_code_ = exit_code;
|
exit_code_ = exit_code;
|
||||||
signaled_ = true;
|
signaled_ = true;
|
||||||
|
@ -760,29 +759,28 @@ class PosixCondition<Thread> : public PosixConditionBase {
|
||||||
}
|
}
|
||||||
if (is_current_thread) {
|
if (is_current_thread) {
|
||||||
pthread_exit(reinterpret_cast<void*>(exit_code));
|
pthread_exit(reinterpret_cast<void*>(exit_code));
|
||||||
} else {
|
|
||||||
#ifdef XE_PLATFORM_ANDROID
|
|
||||||
if (pthread_kill(thread_,
|
|
||||||
GetSystemSignal(SignalType::kThreadTerminate)) != 0) {
|
|
||||||
assert_always();
|
|
||||||
}
|
|
||||||
#else
|
|
||||||
if (pthread_cancel(thread_) != 0) {
|
|
||||||
assert_always();
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
}
|
}
|
||||||
|
#ifdef XE_PLATFORM_ANDROID
|
||||||
|
if (pthread_kill(thread_, GetSystemSignal(SignalType::kThreadTerminate)) !=
|
||||||
|
0) {
|
||||||
|
assert_always();
|
||||||
|
}
|
||||||
|
#else
|
||||||
|
if (pthread_cancel(thread_) != 0) {
|
||||||
|
assert_always();
|
||||||
|
}
|
||||||
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
void WaitStarted() const {
|
void WaitStarted() const {
|
||||||
std::unique_lock<std::mutex> lock(state_mutex_);
|
std::unique_lock lock(state_mutex_);
|
||||||
state_signal_.wait(lock,
|
state_signal_.wait(lock,
|
||||||
[this] { return state_ != State::kUninitialized; });
|
[this] { return state_ != State::kUninitialized; });
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Set state to suspended and wait until it reset by another thread
|
/// Set state to suspended and wait until it reset by another thread
|
||||||
void WaitSuspended() {
|
void WaitSuspended() {
|
||||||
std::unique_lock<std::mutex> lock(state_mutex_);
|
std::unique_lock lock(state_mutex_);
|
||||||
state_signal_.wait(lock, [this] { return suspend_count_ == 0; });
|
state_signal_.wait(lock, [this] { return suspend_count_ == 0; });
|
||||||
state_ = State::kRunning;
|
state_ = State::kRunning;
|
||||||
}
|
}
|
||||||
|
@ -793,8 +791,8 @@ class PosixCondition<Thread> : public PosixConditionBase {
|
||||||
|
|
||||||
private:
|
private:
|
||||||
static void* ThreadStartRoutine(void* parameter);
|
static void* ThreadStartRoutine(void* parameter);
|
||||||
inline bool signaled() const override { return signaled_; }
|
bool signaled() const override { return signaled_; }
|
||||||
inline void post_execution() override {
|
void post_execution() override {
|
||||||
if (thread_) {
|
if (thread_) {
|
||||||
pthread_join(thread_, nullptr);
|
pthread_join(thread_, nullptr);
|
||||||
}
|
}
|
||||||
|
@ -818,6 +816,7 @@ class PosixCondition<Thread> : public PosixConditionBase {
|
||||||
|
|
||||||
class PosixWaitHandle {
|
class PosixWaitHandle {
|
||||||
public:
|
public:
|
||||||
|
virtual ~PosixWaitHandle() = default;
|
||||||
virtual PosixConditionBase& condition() = 0;
|
virtual PosixConditionBase& condition() = 0;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -834,7 +833,9 @@ class PosixConditionHandle : public T, public PosixWaitHandle {
|
||||||
~PosixConditionHandle() override = default;
|
~PosixConditionHandle() override = default;
|
||||||
|
|
||||||
PosixCondition<T>& condition() override { return handle_; }
|
PosixCondition<T>& condition() override { return handle_; }
|
||||||
void* native_handle() const override { return handle_.native_handle(); }
|
[[nodiscard]] void* native_handle() const override {
|
||||||
|
return handle_.native_handle();
|
||||||
|
}
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
PosixCondition<T> handle_;
|
PosixCondition<T> handle_;
|
||||||
|
@ -915,7 +916,7 @@ std::pair<WaitResult, size_t> WaitMultiple(WaitHandle* wait_handles[],
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
class PosixEvent : public PosixConditionHandle<Event> {
|
class PosixEvent final : public PosixConditionHandle<Event> {
|
||||||
public:
|
public:
|
||||||
PosixEvent(bool manual_reset, bool initial_state)
|
PosixEvent(bool manual_reset, bool initial_state)
|
||||||
: PosixConditionHandle(manual_reset, initial_state) {}
|
: PosixConditionHandle(manual_reset, initial_state) {}
|
||||||
|
@ -944,7 +945,7 @@ std::unique_ptr<Event> Event::CreateAutoResetEvent(bool initial_state) {
|
||||||
return std::make_unique<PosixEvent>(false, initial_state);
|
return std::make_unique<PosixEvent>(false, initial_state);
|
||||||
}
|
}
|
||||||
|
|
||||||
class PosixSemaphore : public PosixConditionHandle<Semaphore> {
|
class PosixSemaphore final : public PosixConditionHandle<Semaphore> {
|
||||||
public:
|
public:
|
||||||
PosixSemaphore(int initial_count, int maximum_count)
|
PosixSemaphore(int initial_count, int maximum_count)
|
||||||
: PosixConditionHandle(static_cast<uint32_t>(initial_count),
|
: PosixConditionHandle(static_cast<uint32_t>(initial_count),
|
||||||
|
@ -968,7 +969,7 @@ std::unique_ptr<Semaphore> Semaphore::Create(int initial_count,
|
||||||
return std::make_unique<PosixSemaphore>(initial_count, maximum_count);
|
return std::make_unique<PosixSemaphore>(initial_count, maximum_count);
|
||||||
}
|
}
|
||||||
|
|
||||||
class PosixMutant : public PosixConditionHandle<Mutant> {
|
class PosixMutant final : public PosixConditionHandle<Mutant> {
|
||||||
public:
|
public:
|
||||||
explicit PosixMutant(bool initial_owner)
|
explicit PosixMutant(bool initial_owner)
|
||||||
: PosixConditionHandle(initial_owner) {}
|
: PosixConditionHandle(initial_owner) {}
|
||||||
|
@ -980,9 +981,9 @@ std::unique_ptr<Mutant> Mutant::Create(bool initial_owner) {
|
||||||
return std::make_unique<PosixMutant>(initial_owner);
|
return std::make_unique<PosixMutant>(initial_owner);
|
||||||
}
|
}
|
||||||
|
|
||||||
class PosixTimer : public PosixConditionHandle<Timer> {
|
class PosixTimer final : public PosixConditionHandle<Timer> {
|
||||||
using WClock_ = Timer::WClock_;
|
using WClock_ = WClock_;
|
||||||
using GClock_ = Timer::GClock_;
|
using GClock_ = GClock_;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
explicit PosixTimer(bool manual_reset) : PosixConditionHandle(manual_reset) {}
|
explicit PosixTimer(bool manual_reset) : PosixConditionHandle(manual_reset) {}
|
||||||
|
@ -1035,7 +1036,7 @@ std::unique_ptr<Timer> Timer::CreateSynchronizationTimer() {
|
||||||
return std::make_unique<PosixTimer>(false);
|
return std::make_unique<PosixTimer>(false);
|
||||||
}
|
}
|
||||||
|
|
||||||
class PosixThread : public PosixConditionHandle<Thread> {
|
class PosixThread final : public PosixConditionHandle<Thread> {
|
||||||
public:
|
public:
|
||||||
PosixThread() = default;
|
PosixThread() = default;
|
||||||
explicit PosixThread(pthread_t thread) : PosixConditionHandle(thread) {}
|
explicit PosixThread(pthread_t thread) : PosixConditionHandle(thread) {}
|
||||||
|
@ -1107,14 +1108,14 @@ void* PosixCondition<Thread>::ThreadStartRoutine(void* parameter) {
|
||||||
|
|
||||||
current_thread_ = thread;
|
current_thread_ = thread;
|
||||||
{
|
{
|
||||||
std::unique_lock<std::mutex> lock(thread->handle_.state_mutex_);
|
std::unique_lock lock(thread->handle_.state_mutex_);
|
||||||
thread->handle_.state_ =
|
thread->handle_.state_ =
|
||||||
create_suspended ? State::kSuspended : State::kRunning;
|
create_suspended ? State::kSuspended : State::kRunning;
|
||||||
thread->handle_.state_signal_.notify_all();
|
thread->handle_.state_signal_.notify_all();
|
||||||
}
|
}
|
||||||
|
|
||||||
if (create_suspended) {
|
if (create_suspended) {
|
||||||
std::unique_lock<std::mutex> lock(thread->handle_.state_mutex_);
|
std::unique_lock lock(thread->handle_.state_mutex_);
|
||||||
thread->handle_.suspend_count_ = 1;
|
thread->handle_.suspend_count_ = 1;
|
||||||
thread->handle_.state_signal_.wait(
|
thread->handle_.state_signal_.wait(
|
||||||
lock, [thread] { return thread->handle_.suspend_count_ == 0; });
|
lock, [thread] { return thread->handle_.suspend_count_ == 0; });
|
||||||
|
@ -1123,11 +1124,11 @@ void* PosixCondition<Thread>::ThreadStartRoutine(void* parameter) {
|
||||||
start_routine();
|
start_routine();
|
||||||
|
|
||||||
{
|
{
|
||||||
std::unique_lock<std::mutex> lock(thread->handle_.state_mutex_);
|
std::unique_lock lock(thread->handle_.state_mutex_);
|
||||||
thread->handle_.state_ = State::kFinished;
|
thread->handle_.state_ = State::kFinished;
|
||||||
}
|
}
|
||||||
|
|
||||||
std::unique_lock<std::mutex> lock(mutex_);
|
std::unique_lock lock(mutex_);
|
||||||
thread->handle_.exit_code_ = 0;
|
thread->handle_.exit_code_ = 0;
|
||||||
thread->handle_.signaled_ = true;
|
thread->handle_.signaled_ = true;
|
||||||
cond_.notify_all();
|
cond_.notify_all();
|
||||||
|
|
Loading…
Reference in New Issue