diff --git a/src/xenia/base/threading_posix.cc b/src/xenia/base/threading_posix.cc index 65000203b..be0517fb8 100644 --- a/src/xenia/base/threading_posix.cc +++ b/src/xenia/base/threading_posix.cc @@ -435,8 +435,18 @@ struct ThreadStartData { template <> class PosixCondition : public PosixConditionBase { + enum class State { + kUninitialized, + kRunning, + kFinished, + }; + public: - PosixCondition() : thread_(0), signaled_(false), exit_code_(0) {} + PosixCondition() + : thread_(0), + signaled_(false), + exit_code_(0), + state_(State::kUninitialized) {} bool Initialize(Thread::CreationParameters params, ThreadStartData* start_data) { assert_false(params.create_suspended); @@ -468,7 +478,10 @@ class PosixCondition : public PosixConditionBase { /// Constructor for existing thread. This should only happen once called by /// Thread::GetCurrentThread() on the main thread explicit PosixCondition(pthread_t thread) - : thread_(thread), signaled_(false), exit_code_(0) {} + : thread_(thread), + signaled_(false), + exit_code_(0), + state_(State::kRunning) {} virtual ~PosixCondition() { if (thread_ && !signaled_) { @@ -482,20 +495,29 @@ class PosixCondition : public PosixConditionBase { } std::string name() const { + WaitStarted(); auto result = std::array{'\0'}; - if (pthread_getname_np(thread_, result.data(), result.size() - 1) != 0) - assert_always(); + std::unique_lock lock(state_mutex_); + if (state_ != State::kUninitialized && state_ != State::kFinished) { + if (pthread_getname_np(thread_, result.data(), result.size() - 1) != 0) + assert_always(); + } return std::string(result.data()); } void set_name(const std::string& name) { - threading::set_name(static_cast(thread_), - name); + WaitStarted(); + std::unique_lock lock(state_mutex_); + if (state_ != State::kUninitialized && state_ != State::kFinished) { + threading::set_name(static_cast(thread_), + name); + } } uint32_t system_id() const { return static_cast(thread_); } uint64_t affinity_mask() { + WaitStarted(); cpu_set_t cpu_set; if (pthread_getaffinity_np(thread_, sizeof(cpu_set_t), &cpu_set) != 0) assert_always(); @@ -509,6 +531,7 @@ class PosixCondition : public PosixConditionBase { } void set_affinity_mask(uint64_t mask) { + WaitStarted(); cpu_set_t cpu_set; CPU_ZERO(&cpu_set); for (auto i = 0u; i < 64; i++) { @@ -522,6 +545,7 @@ class PosixCondition : public PosixConditionBase { } int priority() { + WaitStarted(); int policy; sched_param param{}; int ret = pthread_getschedparam(thread_, &policy, ¶m); @@ -533,6 +557,7 @@ class PosixCondition : public PosixConditionBase { } void set_priority(int new_priority) { + WaitStarted(); sched_param param{}; param.sched_priority = new_priority; if (pthread_setschedparam(thread_, SCHED_FIFO, ¶m) != 0) @@ -557,6 +582,11 @@ class PosixCondition : public PosixConditionBase { } void Terminate(int exit_code) { + { + std::unique_lock lock(state_mutex_); + state_ = State::kFinished; + } + std::lock_guard lock(mutex_); // Sometimes the thread can call terminate twice before stopping @@ -570,6 +600,12 @@ class PosixCondition : public PosixConditionBase { if (pthread_cancel(thread) != 0) assert_always(); } + void WaitStarted() const { + std::unique_lock lock(state_mutex_); + state_signal_.wait(lock, + [this] { return state_ != State::kUninitialized; }); + } + private: static void* ThreadStartRoutine(void* parameter); inline bool signaled() const override { return signaled_; } @@ -582,6 +618,9 @@ class PosixCondition : public PosixConditionBase { pthread_t thread_; bool signaled_; int exit_code_; + State state_; + mutable std::mutex state_mutex_; + mutable std::condition_variable state_signal_; }; // This wraps a condition object as our handle because posix has no single @@ -752,6 +791,7 @@ class PosixThread : public PosixConditionHandle { } void set_name(std::string name) override { + handle_.WaitStarted(); Thread::set_name(name); if (name.length() > 15) { name = name.substr(0, 15); @@ -803,8 +843,19 @@ void* PosixCondition::ThreadStartRoutine(void* parameter) { delete start_data; current_thread_ = thread; + { + std::unique_lock lock(thread->handle_.state_mutex_); + thread->handle_.state_ = State::kRunning; + thread->handle_.state_signal_.notify_all(); + } + start_routine(); + { + std::unique_lock lock(thread->handle_.state_mutex_); + thread->handle_.state_ = State::kFinished; + } + std::unique_lock lock(mutex_); thread->handle_.exit_code_ = 0; thread->handle_.signaled_ = true;