[threading linux] Wait for thread start

This commit is contained in:
Sandy Carter 2019-01-11 15:36:42 -05:00 committed by Rick Gibbed
parent b91203a0b5
commit b2912e7891
1 changed files with 57 additions and 6 deletions

View File

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