|
|
@ -57,12 +57,24 @@ class Wakeable { |
|
|
|
inline ~Wakeable() {} |
|
|
|
inline ~Wakeable() {} |
|
|
|
}; |
|
|
|
}; |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
namespace activity_detail { |
|
|
|
|
|
|
|
struct Unwakeable final : public Wakeable { |
|
|
|
|
|
|
|
void Wakeup() override {} |
|
|
|
|
|
|
|
void Drop() override {} |
|
|
|
|
|
|
|
}; |
|
|
|
|
|
|
|
static Unwakeable* unwakeable() { |
|
|
|
|
|
|
|
return NoDestructSingleton<Unwakeable>::Get(); |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
} // namespace activity_detail
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
class AtomicWaker; |
|
|
|
|
|
|
|
|
|
|
|
// An owning reference to a Wakeable.
|
|
|
|
// An owning reference to a Wakeable.
|
|
|
|
// This type is non-copyable but movable.
|
|
|
|
// This type is non-copyable but movable.
|
|
|
|
class Waker { |
|
|
|
class Waker { |
|
|
|
public: |
|
|
|
public: |
|
|
|
explicit Waker(Wakeable* wakeable) : wakeable_(wakeable) {} |
|
|
|
explicit Waker(Wakeable* wakeable) : wakeable_(wakeable) {} |
|
|
|
Waker() : Waker(unwakeable()) {} |
|
|
|
Waker() : Waker(activity_detail::unwakeable()) {} |
|
|
|
~Waker() { wakeable_->Drop(); } |
|
|
|
~Waker() { wakeable_->Drop(); } |
|
|
|
Waker(const Waker&) = delete; |
|
|
|
Waker(const Waker&) = delete; |
|
|
|
Waker& operator=(const Waker&) = delete; |
|
|
|
Waker& operator=(const Waker&) = delete; |
|
|
@ -85,19 +97,50 @@ class Waker { |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
private: |
|
|
|
private: |
|
|
|
struct Unwakeable final : public Wakeable { |
|
|
|
friend class AtomicWaker; |
|
|
|
void Wakeup() override {} |
|
|
|
|
|
|
|
void Drop() override {} |
|
|
|
|
|
|
|
}; |
|
|
|
|
|
|
|
static Unwakeable* unwakeable() { |
|
|
|
|
|
|
|
return NoDestructSingleton<Unwakeable>::Get(); |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
Wakeable* Take() { return absl::exchange(wakeable_, unwakeable()); } |
|
|
|
Wakeable* Take() { |
|
|
|
|
|
|
|
return absl::exchange(wakeable_, activity_detail::unwakeable()); |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
Wakeable* wakeable_; |
|
|
|
Wakeable* wakeable_; |
|
|
|
}; |
|
|
|
}; |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// An atomic variant of Waker - this type is non-copyable and non-movable.
|
|
|
|
|
|
|
|
class AtomicWaker { |
|
|
|
|
|
|
|
public: |
|
|
|
|
|
|
|
explicit AtomicWaker(Wakeable* wakeable) : wakeable_(wakeable) {} |
|
|
|
|
|
|
|
AtomicWaker() : AtomicWaker(activity_detail::unwakeable()) {} |
|
|
|
|
|
|
|
explicit AtomicWaker(Waker waker) : AtomicWaker(waker.Take()) {} |
|
|
|
|
|
|
|
~AtomicWaker() { wakeable_.load(std::memory_order_acquire)->Drop(); } |
|
|
|
|
|
|
|
AtomicWaker(const AtomicWaker&) = delete; |
|
|
|
|
|
|
|
AtomicWaker& operator=(const AtomicWaker&) = delete; |
|
|
|
|
|
|
|
AtomicWaker(AtomicWaker&& other) noexcept = delete; |
|
|
|
|
|
|
|
AtomicWaker& operator=(AtomicWaker&& other) noexcept = delete; |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// Wake the underlying activity.
|
|
|
|
|
|
|
|
void Wakeup() { Take()->Wakeup(); } |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// Return true if there is a not-unwakeable wakeable present.
|
|
|
|
|
|
|
|
bool Armed() const noexcept { |
|
|
|
|
|
|
|
return wakeable_.load(std::memory_order_relaxed) != |
|
|
|
|
|
|
|
activity_detail::unwakeable(); |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// Set to some new waker
|
|
|
|
|
|
|
|
void Set(Waker waker) { |
|
|
|
|
|
|
|
wakeable_.exchange(waker.Take(), std::memory_order_acq_rel)->Wakeup(); |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
private: |
|
|
|
|
|
|
|
Wakeable* Take() { |
|
|
|
|
|
|
|
return wakeable_.exchange(activity_detail::unwakeable(), |
|
|
|
|
|
|
|
std::memory_order_acq_rel); |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
std::atomic<Wakeable*> wakeable_; |
|
|
|
|
|
|
|
}; |
|
|
|
|
|
|
|
|
|
|
|
// An Activity tracks execution of a single promise.
|
|
|
|
// An Activity tracks execution of a single promise.
|
|
|
|
// It executes the promise under a mutex.
|
|
|
|
// It executes the promise under a mutex.
|
|
|
|
// When the promise stalls, it registers the containing activity to be woken up
|
|
|
|
// When the promise stalls, it registers the containing activity to be woken up
|
|
|
|