[threading linux] Implement native_handle

Move wait implementation to not use native_handle.
Implement native_handle for each primitive using posix natives.
This commit is contained in:
Sandy Carter 2019-07-19 10:41:18 -04:00 committed by Rick Gibbed
parent e945a13957
commit d7094fae52
1 changed files with 47 additions and 19 deletions

View File

@ -253,6 +253,8 @@ class PosixConditionBase {
} }
} }
virtual void* native_handle() const { return cond_.native_handle(); }
protected: protected:
inline virtual bool signaled() const = 0; inline virtual bool signaled() const = 0;
inline virtual void post_execution() = 0; inline virtual void post_execution() = 0;
@ -360,6 +362,8 @@ class PosixCondition<Mutant> : public PosixConditionBase {
return false; return false;
} }
void* native_handle() const override { return mutex_.native_handle(); }
private: private:
inline bool signaled() const override { inline bool signaled() const override {
return count_ == 0 || owner_ == std::this_thread::get_id(); return count_ == 0 || owner_ == std::this_thread::get_id();
@ -440,6 +444,10 @@ class PosixCondition<Timer> : public PosixConditionBase {
return result; return result;
} }
void* native_handle() const override {
return reinterpret_cast<void*>(timer_);
}
private: private:
inline bool signaled() const override { return signal_; } inline bool signaled() const override { return signal_; }
inline void post_execution() override { inline void post_execution() override {
@ -673,6 +681,10 @@ class PosixCondition<Thread> : public PosixConditionBase {
state_ = State::kRunning; state_ = State::kRunning;
} }
void* native_handle() const override {
return reinterpret_cast<void*>(thread_);
}
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_; }
@ -693,10 +705,15 @@ class PosixCondition<Thread> : public PosixConditionBase {
std::function<void()> user_callback_; std::function<void()> user_callback_;
}; };
class PosixWaitHandle {
public:
virtual PosixConditionBase& condition() = 0;
};
// 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
// native handle for higher level concurrency constructs such as semaphores // native handle for higher level concurrency constructs such as semaphores
template <typename T> template <typename T>
class PosixConditionHandle : public T { class PosixConditionHandle : public T, public PosixWaitHandle {
public: public:
PosixConditionHandle() = default; PosixConditionHandle() = default;
explicit PosixConditionHandle(bool); explicit PosixConditionHandle(bool);
@ -705,11 +722,10 @@ class PosixConditionHandle : public T {
PosixConditionHandle(uint32_t initial_count, uint32_t maximum_count); PosixConditionHandle(uint32_t initial_count, uint32_t maximum_count);
~PosixConditionHandle() override = default; ~PosixConditionHandle() override = default;
protected: PosixConditionBase& condition() override { return handle_; }
void* native_handle() const override { void* native_handle() const override { return handle_.native_handle(); }
return reinterpret_cast<void*>(const_cast<PosixCondition<T>*>(&handle_));
}
protected:
PosixCondition<T> handle_; PosixCondition<T> handle_;
friend PosixCondition<T>; friend PosixCondition<T>;
}; };
@ -738,10 +754,12 @@ PosixConditionHandle<Thread>::PosixConditionHandle(pthread_t thread)
WaitResult Wait(WaitHandle* wait_handle, bool is_alertable, WaitResult Wait(WaitHandle* wait_handle, bool is_alertable,
std::chrono::milliseconds timeout) { std::chrono::milliseconds timeout) {
auto handle = auto posix_wait_handle = dynamic_cast<PosixWaitHandle*>(wait_handle);
reinterpret_cast<PosixConditionBase*>(wait_handle->native_handle()); if (posix_wait_handle == nullptr) {
return WaitResult::kFailed;
}
if (is_alertable) alertable_state_ = true; if (is_alertable) alertable_state_ = true;
auto result = handle->Wait(timeout); auto result = posix_wait_handle->condition().Wait(timeout);
if (is_alertable) alertable_state_ = false; if (is_alertable) alertable_state_ = false;
return result; return result;
} }
@ -750,12 +768,18 @@ WaitResult SignalAndWait(WaitHandle* wait_handle_to_signal,
WaitHandle* wait_handle_to_wait_on, bool is_alertable, WaitHandle* wait_handle_to_wait_on, bool is_alertable,
std::chrono::milliseconds timeout) { std::chrono::milliseconds timeout) {
auto result = WaitResult::kFailed; auto result = WaitResult::kFailed;
auto handle_to_signal = reinterpret_cast<PosixConditionBase*>( auto posix_wait_handle_to_signal =
wait_handle_to_signal->native_handle()); dynamic_cast<PosixWaitHandle*>(wait_handle_to_signal);
auto handle_to_wait_on = reinterpret_cast<PosixConditionBase*>( auto posix_wait_handle_to_wait_on =
wait_handle_to_wait_on->native_handle()); dynamic_cast<PosixWaitHandle*>(wait_handle_to_wait_on);
if (posix_wait_handle_to_signal == nullptr ||
posix_wait_handle_to_wait_on == nullptr) {
return WaitResult::kFailed;
}
if (is_alertable) alertable_state_ = true; if (is_alertable) alertable_state_ = true;
if (handle_to_signal->Signal()) result = handle_to_wait_on->Wait(timeout); if (posix_wait_handle_to_signal->condition().Signal()) {
result = posix_wait_handle_to_wait_on->condition().Wait(timeout);
}
if (is_alertable) alertable_state_ = false; if (is_alertable) alertable_state_ = false;
return result; return result;
} }
@ -764,14 +788,18 @@ std::pair<WaitResult, size_t> WaitMultiple(WaitHandle* wait_handles[],
size_t wait_handle_count, size_t wait_handle_count,
bool wait_all, bool is_alertable, bool wait_all, bool is_alertable,
std::chrono::milliseconds timeout) { std::chrono::milliseconds timeout) {
std::vector<PosixConditionBase*> handles(wait_handle_count); std::vector<PosixConditionBase*> conditions;
for (int i = 0u; i < wait_handle_count; ++i) { conditions.reserve(wait_handle_count);
handles[i] = for (size_t i = 0u; i < wait_handle_count; ++i) {
reinterpret_cast<PosixConditionBase*>(wait_handles[i]->native_handle()); auto handle = dynamic_cast<PosixWaitHandle*>(wait_handles[i]);
if (handle == nullptr) {
return std::make_pair(WaitResult::kFailed, 0);
}
conditions.push_back(&handle->condition());
} }
if (is_alertable) alertable_state_ = true; if (is_alertable) alertable_state_ = true;
auto result = auto result = PosixConditionBase::WaitMultiple(std::move(conditions),
PosixConditionBase::WaitMultiple(std::move(handles), wait_all, timeout); wait_all, timeout);
if (is_alertable) alertable_state_ = false; if (is_alertable) alertable_state_ = false;
return result; return result;
} }