handle.h
Handle是一个纯虚类(run函数),当CoroHandle父类。
CoroHandle也是一个抽象类,run函数还没实现。
Task::promise_type会继承CoroHandle
namespace ASYNCIO_NS {
// for cancelled
using HandleId = uint64_t;
/*
句柄类,回调类
*/
struct Handle { // type erase for EventLoop
enum State: uint8_t { // 句柄状态
UNSCHEDULED,
SUSPEND,
SCHEDULED,
};
Handle() noexcept: handle_id_(handle_id_generation_++) {}
virtual void run() = 0;
void set_state(State state) { state_ = state; }
HandleId get_handle_id() { return handle_id_; }
virtual ~Handle() = default;
private:
HandleId handle_id_;
static HandleId handle_id_generation_;
protected:
State state_ {Handle::UNSCHEDULED};
};
// handle maybe destroyed, using the increasing id to track the lifetime of handle.
// don't directly using a raw pointer to track coroutine lifetime,
// because a destroyed coroutine may has the same address as a new ready coroutine has created.
/*
通过id来追踪句柄
*/
struct HandleInfo {
HandleId id { }; // id(递增)
Handle* handle { }; // 处理句柄(回调函数)
};
/*
协程句柄类
实现在event_loop.cpp
*/
struct CoroHandle: Handle {
std::string frame_name() const {
const auto& frame_info = get_frame_info();
return fmt::format("{} at {}:{}", frame_info.function_name(),
frame_info.file_name(), frame_info.line());
}
virtual void dump_backtrace(size_t depth = 0) const {};
/*
调度: call_soon
*/
void CoroHandle::schedule() {
if (state_ == Handle::UNSCHEDULED){
get_event_loop().call_soon(*this);
}
}
/*
取消调度:cancel_handle
*/
void CoroHandle::cancel() {
if (state_ != Handle::UNSCHEDULED){
get_event_loop().cancel_handle(*this);
}
}
private:
virtual const std::source_location& get_frame_info() const;
};
selector 封装epoll
d1ad1
- selector.h
using Selector = EpollSelector;
- event.h
namespace ASYNCIO_NS {
/*
事件类:包括事件类型以及对应的回调函数(事件处理句柄)
*/
struct Event {
enum Flags: Flags_t {
EVENT_READ = EPOLLIN,
EVENT_WRITE = EPOLLOUT
};
int fd; // fd
Flags flags; // 事件类型
HandleInfo handle_info; // 处理句柄(回调函数)
};
}
- epoll_selector.h:封装epoll
namespace ASYNCIO_NS {
struct EpollSelector {
EpollSelector(): epfd_(epoll_create1(0)) {
if (epfd_ < 0) {
perror("epoll_create1");
throw;
}
}
/*
epoll_wait将就绪事件的句柄返回
*/
std::vector<Event> select(int timeout /* ms */) {
errno = 0;
std::vector<epoll_event> events;
events.resize(register_event_count_);
int ndfs = epoll_wait(epfd_, events.data(), register_event_count_, timeout);
std::vector<Event> result;
for (size_t i = 0; i < ndfs; ++i) {
auto handle_info = reinterpret_cast<HandleInfo*>(events[i].data.ptr);
// 有处理句柄
if (handle_info->handle != nullptr && handle_info->handle != (Handle*)&handle_info->handle) {
// 不要fd?
result.emplace_back(Event {
.handle_info = *handle_info
});
} else { // 没有处理句柄(或者说处理句柄已经调用过了),就作个标志(不用这么复杂把)
// mark event ready, but has no response callback
handle_info->handle = (Handle*)&handle_info->handle;
}
}
return result;
}
~EpollSelector() {
if (epfd_ > 0) { close(epfd_); }
}
bool is_stop() { return register_event_count_ == 1; }
/*
添加监听事件
*/
void register_event(const Event& event) {
// ev.data.ptr置为handle_info
epoll_event ev{ .events = event.flags, .data {.ptr = const_cast<HandleInfo*>(&event.handle_info) } };
if (epoll_ctl(epfd_, EPOLL_CTL_ADD, event.fd, &ev) == 0) {
++register_event_count_;
}
}
/*
移除监听事件
*/
void remove_event(const Event& event) {
epoll_event ev{ .events = event.flags };
if (epoll_ctl(epfd_, EPOLL_CTL_DEL, event.fd, &ev) == 0) {
--register_event_count_;
}
}
private:
int epfd_;
int register_event_count_ {1};
};
}
EventLoop 事件循环
主要功能:增加事件监听(wait_event) 、 定时器(call_later) 、事件调度(call_soon)
EventLoop::WaitEventAwaiter
顾名思义,当需要等待事件发生时,创建一个WaitEventAwaiter,然后co_await
在EventLoop的wait_event()用到:
selector是EventLoop所属的Selector
event需要外部传入
auto wait_event(const Event& event) { return WaitEventAwaiter{selector_, event}; }
struct WaitEventAwaiter {
bool await_ready() noexcept {
// 检查传入的Event是否已经发生,是否需要挂起
bool ready = (event_.handle_info.handle == (const Handle*)&event_.handle_info.handle); // 这个地方看EpollSelector::select
event_.handle_info.handle = nullptr;
return ready;
}
template<typename Promise>
constexpr void await_suspend(std::coroutine_handle<Promise> handle) noexcept {
handle.promise().set_state(Handle::SUSPEND); // 标志当前协程状态为suspend
event_.handle_info = {
.id = handle.promise().get_handle_id(), // 记录id???? // 调用的是Handle::get_handle_id(),这里就是Task::promise_type::get_handle_id()
.handle = &handle.promise() //< set callback 注意这里的回调函数设置为&handle.promise()
};
if (! registered_) { // 注册到Selecotr监听, 当事件发生时,会被唤醒
selector_.register_event(event_);
registered_ = true;
}
}
void await_resume() noexcept {
event_.handle_info = { }; //< reset callback // co_await返回时,清空event的回调函数,后续不会再调用
}
void destroy() noexcept { // 取消监听
if (registered_) {
selector_.remove_event(event_);
registered_ = false;
}
}
~WaitEventAwaiter() {
destroy();
}
Selector& selector_; // 对应的Selector
Event event_ {}; // 对应的Event
bool registered_ { false }; // 是否注册到Selector等待监听
};
EventLoop事件循环
对外暴露的有:
- call_later(delay, callback)调用call_at(),call_at()将callback加入schedule_(相当于一个定时器),通过Selector等待调度,时间到了,会将callback放到ready _
- call_soon(Handle& handle): 将handle加入到ready _, ready _会在每次epoll时都执行清空一次
- run_until_complete()相当于muduo中的EventLoop::loop()
- wait_event(const Event& event): 返回一个WaitEventAwaiter
- cancel_handle(Handle& handle):取消监听
namespace ASYNCIO_NS {
class EventLoop: private NonCopyable {
using MSDuration = std::chrono::milliseconds;
public:
EventLoop() { // 记录开始时间
auto now = std::chrono::steady_clock::now();
start_time_ = duration_cast<MSDuration>(now.time_since_epoch());
}
MSDuration time() { // 当前时间(相对于start_time_)
auto now = std::chrono::steady_clock::now();
return duration_cast<MSDuration>(now.time_since_epoch()) - start_time_;
}
// delay(单位:milliseconds)后调用callback
template<typename Rep, typename Period>
void call_later(std::chrono::duration<Rep, Period> delay, Handle& callback) {
call_at(time() + duration_cast<MSDuration>(delay), callback);
}
// 取消句柄调度(执行)
void cancel_handle(Handle& handle) {
handle.set_state(Handle::UNSCHEDULED);
cancelled_.insert(handle.get_handle_id());
}
// 调用句柄(直接加入队列等待执行)
void call_soon(Handle& handle) {
handle.set_state(Handle::SCHEDULED);
ready_.push({handle.get_handle_id(), &handle});
}
struct WaitEventAwaiter {
...
};
[[nodiscard]]
auto wait_event(const Event& event) {
return WaitEventAwaiter{selector_, event};
}
void run_until_complete() {
while (! is_stop()) { run_once(); } // 死循环,每次就调用run_once()
}
private:
bool is_stop() {
return schedule_.empty() && ready_.empty() && selector_.is_stop();
}
/*
清除被cancel的句柄,只清理堆顶部分,不然清理时间太长,也没有必要全清理
*/
void EventLoop::cleanup_delayed_call() {
// Remove delayed calls that were cancelled from head of queue.
while (! schedule_.empty()) {
auto&& [when, handle_info] = schedule_[0];
if (auto iter = cancelled_.find(handle_info.id); iter != cancelled_.end()) {
ranges::pop_heap(schedule_, std::ranges::greater{}, &TimerHandle::first);
schedule_.pop_back();
cancelled_.erase(iter);
} else {
break;
}
}
}
/*
std::chrono::duration 是一个表示时间间隔的模板类,它有两个模板参数:Rep 和 Period。
这两个参数分别表示时间间隔的数量(如秒、毫秒等)和时间单位(如秒、毫秒等)。
*/
/*
插入回调,在when时调用
*/
template<typename Rep, typename Period>
void call_at(std::chrono::duration<Rep, Period> when, Handle& callback) {
callback.set_state(Handle::SCHEDULED);
schedule_.emplace_back(duration_cast<MSDuration>(when),
HandleInfo{callback.get_handle_id(), &callback});
/*
这段代码使用了cpp标准库中的std::ranges::push_heap函数,该函数用于将指定范围内的元素调整为堆。
具体来说,std::ranges::push_heap函数接受三个参数:
schedule_:表示要调整为堆的范围。
std::ranges::greater{}:表示使用大顶堆的比较方式,即父节点的值大于或等于其子节点的值。
&TimerHandle::first:表示以TimerHandle类的first成员作为排序依据。
*/
std::ranges::push_heap(schedule_, std::ranges::greater{}, &TimerHandle::first);
}
/*
0:确定epoll_wait超时时间(0(ready_不为空)、堆顶的超时时间、-1(一直阻塞))
1:调用Selecotr.select(epoll)来获取已就绪Event,添加到ready_
2:将已超时句柄从schedule_插入到ready_
3:执行ready_句柄
4:清除被cancel的句柄
*/
void run_once() {
std::optional<MSDuration> timeout;
if (!ready_.empty()) { // 如果已有等待执行的句柄,则不执行select,先调用已经入队的
timeout.emplace(0);
} else if (! schedule_.empty()) {// 如果schedule_非空,则以第一个超时时间作为select超时间
auto&& [when, _] = schedule_[0];
timeout = std::max(when - time(), MSDuration(0));
}
// 将已就绪句柄从schedule_插入到ready_
// 调用select(epoll_wait)获取已就绪事件的句柄
auto event_lists = selector_.select(timeout.has_value() ? timeout->count() : -1);
for (auto&& event: event_lists) {
ready_.push(event.handle_info);
}
// 将已超时句柄从schedule_插入到ready_
auto end_time = time();
while (! schedule_.empty()) {
auto&& [when, handle_info] = schedule_[0];
if (when >= end_time) break;
ready_.push(handle_info);
ranges::pop_heap(schedule_, ranges::greater{}, &TimerHandle::first);
schedule_.pop_back();
}
// 执行ready_句柄
for (size_t ntodo = ready_.size(), i = 0; i < ntodo; ++i) {
auto [handle_id, handle] = ready_.front(); ready_.pop();
if (auto iter = cancelled_.find(handle_id); iter != cancelled_.end()) {
cancelled_.erase(iter);
} else {
handle->set_state(Handle::UNSCHEDULED);
handle->run();
}
}
// 清除被cancel的句柄
cleanup_delayed_call();
}
private:
MSDuration start_time_; // 记录eventloop开始的时间
Selector selector_; // EpollSelector
std::queue<HandleInfo> ready_; // 等待执行的句柄
using TimerHandle = std::pair<MSDuration, HandleInfo>;
std::vector<TimerHandle> schedule_; // min time heap(定时器)
std::unordered_set<HandleId> cancelled_; // 已取消的句柄
};
// 单例EventLoop
EventLoop& get_event_loop() {
static EventLoop loop;
return loop;
}