Skip to content

Commit 23e6a38

Browse files
committed
refactor coroutine cancelled set
1 parent 6511af9 commit 23e6a38

File tree

4 files changed

+46
-19
lines changed

4 files changed

+46
-19
lines changed

include/asyncio/event_loop.h

Lines changed: 22 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@
88
#include <asyncio/concept/future.h>
99
#include <asyncio/selector/selector.h>
1010
#include <utility>
11-
#include <set>
11+
#include <unordered_set>
1212
#include <algorithm>
1313
#include <queue>
1414
#include <chrono>
@@ -17,10 +17,16 @@
1717
ASYNCIO_NS_BEGIN
1818
class EventLoop: private NonCopyable {
1919
using MSDuration = std::chrono::milliseconds;
20+
// handle maybe destroyed, using the increasing id to track the lifetime of handle.
21+
// don't directly using a raw pointer to track coroutine lifetime,
22+
// because a destroyed coroutine may has the same address as a new ready coroutine has created.
23+
struct HandleInfo {
24+
HandleId id;
25+
Handle* handle;
26+
};
2027

2128
public:
22-
EventLoop() {
23-
auto now = std::chrono::system_clock::now();
29+
EventLoop() { auto now = std::chrono::system_clock::now();
2430
start_time_ = duration_cast<MSDuration>(now.time_since_epoch());
2531
}
2632

@@ -29,6 +35,10 @@ class EventLoop: private NonCopyable {
2935
return duration_cast<MSDuration>(now.time_since_epoch()) - start_time_;
3036
}
3137

38+
HandleId allocate_handle_id() {
39+
return handle_alloc_id_++;
40+
}
41+
3242
bool is_stop() {
3343
return schedule_.empty() && ready_.empty() && selector_.is_stop();
3444
}
@@ -41,17 +51,18 @@ class EventLoop: private NonCopyable {
4151
template<typename Rep, typename Period>
4252
void call_at(std::chrono::duration<Rep, Period> when, Handle& callback) {
4353
callback.set_state(PromiseState::PENDING);
44-
schedule_.emplace_back(std::make_pair(duration_cast<MSDuration>(when), &callback));
54+
schedule_.emplace_back(std::make_pair(duration_cast<MSDuration>(when),
55+
HandleInfo{callback.get_handle_id(), &callback}));
4556
std::ranges::push_heap(schedule_, std::ranges::greater{}, &TimerHandle::first);
4657
}
4758

4859
void cancel_handle(Handle& handle) {
49-
cancelled_.insert(&handle);
60+
cancelled_.insert(handle.get_handle_id());
5061
}
5162

5263
void call_soon(Handle& callback) {
5364
callback.set_state(PromiseState::PENDING);
54-
ready_.emplace(&callback);
65+
ready_.push({callback.get_handle_id(), &callback});
5566
}
5667

5768
template<concepts::Future Fut>
@@ -90,14 +101,15 @@ class EventLoop: private NonCopyable {
90101

91102
private:
92103
MSDuration start_time_;
93-
std::queue<Handle*> ready_;
94-
std::set<Handle*> cancelled_;
104+
std::queue<HandleInfo> ready_;
105+
std::unordered_set<HandleId> cancelled_;
95106
Selector selector_;
96-
using TimerHandle = std::pair<MSDuration, Handle*>;
107+
using TimerHandle = std::pair<MSDuration, HandleInfo>;
97108
std::vector<TimerHandle> schedule_; // min time heap
109+
static HandleId handle_alloc_id_;
98110
};
99111

100112
EventLoop& get_event_loop();
101113
ASYNCIO_NS_END
102114

103-
#endif // ASYNCIO_EVENT_LOOP_H
115+
#endif // ASYNCIO_EVENT_LOOP_H

include/asyncio/handle.h

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,9 @@ enum class PromiseState: uint8_t {
1515
PENDING,
1616
};
1717

18+
// for cancelled
19+
using HandleId = uint64_t;
20+
1821
struct Handle { // type erase for EventLoop
1922
virtual void run() = 0;
2023
std::string frame_name() const {
@@ -24,12 +27,18 @@ struct Handle { // type erase for EventLoop
2427
}
2528
virtual void dump_backtrace(size_t depth = 0) const {};
2629
virtual void set_state(PromiseState state) {}
30+
HandleId get_handle_id() { return handle_id_; }
31+
Handle() noexcept;
2732
virtual ~Handle() = default;
33+
2834
private:
2935
virtual const std::source_location& get_frame_info() const {
3036
static const std::source_location frame_info = std::source_location::current();
3137
return frame_info;
3238
}
39+
40+
private:
41+
HandleId handle_id_;
3342
};
3443

3544
ASYNCIO_NS_END

include/asyncio/task.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -148,4 +148,4 @@ struct Task: private NonCopyable {
148148
};
149149

150150
ASYNCIO_NS_END
151-
#endif // ASYNCIO_TASK_H
151+
#endif // ASYNCIO_TASK_H

src/event_loop.cpp

Lines changed: 14 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -23,8 +23,8 @@ void EventLoop::run_once() {
2323
std::optional<MSDuration> timeout;
2424
// Remove delayed calls that were cancelled from head of queue.
2525
while (! schedule_.empty()) {
26-
auto&& [when, handle] = schedule_[0];
27-
if (auto iter = cancelled_.find(handle); iter != cancelled_.end()) {
26+
auto&& [when, handle_info] = schedule_[0];
27+
if (auto iter = cancelled_.find(handle_info.id); iter != cancelled_.end()) {
2828
ranges::pop_heap(schedule_,std::ranges::greater{}, &TimerHandle::first);
2929
schedule_.pop_back();
3030
cancelled_.erase(iter);
@@ -43,27 +43,33 @@ void EventLoop::run_once() {
4343
auto event_lists = selector_.select(timeout.has_value() ? timeout->count() : -1);
4444
for (auto&& event: event_lists) {
4545
Handle* continuation_ = reinterpret_cast<Handle*>(event.data);
46-
ready_.emplace(continuation_);
46+
ready_.push({continuation_->get_handle_id(), continuation_});
4747
}
4848

4949
auto end_time = time();
5050
while (! schedule_.empty()) {
51-
auto&& [when, handle] = schedule_[0];
51+
auto&& [when, handle_info] = schedule_[0];
5252
if (when >= end_time) break;
53-
ready_.emplace(handle);
53+
ready_.push(handle_info);
5454
ranges::pop_heap(schedule_,std::ranges::greater{}, &TimerHandle::first);
5555
schedule_.pop_back();
5656
}
5757

5858
for (size_t ntodo = ready_.size(), i = 0; i < ntodo ; ++i ) {
59-
auto handle = ready_.front();
59+
auto [handle_id, handle] = ready_.front();
6060
ready_.pop();
61-
if (auto iter = cancelled_.find(handle); iter != cancelled_.end()) {
61+
if (auto iter = cancelled_.find(handle_id); iter != cancelled_.end()) {
6262
cancelled_.erase(iter);
6363
} else {
6464
handle->run();
6565
}
6666
}
6767
}
6868

69-
ASYNCIO_NS_END
69+
HandleId EventLoop::handle_alloc_id_ = 0;
70+
71+
Handle::Handle() noexcept {
72+
auto& loop = get_event_loop();
73+
handle_id_ = loop.allocate_handle_id();
74+
}
75+
ASYNCIO_NS_END

0 commit comments

Comments
 (0)