| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104 |
- // EventLoop.cpp - 事件循环实现
- #include "pch.h"
- #include "EventLoop.h"
- #include "Logger.h"
- namespace commkit {
- EventLoop::EventLoop() {}
- EventLoop::~EventLoop() {
- Stop();
- }
- bool EventLoop::Start(HANDLE driver_handle, TOnData callback) {
- if (running_.load()) {
- return true;
- }
- if (driver_handle == INVALID_HANDLE_VALUE || !callback) {
- LOG_ERROR("EventLoop::Start invalid args");
- return false;
- }
- driver_handle_ = driver_handle;
- callback_ = callback;
- running_.store(true);
- try {
- thread_ = std::thread(&EventLoop::Run, this);
- } catch (const std::exception& e) {
- LOG_ERROR(std::string("EventLoop thread create failed: ") + e.what());
- running_.store(false);
- return false;
- }
- LOG_INFO("EventLoop started");
- return true;
- }
- void EventLoop::Stop() {
- if (!running_.exchange(false)) {
- return;
- }
- // 关闭驱动句柄会阻塞的 ReadEvents 立即返回错误
- // 此处仅设置标志,由 Run() 循环自行退出
- // 注意:不能在此处 CloseHandle(driver_handle_),因为 Run() 可能正在使用
- if (thread_.joinable()) {
- thread_.join();
- }
- LOG_INFO("EventLoop stopped");
- }
- void EventLoop::Run() {
- // 批量读取缓冲区:单次最多 COMMKIT_EVENT_BATCH 条事件
- COMMKIT_EVENT batch[COMMKIT_EVENT_BATCH];
- while (running_.load()) {
- DWORD returned = 0;
- // 阻塞式 IOCTL:驱动在无事件时会让 IRP pending
- // 当驱动有事件或被取消时返回
- BOOL ok = DeviceIoControl(
- driver_handle_,
- IOCTL_COMMKIT_READ_EVENTS,
- nullptr, 0,
- batch, sizeof(batch),
- &returned,
- nullptr);
- if (!running_.load()) {
- break;
- }
- if (!ok) {
- DWORD err = ::GetLastError();
- // 驱动关闭或句柄无效时退出循环
- if (err == ERROR_INVALID_HANDLE || err == ERROR_OPERATION_ABORTED) {
- LOG_WARNING("EventLoop Run: driver handle closed, exiting");
- break;
- }
- // 其他错误:短暂 sleep 后重试,避免空转
- LOG_ERROR("EventLoop Run: DeviceIoControl failed, error=" + std::to_string(err));
- std::this_thread::sleep_for(std::chrono::milliseconds(50));
- continue;
- }
- // 处理返回的事件
- DWORD count = returned / sizeof(COMMKIT_EVENT);
- for (DWORD i = 0; i < count; ++i) {
- const COMMKIT_EVENT& e = batch[i];
- if (callback_) {
- // 调用用户注册的回调
- // 数据指针:const_cast 转换以匹配 TOnData 签名
- // 注意:回调应只读 lpData,不应释放
- callback_(e.Sequence, e.TimeStamp, e.ComNumber,
- e.EventType, e.DataSize,
- const_cast<char*>(e.Data));
- }
- }
- }
- }
- } // namespace commkit
|