[threading linux] Implement Signal and Wait

Add Signal abstract function to handles.
Test SignalAndWait.
This commit is contained in:
Sandy Carter 2019-01-16 18:45:39 -08:00 committed by Rick Gibbed
parent cb905fb195
commit e11fa0372d
2 changed files with 35 additions and 6 deletions

View File

@ -227,8 +227,19 @@ TEST_CASE("Wait on Multiple Handles", "Wait") {
}
TEST_CASE("Signal and Wait") {
// TODO(bwrsandman): Test semaphore, mutex and event
REQUIRE(true);
WaitResult result;
auto mutant = Mutant::Create(true);
auto event_ = Event::CreateAutoResetEvent(false);
auto thread = Thread::Create({}, [&mutant, &event_] {
Wait(mutant.get(), false);
event_->Set();
});
result = Wait(event_.get(), false, 50ms);
REQUIRE(result == WaitResult::kTimeout);
result = SignalAndWait(mutant.get(), event_.get(), false, 50ms);
REQUIRE(result == WaitResult::kSuccess);
result = Wait(thread.get(), false, 50ms);
REQUIRE(result == WaitResult::kSuccess);
}
TEST_CASE("Wait on Event", "Event") {

View File

@ -179,6 +179,8 @@ std::unique_ptr<HighResolutionTimer> HighResolutionTimer::CreateRepeating(
class PosixConditionBase {
public:
virtual bool Signal() = 0;
WaitResult Wait(std::chrono::milliseconds timeout) {
bool executed;
auto predicate = [this] { return this->signaled(); };
@ -275,7 +277,7 @@ class PosixCondition<Event> : public PosixConditionBase {
: signal_(initial_state), manual_reset_(manual_reset) {}
virtual ~PosixCondition() = default;
void Signal() {
bool Signal() override {
auto lock = std::unique_lock<std::mutex>(mutex_);
signal_ = true;
if (manual_reset_) {
@ -285,6 +287,7 @@ class PosixCondition<Event> : public PosixConditionBase {
// See issue #1678 for possible fix and discussion
cond_.notify_one();
}
return true;
}
void Reset() {
@ -309,6 +312,8 @@ class PosixCondition<Semaphore> : public PosixConditionBase {
PosixCondition(uint32_t initial_count, uint32_t maximum_count)
: count_(initial_count), maximum_count_(maximum_count) {}
bool Signal() override { return Release(1, nullptr); }
bool Release(uint32_t release_count, int* out_previous_count) {
if (maximum_count_ - count_ >= release_count) {
auto lock = std::unique_lock<std::mutex>(mutex_);
@ -339,6 +344,9 @@ class PosixCondition<Mutant> : public PosixConditionBase {
owner_ = std::this_thread::get_id();
}
}
bool Signal() override { return Release(); }
bool Release() {
if (owner_ == std::this_thread::get_id() && count_ > 0) {
auto lock = std::unique_lock<std::mutex>(mutex_);
@ -375,6 +383,11 @@ class PosixCondition<Timer> : public PosixConditionBase {
virtual ~PosixCondition() { Cancel(); }
bool Signal() override {
CompletionRoutine();
return true;
}
// TODO(bwrsandman): due_times of under 1ms deadlock under travis
bool Set(std::chrono::nanoseconds due_time, std::chrono::milliseconds period,
std::function<void()> opt_callback = nullptr) {
@ -508,6 +521,8 @@ class PosixCondition<Thread> : public PosixConditionBase {
}
}
bool Signal() override { return true; }
std::string name() const {
WaitStarted();
auto result = std::array<char, 17>{'\0'};
@ -717,13 +732,16 @@ WaitResult Wait(WaitHandle* wait_handle, bool is_alertable,
return result;
}
// TODO(dougvj)
WaitResult SignalAndWait(WaitHandle* wait_handle_to_signal,
WaitHandle* wait_handle_to_wait_on, bool is_alertable,
std::chrono::milliseconds timeout) {
assert_always();
if (is_alertable) alertable_state_ = true;
auto result = WaitResult::kFailed;
auto handle_to_signal = reinterpret_cast<PosixConditionBase*>(
wait_handle_to_signal->native_handle());
auto handle_to_wait_on = reinterpret_cast<PosixConditionBase*>(
wait_handle_to_wait_on->native_handle());
if (is_alertable) alertable_state_ = true;
if (handle_to_signal->Signal()) result = handle_to_wait_on->Wait(timeout);
if (is_alertable) alertable_state_ = false;
return result;
}