diff --git a/src/xenia/base/clock_posix.cc b/src/xenia/base/clock_posix.cc index 73a23dc76..1dd155f8f 100644 --- a/src/xenia/base/clock_posix.cc +++ b/src/xenia/base/clock_posix.cc @@ -53,4 +53,5 @@ uint64_t Clock::QueryHostUptimeMillis() { return host_tick_count_platform() * 1000 / host_tick_frequency_platform(); } +uint64_t Clock::QueryHostInterruptTime() { return host_tick_count_platform(); } } // namespace xe diff --git a/src/xenia/base/main_init_posix.cc b/src/xenia/base/main_init_posix.cc new file mode 100644 index 000000000..651d26903 --- /dev/null +++ b/src/xenia/base/main_init_posix.cc @@ -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 +#include +#include + +#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; \ No newline at end of file diff --git a/src/xenia/base/threading_posix.cc b/src/xenia/base/threading_posix.cc index b35a30e73..1d4e5cfe8 100644 --- a/src/xenia/base/threading_posix.cc +++ b/src/xenia/base/threading_posix.cc @@ -82,8 +82,7 @@ void AndroidShutdown() { #endif template -inline timespec DurationToTimeSpec( - std::chrono::duration<_Rep, _Period> duration) { +timespec DurationToTimeSpec(std::chrono::duration<_Rep, _Period> duration) { auto nanoseconds = std::chrono::duration_cast(duration); auto div = ldiv(nanoseconds.count(), 1000000000L); @@ -161,6 +160,8 @@ void Sleep(std::chrono::microseconds duration) { } 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 thread_local bool alertable_state_ = false; SleepResult AlertableSleep(std::chrono::microseconds duration) { @@ -178,28 +179,25 @@ TlsHandle AllocateTlsHandle() { return static_cast(key); } -bool FreeTlsHandle(TlsHandle handle) { - return pthread_key_delete(static_cast(handle)) == 0; -} +bool FreeTlsHandle(TlsHandle handle) { return pthread_key_delete(handle) == 0; } uintptr_t GetTlsValue(TlsHandle handle) { - return reinterpret_cast( - pthread_getspecific(static_cast(handle))); + return reinterpret_cast(pthread_getspecific(handle)); } bool SetTlsValue(TlsHandle handle, uintptr_t value) { - return pthread_setspecific(static_cast(handle), - reinterpret_cast(value)) == 0; + return pthread_setspecific(handle, reinterpret_cast(value)) == 0; } class PosixConditionBase { public: + virtual ~PosixConditionBase() = default; virtual bool Signal() = 0; WaitResult Wait(std::chrono::milliseconds timeout) { bool executed; auto predicate = [this] { return this->signaled(); }; - auto lock = std::unique_lock(mutex_); + auto lock = std::unique_lock(mutex_); if (predicate()) { executed = true; } else { @@ -213,15 +211,14 @@ class PosixConditionBase { if (executed) { post_execution(); return WaitResult::kSuccess; - } else { - return WaitResult::kTimeout; } + return WaitResult::kTimeout; } static std::pair WaitMultiple( std::vector&& handles, bool wait_all, std::chrono::milliseconds timeout) { - assert_true(handles.size() > 0); + assert_true(!handles.empty()); // Construct a condition for all or any depending on wait_all std::function predicate; @@ -239,17 +236,16 @@ class PosixConditionBase { // TODO(bwrsandman, Triang3l) This is controversial, see issue #1677 // This will probably cause a deadlock on the next thread doing any waiting // if the thread is suspended between locking and waiting - std::unique_lock lock(PosixConditionBase::mutex_); + std::unique_lock lock(mutex_); bool wait_success = true; // If the timeout is infinite, wait without timeout. // The predicate will be checked before beginning the wait if (timeout == std::chrono::milliseconds::max()) { - PosixConditionBase::cond_.wait(lock, predicate); + cond_.wait(lock, predicate); } else { // Wait with timeout. - wait_success = - PosixConditionBase::cond_.wait_for(lock, timeout, predicate); + wait_success = cond_.wait_for(lock, timeout, predicate); } if (wait_success) { auto first_signaled = std::numeric_limits::max(); @@ -264,15 +260,16 @@ class PosixConditionBase { } assert_true(std::numeric_limits::max() != first_signaled); return std::make_pair(WaitResult::kSuccess, first_signaled); - } else { - return std::make_pair(WaitResult::kTimeout, 0); } + return std::make_pair(WaitResult::kTimeout, 0); } - virtual void* native_handle() const { return cond_.native_handle(); } + [[nodiscard]] virtual void* native_handle() const { + return cond_.native_handle(); + } protected: - inline virtual bool signaled() const = 0; + [[nodiscard]] inline virtual bool signaled() const = 0; inline virtual void post_execution() = 0; static std::condition_variable cond_; static std::mutex mutex_; @@ -293,23 +290,23 @@ class PosixCondition : public PosixConditionBase { public: PosixCondition(bool manual_reset, bool initial_state) : signal_(initial_state), manual_reset_(manual_reset) {} - virtual ~PosixCondition() = default; + ~PosixCondition() override = default; bool Signal() override { - auto lock = std::unique_lock(mutex_); + auto lock = std::unique_lock(mutex_); signal_ = true; cond_.notify_all(); return true; } void Reset() { - auto lock = std::unique_lock(mutex_); + auto lock = std::unique_lock(mutex_); signal_ = false; } private: - inline bool signaled() const override { return signal_; } - inline void post_execution() override { + [[nodiscard]] bool signaled() const override { return signal_; } + void post_execution() override { if (!manual_reset_) { signal_ = false; } @@ -319,7 +316,7 @@ class PosixCondition : public PosixConditionBase { }; template <> -class PosixCondition : public PosixConditionBase { +class PosixCondition final : public PosixConditionBase { public: PosixCondition(uint32_t initial_count, uint32_t maximum_count) : count_(initial_count), maximum_count_(maximum_count) {} @@ -328,7 +325,7 @@ class PosixCondition : public PosixConditionBase { bool Release(uint32_t release_count, int* out_previous_count) { if (maximum_count_ - count_ >= release_count) { - auto lock = std::unique_lock(mutex_); + auto lock = std::unique_lock(mutex_); if (out_previous_count) *out_previous_count = count_; count_ += release_count; cond_.notify_all(); @@ -338,8 +335,8 @@ class PosixCondition : public PosixConditionBase { } private: - inline bool signaled() const override { return count_ > 0; } - inline void post_execution() override { + [[nodiscard]] bool signaled() const override { return count_ > 0; } + void post_execution() override { count_--; cond_.notify_all(); } @@ -348,7 +345,7 @@ class PosixCondition : public PosixConditionBase { }; template <> -class PosixCondition : public PosixConditionBase { +class PosixCondition final : public PosixConditionBase { public: explicit PosixCondition(bool initial_owner) : count_(0) { if (initial_owner) { @@ -361,7 +358,7 @@ class PosixCondition : public PosixConditionBase { bool Release() { if (owner_ == std::this_thread::get_id() && count_ > 0) { - auto lock = std::unique_lock(mutex_); + auto lock = std::unique_lock(mutex_); --count_; // Free to be acquired by another thread if (count_ == 0) { @@ -372,13 +369,15 @@ class PosixCondition : public PosixConditionBase { return false; } - void* native_handle() const override { return mutex_.native_handle(); } + [[nodiscard]] void* native_handle() const override { + return mutex_.native_handle(); + } private: - inline bool signaled() const override { + [[nodiscard]] bool signaled() const override { return count_ == 0 || owner_ == std::this_thread::get_id(); } - inline void post_execution() override { + void post_execution() override { count_++; owner_ = std::this_thread::get_id(); } @@ -387,15 +386,15 @@ class PosixCondition : public PosixConditionBase { }; template <> -class PosixCondition : public PosixConditionBase { +class PosixCondition final : public PosixConditionBase { public: explicit PosixCondition(bool manual_reset) : callback_(nullptr), signal_(false), manual_reset_(manual_reset) {} - virtual ~PosixCondition() { Cancel(); } + ~PosixCondition() override { Cancel(); } bool Signal() override { - std::lock_guard lock(mutex_); + std::lock_guard lock(mutex_); signal_ = true; cond_.notify_all(); return true; @@ -405,7 +404,7 @@ class PosixCondition : public PosixConditionBase { std::function opt_callback) { Cancel(); - std::lock_guard lock(mutex_); + std::lock_guard lock(mutex_); callback_ = std::move(opt_callback); signal_ = false; @@ -417,7 +416,7 @@ class PosixCondition : public PosixConditionBase { std::function opt_callback) { Cancel(); - std::lock_guard lock(mutex_); + std::lock_guard lock(mutex_); callback_ = std::move(opt_callback); signal_ = false; @@ -425,13 +424,13 @@ class PosixCondition : public PosixConditionBase { QueueTimerRecurring(&CompletionRoutine, this, due_time, period); } - void Cancel() { + void Cancel() const { if (auto wait_item = wait_item_.lock()) { wait_item->Disarm(); } } - void* native_handle() const override { + [[nodiscard]] void* native_handle() const override { assert_always(); return nullptr; } @@ -439,12 +438,12 @@ class PosixCondition : public PosixConditionBase { private: static void CompletionRoutine(void* userdata) { assert_not_null(userdata); - auto timer = reinterpret_cast*>(userdata); + auto timer = static_cast(userdata); timer->Signal(); // As the callback may reset the timer, store local. std::function callback; { - std::lock_guard lock(timer->mutex_); + std::lock_guard lock(timer->mutex_); callback = timer->callback_; } if (callback) { @@ -452,9 +451,8 @@ class PosixCondition : public PosixConditionBase { } } - private: - inline bool signaled() const override { return signal_; } - inline void post_execution() override { + [[nodiscard]] bool signaled() const override { return signal_; } + void post_execution() override { if (!manual_reset_) { signal_ = false; } @@ -472,7 +470,7 @@ struct ThreadStartData { }; template <> -class PosixCondition : public PosixConditionBase { +class PosixCondition final : public PosixConditionBase { enum class State { kUninitialized, kRunning, @@ -526,13 +524,14 @@ class PosixCondition : public PosixConditionBase { : thread_(thread), signaled_(false), exit_code_(0), - state_(State::kRunning) { + state_(State::kRunning), + suspend_count_(0) { #if XE_PLATFORM_ANDROID android_pre_api_26_name_[0] = '\0'; #endif } - virtual ~PosixCondition() { + ~PosixCondition() override { // FIXME(RodoMa92): This causes random crashes. // The proper way to handle them according to the webs is properly shutdown // instead on relying on killing them using pthread_cancel. @@ -560,7 +559,7 @@ class PosixCondition : public PosixConditionBase { std::string name() const { WaitStarted(); auto result = std::array{'\0'}; - std::unique_lock lock(state_mutex_); + std::unique_lock lock(state_mutex_); if (state_ != State::kUninitialized && state_ != State::kFinished) { #if XE_PLATFORM_ANDROID // pthread_getname_np was added in API 26 - below that, store the name in @@ -584,7 +583,7 @@ class PosixCondition : public PosixConditionBase { return std::string(result.data()); } - void set_name(const std::string& name) { + void set_name(const std::string& name) const { WaitStarted(); std::unique_lock lock(state_mutex_); if (state_ != State::kUninitialized && state_ != State::kFinished) { @@ -608,7 +607,7 @@ class PosixCondition : public PosixConditionBase { uint32_t system_id() const { return static_cast(thread_); } - uint64_t affinity_mask() { + uint64_t affinity_mask() const { WaitStarted(); cpu_set_t cpu_set; #if XE_PLATFORM_ANDROID @@ -630,7 +629,7 @@ class PosixCondition : public PosixConditionBase { return result; } - void set_affinity_mask(uint64_t mask) { + void set_affinity_mask(uint64_t mask) const { WaitStarted(); cpu_set_t cpu_set; CPU_ZERO(&cpu_set); @@ -651,7 +650,7 @@ class PosixCondition : public PosixConditionBase { #endif } - int priority() { + int priority() const { WaitStarted(); int policy; sched_param param{}; @@ -663,7 +662,7 @@ class PosixCondition : public PosixConditionBase { return param.sched_priority; } - void set_priority(int new_priority) { + void set_priority(int new_priority) const { WaitStarted(); sched_param param{}; param.sched_priority = new_priority; @@ -683,7 +682,7 @@ class PosixCondition : public PosixConditionBase { void QueueUserCallback(std::function callback) { WaitStarted(); - std::unique_lock lock(callback_mutex_); + std::unique_lock lock(callback_mutex_); user_callback_ = std::move(callback); sigval value{}; value.sival_ptr = this; @@ -696,8 +695,8 @@ class PosixCondition : public PosixConditionBase { #endif } - void CallUserCallback() { - std::unique_lock lock(callback_mutex_); + void CallUserCallback() const { + std::unique_lock lock(callback_mutex_); user_callback_(); } @@ -706,7 +705,7 @@ class PosixCondition : public PosixConditionBase { *out_previous_suspend_count = 0; } WaitStarted(); - std::unique_lock lock(state_mutex_); + std::unique_lock lock(state_mutex_); if (state_ != State::kSuspended) return false; if (out_previous_suspend_count) { *out_previous_suspend_count = suspend_count_; @@ -736,7 +735,7 @@ class PosixCondition : public PosixConditionBase { void Terminate(int exit_code) { bool is_current_thread = pthread_self() == thread_; { - std::unique_lock lock(state_mutex_); + std::unique_lock lock(state_mutex_); if (state_ == State::kFinished) { if (is_current_thread) { // This is really bad. Some thread must have called Terminate() on us @@ -752,7 +751,7 @@ class PosixCondition : public PosixConditionBase { } { - std::lock_guard lock(mutex_); + std::lock_guard lock(mutex_); exit_code_ = exit_code; signaled_ = true; @@ -760,29 +759,28 @@ class PosixCondition : public PosixConditionBase { } if (is_current_thread) { pthread_exit(reinterpret_cast(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 { - std::unique_lock lock(state_mutex_); + std::unique_lock lock(state_mutex_); state_signal_.wait(lock, [this] { return state_ != State::kUninitialized; }); } /// Set state to suspended and wait until it reset by another thread void WaitSuspended() { - std::unique_lock lock(state_mutex_); + std::unique_lock lock(state_mutex_); state_signal_.wait(lock, [this] { return suspend_count_ == 0; }); state_ = State::kRunning; } @@ -793,8 +791,8 @@ class PosixCondition : public PosixConditionBase { private: static void* ThreadStartRoutine(void* parameter); - inline bool signaled() const override { return signaled_; } - inline void post_execution() override { + bool signaled() const override { return signaled_; } + void post_execution() override { if (thread_) { pthread_join(thread_, nullptr); } @@ -818,6 +816,7 @@ class PosixCondition : public PosixConditionBase { class PosixWaitHandle { public: + virtual ~PosixWaitHandle() = default; virtual PosixConditionBase& condition() = 0; }; @@ -834,7 +833,9 @@ class PosixConditionHandle : public T, public PosixWaitHandle { ~PosixConditionHandle() override = default; PosixCondition& condition() override { return handle_; } - void* native_handle() const override { return handle_.native_handle(); } + [[nodiscard]] void* native_handle() const override { + return handle_.native_handle(); + } protected: PosixCondition handle_; @@ -915,7 +916,7 @@ std::pair WaitMultiple(WaitHandle* wait_handles[], return result; } -class PosixEvent : public PosixConditionHandle { +class PosixEvent final : public PosixConditionHandle { public: PosixEvent(bool manual_reset, bool initial_state) : PosixConditionHandle(manual_reset, initial_state) {} @@ -944,7 +945,7 @@ std::unique_ptr Event::CreateAutoResetEvent(bool initial_state) { return std::make_unique(false, initial_state); } -class PosixSemaphore : public PosixConditionHandle { +class PosixSemaphore final : public PosixConditionHandle { public: PosixSemaphore(int initial_count, int maximum_count) : PosixConditionHandle(static_cast(initial_count), @@ -968,7 +969,7 @@ std::unique_ptr Semaphore::Create(int initial_count, return std::make_unique(initial_count, maximum_count); } -class PosixMutant : public PosixConditionHandle { +class PosixMutant final : public PosixConditionHandle { public: explicit PosixMutant(bool initial_owner) : PosixConditionHandle(initial_owner) {} @@ -980,9 +981,9 @@ std::unique_ptr Mutant::Create(bool initial_owner) { return std::make_unique(initial_owner); } -class PosixTimer : public PosixConditionHandle { - using WClock_ = Timer::WClock_; - using GClock_ = Timer::GClock_; +class PosixTimer final : public PosixConditionHandle { + using WClock_ = WClock_; + using GClock_ = GClock_; public: explicit PosixTimer(bool manual_reset) : PosixConditionHandle(manual_reset) {} @@ -1035,7 +1036,7 @@ std::unique_ptr Timer::CreateSynchronizationTimer() { return std::make_unique(false); } -class PosixThread : public PosixConditionHandle { +class PosixThread final : public PosixConditionHandle { public: PosixThread() = default; explicit PosixThread(pthread_t thread) : PosixConditionHandle(thread) {} @@ -1107,14 +1108,14 @@ void* PosixCondition::ThreadStartRoutine(void* parameter) { current_thread_ = thread; { - std::unique_lock lock(thread->handle_.state_mutex_); + std::unique_lock lock(thread->handle_.state_mutex_); thread->handle_.state_ = create_suspended ? State::kSuspended : State::kRunning; thread->handle_.state_signal_.notify_all(); } if (create_suspended) { - std::unique_lock lock(thread->handle_.state_mutex_); + std::unique_lock lock(thread->handle_.state_mutex_); thread->handle_.suspend_count_ = 1; thread->handle_.state_signal_.wait( lock, [thread] { return thread->handle_.suspend_count_ == 0; }); @@ -1123,11 +1124,11 @@ void* PosixCondition::ThreadStartRoutine(void* parameter) { start_routine(); { - std::unique_lock lock(thread->handle_.state_mutex_); + std::unique_lock lock(thread->handle_.state_mutex_); thread->handle_.state_ = State::kFinished; } - std::unique_lock lock(mutex_); + std::unique_lock lock(mutex_); thread->handle_.exit_code_ = 0; thread->handle_.signaled_ = true; cond_.notify_all();