diff --git a/base/defines.h b/base/defines.h index 321990d3da92558ee556ce392700da604dbd30ab..128d941f2439a162cdef899aad62a4bbc4667dd3 100644 --- a/base/defines.h +++ b/base/defines.h @@ -44,4 +44,13 @@ swap(tmp); \ } +//! 条件预加载宏 +#ifndef likely +#define likely(x) __builtin_expect(!!(x), 1) +#endif + +#ifndef unlikely +#define unlikely(x) __builtin_expect(!!(x), 0) +#endif + #endif //TBOX_BASE_DEFINES_H_20171030 diff --git a/coroutine/Makefile b/coroutine/Makefile index 0340355184aea00a45a6bd91503acaa4f1196210..cd249292a1f2697b27cc7e856eec7460a55a5acf 100644 --- a/coroutine/Makefile +++ b/coroutine/Makefile @@ -24,7 +24,7 @@ TEST_CPP_SRC_FILES = \ broadcast_test.cpp \ condition_test.cpp \ -TEST_LDFLAGS := $(LDFLAGS) -ltbox_event-ne -ltbox_base -levent_core -lev +TEST_LDFLAGS := $(LDFLAGS) -ltbox_event -ltbox_base -levent_core -lev ENABLE_SHARED_LIB = no diff --git a/event/Makefile b/event/Makefile index 35e0a9be62e4a07b9c92aa3a150762b39e1ed01e..0eced0e928f39ce50ea357037af86ec2d007cce7 100644 --- a/event/Makefile +++ b/event/Makefile @@ -36,10 +36,21 @@ CXXFLAGS += -DENABLE_LIBEV=1 LIB_NAME_EXT := $(LIB_NAME_EXT)e endif +ifeq ($(ENABLE_EPOLL), yes) +CPP_SRC_FILES += \ + engins/epoll/loop.cpp \ + engins/epoll/fd_event.cpp \ + engins/epoll/signal_event.cpp \ + engins/epoll/timer_event.cpp +CXXFLAGS += -DENABLE_EPOLL=1 +LIB_NAME_EXT := +endif + TEST_CPP_SRC_FILES = \ common_loop_test.cpp \ fd_event_test.cpp \ timer_event_test.cpp \ + signal_event_test.cpp \ CXXFLAGS := -DLOG_MODULE_ID='"tbox_event"' $(CXXFLAGS) diff --git a/event/common_loop.cpp b/event/common_loop.cpp index afd5189edc66c96fa23b03b4a5f61dc8cc346928..99324b372e5397b85a8010fc4c860334132102d0 100644 --- a/event/common_loop.cpp +++ b/event/common_loop.cpp @@ -26,6 +26,9 @@ CommonLoop::CommonLoop() : CommonLoop::~CommonLoop() { assert(cb_level_ == 0); + + std::lock_guard g(lock_); + cleanupDeferredTasks(); } bool CommonLoop::isInLoopThread() @@ -192,7 +195,7 @@ void CommonLoop::onGotRunInLoopFunc(short) //! 清理 run_in_loop_func_queue_ 与 run_next_func_queue_ 中的任务 void CommonLoop::cleanupDeferredTasks() { - int remain_loop_count = 10; //! 防止出现 runNext() 递归导致无法退出循环的问题 + int remain_loop_count = 10; //! 限定次数,防止出现 runNext() 递归导致无法退出循环的问题 while ((!run_in_loop_func_queue_.empty() || !run_next_func_queue_.empty()) && remain_loop_count-- > 0) { std::deque tasks = std::move(run_next_func_queue_); diff --git a/event/common_loop_test.cpp b/event/common_loop_test.cpp index 1539ad55a0e0645b3f3301557a5314c59f23c768..f633e0d754a55f16ea6cb43ab91ad80c41b3ae08 100644 --- a/event/common_loop_test.cpp +++ b/event/common_loop_test.cpp @@ -21,7 +21,7 @@ TEST(CommonLoop, isRunning) cout << "engin: " << e << endl; Loop *sp_loop = event::Loop::New(e); TimerEvent *sp_timer = sp_loop->newTimerEvent(); - SetScopeExitAction([sp_loop, sp_timer]{ delete sp_loop; delete sp_timer; }); + SetScopeExitAction([sp_loop, sp_timer]{ delete sp_timer; delete sp_loop; }); sp_timer->initialize(chrono::milliseconds(10), Event::Mode::kOneshot); bool is_run = false; @@ -50,7 +50,7 @@ TEST(CommonLoop, isInLoopThread) cout << "engin: " << e << endl; Loop *sp_loop = event::Loop::New(e); TimerEvent *sp_timer = sp_loop->newTimerEvent(); - SetScopeExitAction([sp_loop, sp_timer]{ delete sp_loop; delete sp_timer; }); + SetScopeExitAction([sp_loop, sp_timer]{ delete sp_timer; delete sp_loop; }); sp_timer->initialize(chrono::milliseconds(10), Event::Mode::kOneshot); bool is_timer_run = false; @@ -91,9 +91,9 @@ TEST(CommonLoop, runNextInsideLoop) TimerEvent *sp_timer2 = sp_loop->newTimerEvent(); SetScopeExitAction( [sp_loop, sp_timer1, sp_timer2]{ - delete sp_loop; - delete sp_timer1; delete sp_timer2; + delete sp_timer1; + delete sp_loop; } ); @@ -131,7 +131,7 @@ TEST(CommonLoop, runNextBeforeLoop) cout << "engin: " << e << endl; Loop *sp_loop = event::Loop::New(e); TimerEvent *sp_timer = sp_loop->newTimerEvent(); - SetScopeExitAction([sp_loop, sp_timer]{ delete sp_loop; delete sp_timer; }); + SetScopeExitAction([sp_loop, sp_timer]{ delete sp_timer; delete sp_loop; }); bool is_run_next_run = false; sp_loop->runNext([&] { is_run_next_run = true; }); @@ -188,9 +188,9 @@ TEST(CommonLoop, runInLoopInsideLoop) TimerEvent *sp_timer2 = sp_loop->newTimerEvent(); SetScopeExitAction( [sp_loop, sp_timer1, sp_timer2]{ - delete sp_loop; - delete sp_timer1; delete sp_timer2; + delete sp_timer1; + delete sp_loop; } ); @@ -227,7 +227,7 @@ TEST(CommonLoop, runInLoopBeforeLoop) cout << "engin: " << e << endl; Loop *sp_loop = event::Loop::New(e); TimerEvent *sp_timer = sp_loop->newTimerEvent(); - SetScopeExitAction([sp_loop, sp_timer]{ delete sp_loop; delete sp_timer; }); + SetScopeExitAction([sp_loop, sp_timer]{ delete sp_timer; delete sp_loop; }); bool is_run = false; sp_loop->runInLoop([&] { is_run = true; }); @@ -256,7 +256,7 @@ TEST(CommonLoop, runInLoopCrossThread) cout << "engin: " << e << endl; Loop *sp_loop = event::Loop::New(e); TimerEvent *sp_timer = sp_loop->newTimerEvent(); - SetScopeExitAction([sp_loop, sp_timer]{ delete sp_loop; delete sp_timer; }); + SetScopeExitAction([sp_loop, sp_timer]{ delete sp_timer; delete sp_loop; }); bool is_thread_run = false; bool is_run = false; @@ -298,9 +298,9 @@ TEST(CommonLoop, runInsideLoop) TimerEvent *sp_timer2 = sp_loop->newTimerEvent(); SetScopeExitAction( [sp_loop, sp_timer1, sp_timer2]{ - delete sp_loop; - delete sp_timer1; delete sp_timer2; + delete sp_timer1; + delete sp_loop; } ); @@ -337,7 +337,7 @@ TEST(CommonLoop, runBeforeLoop) cout << "engin: " << e << endl; Loop *sp_loop = event::Loop::New(e); TimerEvent *sp_timer = sp_loop->newTimerEvent(); - SetScopeExitAction([sp_loop, sp_timer]{ delete sp_loop; delete sp_timer; }); + SetScopeExitAction([sp_loop, sp_timer]{ delete sp_timer; delete sp_loop; }); bool is_run = false; sp_loop->run([&] { is_run = true; }); @@ -366,7 +366,7 @@ TEST(CommonLoop, runCrossThread) cout << "engin: " << e << endl; Loop *sp_loop = event::Loop::New(e); TimerEvent *sp_timer = sp_loop->newTimerEvent(); - SetScopeExitAction([sp_loop, sp_timer]{ delete sp_loop; delete sp_timer; }); + SetScopeExitAction([sp_loop, sp_timer]{ delete sp_timer; delete sp_loop; }); bool is_thread_run = false; bool is_run = false; @@ -407,8 +407,8 @@ TEST(CommonLoop, cleanupDeferedTask) TimerEvent *sp_timer1 = sp_loop->newTimerEvent(); SetScopeExitAction( [&]{ - delete sp_loop; delete sp_timer1; + delete sp_loop; } ); @@ -463,8 +463,8 @@ TEST(CommonLoop, runOrder) TimerEvent *sp_timer1 = sp_loop->newTimerEvent(); SetScopeExitAction( [sp_loop, sp_timer1]{ - delete sp_loop; delete sp_timer1; + delete sp_loop; } ); diff --git a/event/config.mk b/event/config.mk index a7bd7e3be2a0963680cb1c969efcf3f21c7ebff8..48da8d554abd0d2f59b9d75030d188980c959f72 100644 --- a/event/config.mk +++ b/event/config.mk @@ -1,4 +1,5 @@ -ENABLE_LIBEVENT = yes -ENABLE_LIBEV = yes +#ENABLE_LIBEVENT = yes +#ENABLE_LIBEV = yes +ENABLE_EPOLL = yes ENABLE_STAT = yes diff --git a/event/engins/epoll/fd_event.cpp b/event/engins/epoll/fd_event.cpp new file mode 100644 index 0000000000000000000000000000000000000000..b38e58a32ac45a15acc509e8ac931c928866943f --- /dev/null +++ b/event/engins/epoll/fd_event.cpp @@ -0,0 +1,155 @@ +#include +#include +#include +#include + +#include "fd_event.h" +#include "loop.h" + +namespace tbox { +namespace event { + +//! 同一个fd共享的数据 +struct EpollFdSharedData { + int ref = 0; //! 引用计数 + struct epoll_event ev; + std::vector read_events; + std::vector write_events; +}; + +EpollFdEvent::EpollFdEvent(EpollLoop *wp_loop) : + wp_loop_(wp_loop) +{ } + +EpollFdEvent::~EpollFdEvent() +{ + assert(cb_level_ == 0); + + disable(); + + --d_->ref; + if (d_->ref == 0) { + wp_loop_->removeFdSharedData(fd_); + delete d_; + } +} + +bool EpollFdEvent::initialize(int fd, short events, Mode mode) +{ + if (isEnabled()) + return false; + + fd_ = fd; + events_ = events; + if (mode == FdEvent::Mode::kOneshot) + is_stop_after_trigger_ = true; + + d_ = wp_loop_->queryFdSharedData(fd_); + if (d_ == nullptr) { + d_ = new EpollFdSharedData; + assert(d_ != nullptr); + + memset(&d_->ev, 0, sizeof(d_->ev)); + d_->ev.data.ptr = static_cast(d_); + + wp_loop_->addFdSharedData(fd_, d_); + } + + ++d_->ref; + return true; +} + +bool EpollFdEvent::enable() +{ + if (d_ == nullptr) + return false; + + if (is_enabled_) + return true; + + if (events_ & kReadEvent) + d_->read_events.push_back(this); + + if (events_ & kWriteEvent) + d_->write_events.push_back(this); + + reloadEpoll(); + + is_enabled_ = true; + return true; +} + +bool EpollFdEvent::disable() +{ + if (d_ == nullptr || !is_enabled_) + return true; + + if (events_ & kReadEvent) { + auto iter = std::find(d_->read_events.begin(), d_->read_events.end(), this); + d_->read_events.erase(iter); + } + + if (events_ & kWriteEvent) { + auto iter = std::find(d_->write_events.begin(), d_->write_events.end(), this); + d_->write_events.erase(iter); + } + + reloadEpoll(); + + is_enabled_ = false; + return true; +} + +Loop* EpollFdEvent::getLoop() const +{ + return wp_loop_; +} + +//! 重新加载fd对应的epoll +void EpollFdEvent::reloadEpoll() +{ + epoll_ctl(wp_loop_->epollFd(), EPOLL_CTL_DEL, fd_, NULL); + + d_->ev.events = 0; + if (!d_->write_events.empty()) + d_->ev.events |= EPOLLOUT; + if (!d_->read_events.empty()) + d_->ev.events |= EPOLLIN; + + epoll_ctl(wp_loop_->epollFd(), EPOLL_CTL_ADD, fd_, &d_->ev); +} + +void EpollFdEvent::OnEventCallback(int fd, uint32_t events, void *obj) +{ + EpollFdSharedData *d = static_cast(obj); + + if (events & EPOLLIN) { + for (EpollFdEvent *event : d->read_events) + event->onEvent(kReadEvent); + } + + if (events & EPOLLOUT) { + for (EpollFdEvent *event : d->write_events) + event->onEvent(kWriteEvent); + } +} + +void EpollFdEvent::onEvent(short events) +{ + wp_loop_->beginEventProcess(); + + if (cb_) { + + ++cb_level_; + cb_(events); + --cb_level_; + + if (is_stop_after_trigger_) + disable(); + } + + wp_loop_->endEventProcess(); +} + +} +} diff --git a/event/engins/epoll/fd_event.h b/event/engins/epoll/fd_event.h new file mode 100644 index 0000000000000000000000000000000000000000..e45fc516c1c36e641b2d77cce94b1c3c6f0a9948 --- /dev/null +++ b/event/engins/epoll/fd_event.h @@ -0,0 +1,53 @@ +#ifndef TBOX_EVENT_EPOLL_FD_EVENT_H_20220110 +#define TBOX_EVENT_EPOLL_FD_EVENT_H_20220110 + +#include "../../fd_event.h" + +#include + +namespace tbox { +namespace event { + +class EpollLoop; +class EpollFdSharedData; + +class EpollFdEvent : public FdEvent { + public: + explicit EpollFdEvent(EpollLoop *wp_loop); + ~EpollFdEvent() override; + + public: + bool initialize(int fd, short events, Mode mode) override; + void setCallback(const CallbackFunc &cb) override { cb_ = cb; } + + bool isEnabled() const override{ return is_enabled_; } + bool enable() override; + bool disable() override; + + Loop* getLoop() const override; + + public: + static void OnEventCallback(int fd, uint32_t events, void *obj); + + protected: + void reloadEpoll(); + void onEvent(short events); + + private: + EpollLoop *wp_loop_; + bool is_stop_after_trigger_ = false; + + int fd_ = -1; + uint32_t events_ = 0; + bool is_enabled_ = false; + + CallbackFunc cb_; + EpollFdSharedData *d_ = nullptr; + + int cb_level_ = 0; +}; + +} +} + +#endif //TBOX_EVENT_EPOLL_FD_EVENT_H_20220110 diff --git a/event/engins/epoll/loop.cpp b/event/engins/epoll/loop.cpp new file mode 100644 index 0000000000000000000000000000000000000000..3bfcefc8b6a1ad151732e0ca1a2d3a138c9da575 --- /dev/null +++ b/event/engins/epoll/loop.cpp @@ -0,0 +1,228 @@ +#include +#include + +#include +#include + +#include + +#include "loop.h" +#include "timer_event.h" +#include "fd_event.h" +#include "signal_event.h" + +#include +#include + +namespace tbox { +namespace event { + +namespace { +uint64_t CurrentMilliseconds() +{ + return std::chrono::duration_cast \ + (std::chrono::high_resolution_clock::now().time_since_epoch()).count(); +} + +} + +EpollLoop::EpollLoop() : + epoll_fd_(epoll_create1(EPOLL_CLOEXEC)) +{ + assert(epoll_fd_ >= 0); +} + +EpollLoop::~EpollLoop() +{ + CHECK_CLOSE_RESET_FD(epoll_fd_); + CHECK_DELETE_RESET_OBJ(sp_exit_timer_); +} + +int64_t EpollLoop::getWaitTime() const +{ + /// Get the top of minimum heap + int64_t wait_time = -1; + if (!timer_min_heap_.empty()) { + wait_time = timer_min_heap_.front()->expired - CurrentMilliseconds(); + if (wait_time < 0) //! If expired is little than now, then we consider this timer invalid and trigger it immediately. + wait_time = 0; + } + + return wait_time; +} + +void EpollLoop::onTimeExpired() +{ + auto now = CurrentMilliseconds(); + + while (!timer_min_heap_.empty()) { + auto t = timer_min_heap_.front(); + assert(t != nullptr); + + if (now < t->expired) + break; + + auto tobe_run = t->cb; + + // swap first element and last element + std::pop_heap(timer_min_heap_.begin(), timer_min_heap_.end(), TimerCmp()); + if (unlikely(t->repeat == 1)) { + // remove the last element + timer_min_heap_.pop_back(); + timer_cabinet_.remove(t->token); + CHECK_DELETE_RESET_OBJ(t); + } else { + t->expired += t->interval; + // push the last element to heap again + std::push_heap(timer_min_heap_.begin(), timer_min_heap_.end(), TimerCmp()); + if (t->repeat != 0) + --t->repeat; + } + + //! Q: 为什么不在L68执行? + //! A: 因为要尽可能地将回调放到最后执行。否则不满足测试 TEST(TimerEvent, DisableSelfInCallback) + if (tobe_run) + tobe_run(); + } +} + +void EpollLoop::runLoop(Mode mode) +{ + if (epoll_fd_ < 0) + return; + + std::vector events; + /* + * Why not events.reserve()? + * The reserve() method only allocates memory, but leaves it uninitialized, + * it only affects capacity(), but size() will be unchanged. + * The standard only guarantees that std::vector::data returns a pointer and [data(), data() + size()] is a valid range, + * the capacity is not concerned. So we need use resize and ensure the [data(), data() + size()] is a valid range whitch used by epoll_wait. + */ + events.resize(max_loop_entries_); + + runThisBeforeLoop(); + + keep_running_ = (mode == Loop::Mode::kForever); + do { + int fds = epoll_wait(epoll_fd_, events.data(), events.size(), getWaitTime()); + + onTimeExpired(); + + if (fds <= 0) + continue; + + for (int i = 0; i < fds; ++i) { + epoll_event &ev = events.at(i); + EpollFdEvent::OnEventCallback(ev.data.fd, ev.events, ev.data.ptr); + } + + /// If the receiver array size is full, increase its size with 1.5 times. + if (fds >= max_loop_entries_) { + max_loop_entries_ = (max_loop_entries_ + max_loop_entries_ / 2); +#if 0 + std::vector temp_events; + temp_events.resize(max_loop_entries_); + events.swap(temp_events); +#else + events.resize(max_loop_entries_); +#endif + } + + } while (keep_running_); + + runThisAfterLoop(); +} + +void EpollLoop::exitLoop(const std::chrono::milliseconds &wait_time) +{ + if (wait_time.count() == 0) { + keep_running_ = false; + } else { + sp_exit_timer_ = newTimerEvent(); + sp_exit_timer_->initialize(wait_time, Event::Mode::kOneshot); + sp_exit_timer_->setCallback([this] { keep_running_ = false; }); + sp_exit_timer_->enable(); + } +} + +cabinet::Token EpollLoop::addTimer(uint64_t interval, uint64_t repeat, const TimerCallback &cb) +{ + assert(cb); + + auto now = CurrentMilliseconds(); + + Timer *t = new Timer; + assert(t != nullptr); + + t->token = this->timer_cabinet_.insert(t); + + t->expired = now + interval; + t->interval = interval; + t->cb = cb; + t->repeat = repeat; + + timer_min_heap_.push_back(t); + std::push_heap(timer_min_heap_.begin(), timer_min_heap_.end(), TimerCmp()); + + return t->token; +} + +void EpollLoop::deleteTimer(const cabinet::Token& token) +{ + auto timer = timer_cabinet_.remove(token); + if (timer == nullptr) + return; + +#if 0 + timer_min_heap_.erase(timer); + std::make_heap(timer_min_heap_.begin(), timer_min_heap_.end(), TimerCmp()); +#else + //! If we use the above method, it is likely to disrupt order, leading to a wide range of exchanges. + //! This method will be a little better. + timer->expired = 0; + std::make_heap(timer_min_heap_.begin(), timer_min_heap_.end(), TimerCmp()); + std::pop_heap(timer_min_heap_.begin(), timer_min_heap_.end(), TimerCmp()); + timer_min_heap_.pop_back(); +#endif + + run([timer] { delete timer; }); //! Delete later, avoid delete itself +} + +void EpollLoop::addFdSharedData(int fd, EpollFdSharedData *fd_event) +{ + fd_data_map_.insert(std::make_pair(fd, fd_event)); +} + +void EpollLoop::removeFdSharedData(int fd) +{ + fd_data_map_.erase(fd); +} + +EpollFdSharedData* EpollLoop::queryFdSharedData(int fd) const +{ + auto it = fd_data_map_.find(fd); + if (it != fd_data_map_.end()) + return it->second; + return nullptr; +} + + +FdEvent* EpollLoop::newFdEvent() +{ + return new EpollFdEvent(this); +} + +TimerEvent* EpollLoop::newTimerEvent() +{ + return new EpollTimerEvent(this); +} + +SignalEvent* EpollLoop::newSignalEvent() +{ + LogWarn("EpollSignalEvent is not stable in multithread"); + return new EpollSignalEvent(this); +} + +} +} diff --git a/event/engins/epoll/loop.h b/event/engins/epoll/loop.h new file mode 100644 index 0000000000000000000000000000000000000000..5b5d14693fb2720efa09ec3cad83362fa2d28f16 --- /dev/null +++ b/event/engins/epoll/loop.h @@ -0,0 +1,80 @@ +#ifndef TBOX_EVENT_EPOLL_LOOP_H_20220105 +#define TBOX_EVENT_EPOLL_LOOP_H_20220105 + +#include +#include +#include + +#include "tbox/base/cabinet.hpp" +#include "../../common_loop.h" + +#ifndef DEFAULT_MAX_LOOP_ENTRIES +#define DEFAULT_MAX_LOOP_ENTRIES (256) +#endif + +namespace tbox { +namespace event { + +struct EpollFdSharedData; + +class EpollLoop : public CommonLoop { + public: + explicit EpollLoop(); + virtual ~EpollLoop(); + + public: + virtual void runLoop(Mode mode); + virtual void exitLoop(const std::chrono::milliseconds &wait_time); + + virtual FdEvent* newFdEvent(); + virtual TimerEvent* newTimerEvent(); + virtual SignalEvent* newSignalEvent(); + + public: + inline int epollFd() const { return epoll_fd_; } + + using TimerCallback = std::function; + cabinet::Token addTimer(uint64_t interval, uint64_t repeat, const TimerCallback &cb); + void deleteTimer(const cabinet::Token &token); + + void addFdSharedData(int fd, EpollFdSharedData *fd_data); + void removeFdSharedData(int fd); + EpollFdSharedData *queryFdSharedData(int fd) const; + + private: + void onTimeExpired(); + int64_t getWaitTime() const; + + private: + struct Timer { + cabinet::Token token; + uint64_t interval = 0; + uint64_t expired = 0; + uint64_t repeat = 0; + + TimerCallback cb; + }; + + struct TimerCmp { + bool operator()(const Timer *x, const Timer *y) const { + return x->expired > y->expired; + } + }; + + private: + int max_loop_entries_{ DEFAULT_MAX_LOOP_ENTRIES }; + int epoll_fd_{ -1 }; + bool keep_running_{ true }; + + TimerEvent *sp_exit_timer_{ nullptr }; + + cabinet::Cabinet timer_cabinet_; + std::vector timer_min_heap_; + + std::unordered_map fd_data_map_; +}; + +} +} + +#endif //TBOX_EVENT_EPOLL_LOOP_H_20220105 diff --git a/event/engins/epoll/signal_event.cpp b/event/engins/epoll/signal_event.cpp new file mode 100644 index 0000000000000000000000000000000000000000..beb80fc5741dcf1ef3e5c976da47eb66381c856f --- /dev/null +++ b/event/engins/epoll/signal_event.cpp @@ -0,0 +1,131 @@ +#include +#include +#include +#include +#include + +#include "signal_event.h" + +#include +#include +#include "loop.h" + +namespace tbox { +namespace event { + +EpollSignalEvent::EpollSignalEvent(EpollLoop *wp_loop) : + wp_loop_(wp_loop), + signal_fd_event_(wp_loop) +{ + sigemptyset(&sig_mask_); + signal_fd_ = signalfd(-1, &sig_mask_, SFD_NONBLOCK | SFD_CLOEXEC); + assert(signal_fd_ >= 0); +} + +EpollSignalEvent::~EpollSignalEvent() +{ + assert(cb_level_ == 0); + disable(); + + CHECK_CLOSE_RESET_FD(signal_fd_); +} + +bool EpollSignalEvent::initialize(int signum, Mode mode) +{ + disable(); + + if (!signal_fd_event_.initialize(signal_fd_, FdEvent::kReadEvent, mode)) + return false; + + signal_fd_event_.setCallback(std::bind(&EpollSignalEvent::onEvent, this, std::placeholders::_1)); + + sigaddset(&sig_mask_, signum); + + if (mode == Mode::kOneshot) + is_stop_after_trigger_ = true; + + is_inited_ = true; + return true; +} + +void EpollSignalEvent::setCallback(const CallbackFunc &cb) +{ + cb_ = cb; +} + +bool EpollSignalEvent::isEnabled() const +{ + if (!is_inited_) + return false; + + return signal_fd_event_.isEnabled(); +} + +bool EpollSignalEvent::enable() +{ + if (!is_inited_) + return false; + + if (isEnabled()) + return true; + + if (!signal_fd_event_.enable()) + return false; + + signalfd(signal_fd_, &sig_mask_, 0); + sigprocmask(SIG_BLOCK, &sig_mask_, 0); + + return true; +} + +bool EpollSignalEvent::disable() +{ + if (!is_inited_) + return false; + + if (!isEnabled()) + return true; + + sigprocmask(SIG_UNBLOCK, &sig_mask_, 0); + signalfd(signal_fd_, &sig_mask_, 0); + + if (!signal_fd_event_.disable()) + return false; + + return true; +} + +Loop* EpollSignalEvent::getLoop() const +{ + return wp_loop_; +} + +void EpollSignalEvent::onEvent(short events) +{ + wp_loop_->beginEventProcess(); + + if (!(events & FdEvent::kReadEvent)) + return; + + /// We need read the signal_fd_ if got some signals + struct signalfd_siginfo info; + if (read(signal_fd_, &info, sizeof(info)) != sizeof(info)) + return; + + /// signal number = info.ssi_signo + /// pid = info.ssi_pid + /// uid = info.ssi_uid + + if (cb_) { + ++cb_level_; + cb_(); + --cb_level_; + + if (is_stop_after_trigger_) + disable(); + } + + wp_loop_->endEventProcess(); +} +} +} diff --git a/event/engins/epoll/signal_event.h b/event/engins/epoll/signal_event.h new file mode 100644 index 0000000000000000000000000000000000000000..61d8a1fa6adc850d289bb56d167a608d9a169fbc --- /dev/null +++ b/event/engins/epoll/signal_event.h @@ -0,0 +1,52 @@ +#ifndef TBOX_EVENT_EPOLL_SINGAL_EVENT_H_20220110 +#define TBOX_EVENT_EPOLL_SINGAL_EVENT_H_20220110 + +#include +#include "../../signal_event.h" +#include "fd_event.h" + +struct epoll_event; + +namespace tbox { +namespace event { + +class EpollLoop; +class EpollFdEvent; + +class EpollSignalEvent : public SignalEvent { + public: + explicit EpollSignalEvent(EpollLoop *wp_loop); + virtual ~EpollSignalEvent(); + + public: + virtual bool initialize(int signum, Mode mode); + virtual void setCallback(const CallbackFunc &cb); + + virtual bool isEnabled() const; + virtual bool enable(); + virtual bool disable(); + + virtual Loop* getLoop() const; + + protected: + void onEvent(short events); + + private: + EpollLoop *wp_loop_{ nullptr }; + + bool is_inited_{ false }; + bool is_stop_after_trigger_{ false }; + CallbackFunc cb_{ nullptr }; + + int signal_fd_ = -1; + sigset_t sig_mask_; + EpollFdEvent signal_fd_event_; + + int cb_level_ = 0; +}; + +} +} + +#endif //TBOX_EVENT_EPOLL_SINGAL_EVENT_H_20220110 + diff --git a/event/engins/epoll/timer_event.cpp b/event/engins/epoll/timer_event.cpp new file mode 100644 index 0000000000000000000000000000000000000000..908a4bb884bfa5ab9417e0523c06f57be67c0655 --- /dev/null +++ b/event/engins/epoll/timer_event.cpp @@ -0,0 +1,93 @@ +#include +#include +#include "loop.h" +#include "timer_event.h" + +namespace tbox { +namespace event { + +EpollTimerEvent::EpollTimerEvent(EpollLoop *wp_loop) + : wp_loop_(wp_loop) +{ } + +EpollTimerEvent::~EpollTimerEvent() +{ + assert(cb_level_ == 0); + disable(); +} + +bool EpollTimerEvent::initialize(const std::chrono::milliseconds &interval, Mode mode) +{ + disable(); + + interval_ = interval; + mode_ = mode; + + is_inited_ = true; + return true; +} + +void EpollTimerEvent::setCallback(const CallbackFunc &cb) +{ + cb_ = cb; +} + +bool EpollTimerEvent::isEnabled() const +{ + if (!is_inited_) + return false; + + return is_enabled_; +} + +bool EpollTimerEvent::enable() +{ + if (!is_inited_) + return false; + + if (isEnabled()) + return true; + + if (wp_loop_) + token_ = wp_loop_->addTimer(interval_.count(), mode_ == Mode::kOneshot ? 1 : 0, [this]{ onEvent(); }); + + is_enabled_ = true; + + return true; +} + +bool EpollTimerEvent::disable() +{ + if (!is_inited_) + return false; + + if (!isEnabled()) + return true; + + if (wp_loop_) + wp_loop_->deleteTimer(token_); + + is_enabled_ = false; + return true; +} + +Loop* EpollTimerEvent::getLoop() const +{ + return wp_loop_; +} + +void EpollTimerEvent::onEvent() +{ + wp_loop_->beginEventProcess(); + + if (cb_) { + ++cb_level_; + cb_(); + --cb_level_; + } + + wp_loop_->endEventProcess(); +} + +} +} diff --git a/event/engins/epoll/timer_event.h b/event/engins/epoll/timer_event.h new file mode 100644 index 0000000000000000000000000000000000000000..d84acdc5f96737d01b614a9cd7e311ed5aaba54b --- /dev/null +++ b/event/engins/epoll/timer_event.h @@ -0,0 +1,47 @@ +#ifndef TBOX_EVENT_EPOLL_TIMER_EVENT_H_20200110 +#define TBOX_EVENT_EPOLL_TIMER_EVENT_H_20200110 + +#include "tbox/base/cabinet.hpp" +#include "../../timer_event.h" + +namespace tbox { +namespace event { + +class EpollLoop; + +class EpollTimerEvent : public TimerEvent { + public: + explicit EpollTimerEvent(EpollLoop *wp_loop); + virtual ~EpollTimerEvent(); + + public: + virtual bool initialize(const std::chrono::milliseconds &interval, Mode mode); + virtual void setCallback(const CallbackFunc &cb); + + virtual bool isEnabled() const; + virtual bool enable(); + virtual bool disable(); + + virtual Loop* getLoop() const; + + protected: + void onEvent(); + + private: + EpollLoop *wp_loop_; + bool is_inited_{ false }; + bool is_enabled_{ false }; + + std::chrono::milliseconds interval_{ 0 }; + Mode mode_{ Mode::kOneshot }; + + CallbackFunc cb_{ nullptr }; + int cb_level_{ 0 }; + + cabinet::Token token_; +}; + +} +} + +#endif //TBOX_EVENT_EPOLL_TIMER_EVENT_H_20200110 diff --git a/event/example/basic/Makefile b/event/example/basic/Makefile index 8601f72c4023a57ef8035386948fbb4c3f6d9177..06ad74fb60b898c1a0b6bc9534e3d8b288e56782 100644 --- a/event/example/basic/Makefile +++ b/event/example/basic/Makefile @@ -5,7 +5,8 @@ TARGETS=io_example timer_example signal_example \ run_next_seq_demo delay_delete_demo CXXFLAGS += -ggdb -LDFLAGS += -ltbox_event-ne -ltbox_base -levent_core -lev -lpthread +#LDFLAGS += -ltbox_event -ltbox_base -levent_core -lev -lpthread +LDFLAGS += -ltbox_event -ltbox_base -lpthread CXXFLAGS += -fsanitize=address -fno-omit-frame-pointer LDFLAGS += -fsanitize=address -static-libasan diff --git a/event/example/basic/delay_delete_demo.cpp b/event/example/basic/delay_delete_demo.cpp index dd173d59dc5cbafc015d2bc7237a50d1207e1ba5..2879911b84ac4e48d82a5d33ec773ea678298ef5 100644 --- a/event/example/basic/delay_delete_demo.cpp +++ b/event/example/basic/delay_delete_demo.cpp @@ -7,7 +7,7 @@ using namespace tbox::event; void PrintUsage(const char *process_name) { - cout << "Usage:" << process_name << " libevent|libev" << endl; + cout << "Usage:" << process_name << " libevent|libev|epoll" << endl; } int main(int argc, char *argv[]) diff --git a/event/example/basic/io_example.cpp b/event/example/basic/io_example.cpp index 3b2ca5c69bc45ab61bb093627863f6b89cca77a8..0e3ba427199e05ff9beeb643b32c9d138fedf05a 100644 --- a/event/example/basic/io_example.cpp +++ b/event/example/basic/io_example.cpp @@ -1,5 +1,12 @@ +/** + * 本示例,使用异步FdEvent替代了cout, cin的功能 + */ + #include #include +#include +#include +#include #include #include @@ -7,17 +14,9 @@ using namespace std; using namespace tbox; using namespace tbox::event; -void FdCallback(int fd, short event) -{ - char input_buff[200]; - int rsize = read(fd, input_buff, sizeof(input_buff)); - input_buff[rsize - 1] = '\0'; - cout << "fd: " << fd << " INPUT is [" << input_buff << "]" << endl; -} - void PrintUsage(const char *process_name) { - cout << "Usage:" << process_name << " libevent|libev" << endl; + cout << "Usage:" << process_name << " libevent|libev|epoll" << endl; } int main(int argc, char *argv[]) @@ -33,15 +32,52 @@ int main(int argc, char *argv[]) return 0; } - FdEvent* sp_fd = sp_loop->newFdEvent(); - sp_fd->initialize(STDIN_FILENO, FdEvent::kReadEvent, Event::Mode::kPersist); - using std::placeholders::_1; - sp_fd->setCallback(std::bind(FdCallback, STDIN_FILENO, _1)); - sp_fd->enable(); + FdEvent* sp_fd_read = sp_loop->newFdEvent(); + FdEvent* sp_fd_write = sp_loop->newFdEvent(); + + sp_fd_read->initialize(STDIN_FILENO, FdEvent::kReadEvent, Event::Mode::kPersist); //! 可读事件一直有效 + sp_fd_write->initialize(STDOUT_FILENO, FdEvent::kWriteEvent, Event::Mode::kOneshot); //! 可写事件单次有效 + + sp_fd_read->enable(); //! 可读是常开的,可写不是 + + string send_cache; //! 发送缓存 + + //! 当终端有输入的时候 + sp_fd_read->setCallback( + [&] (short event) { + if (event & FdEvent::kReadEvent) { + char input_buff[200]; + int rsize = read(STDIN_FILENO, input_buff, sizeof(input_buff)); + input_buff[rsize - 1] = '\0'; + + stringstream ss; + ss << "INPUT " << rsize << " : " << input_buff << endl; + + send_cache += ss.str(); //! 放入到send_cache中 + sp_fd_write->enable(); //! 使能发送 + } + } + ); + + //! 当终端可以输出的时候 + sp_fd_write->setCallback( + [&] (short event) { + if (event & FdEvent::kWriteEvent) { + int wsize = write(STDOUT_FILENO, send_cache.data(), send_cache.size()); //! 尝试全量发送 + if (wsize > 0) { + send_cache.erase(0, wsize); //! 删除已发送的部分 + if (!send_cache.empty()) //! 如果没有发送完,要继续发 + sp_fd_write->enable(); + } + } + } + ); sp_loop->runLoop(Loop::Mode::kForever); - delete sp_fd; + delete sp_fd_read; + delete sp_fd_write; delete sp_loop; + return 0; } diff --git a/event/example/basic/run_in_loop_demo.cpp b/event/example/basic/run_in_loop_demo.cpp index 883f3f0d97f4cdda33433a8506912986fccf69a2..2ce2063caa6d7b2c6db23af13b1f9db485136d34 100644 --- a/event/example/basic/run_in_loop_demo.cpp +++ b/event/example/basic/run_in_loop_demo.cpp @@ -64,7 +64,7 @@ void ThreadFunc2(Loop* wp_loop) void PrintUsage(const char *process_name) { - cout << "Usage:" << process_name << " libevent|libev" << endl; + cout << "Usage:" << process_name << " libevent|libev|epoll" << endl; } int main(int argc, char *argv[]) diff --git a/event/example/basic/run_next_seq_demo.cpp b/event/example/basic/run_next_seq_demo.cpp index f2db4b0c7b1af895f4b649c093bf99d662f06747..761e79af93a91c332888a22ff2be56a5cead70b9 100644 --- a/event/example/basic/run_next_seq_demo.cpp +++ b/event/example/basic/run_next_seq_demo.cpp @@ -6,7 +6,7 @@ using namespace tbox::event; void PrintUsage(const char *process_name) { - cout << "Usage:" << process_name << " libevent|libev" << endl; + cout << "Usage:" << process_name << " libevent|libev|epoll" << endl; } int main(int argc, char *argv[]) diff --git a/event/example/basic/signal_example.cpp b/event/example/basic/signal_example.cpp index 44b6747a3e906846fc55e0b2d879e8ae5cc618ff..b59942f730a5b654b7273da125549f8fe9339c06 100644 --- a/event/example/basic/signal_example.cpp +++ b/event/example/basic/signal_example.cpp @@ -14,7 +14,7 @@ void SignalCallback() void PrintUsage(const char *process_name) { - cout << "Usage:" << process_name << " libevent|libev" << endl; + cout << "Usage:" << process_name << " libevent|libev|epoll" << endl; } int main(int argc, char *argv[]) diff --git a/event/example/basic/stdin_timer_signal_demo.cpp b/event/example/basic/stdin_timer_signal_demo.cpp index 69d02afd02fc1f6bc74209519b61f7aebf5e40c2..50413fd90ee2b0d8f7cd7d339e5dd81c9069da07 100644 --- a/event/example/basic/stdin_timer_signal_demo.cpp +++ b/event/example/basic/stdin_timer_signal_demo.cpp @@ -75,7 +75,7 @@ void IntSignalCallback(Loop* wp_loop) void PrintUsage(const char *process_name) { - cout << "Usage:" << process_name << " libevent|libev" << endl; + cout << "Usage:" << process_name << " libevent|libev|epoll" << endl; } int main(int argc, char *argv[]) diff --git a/event/example/basic/timer_example.cpp b/event/example/basic/timer_example.cpp index f14b18df10300407bcd7221161853dcbd1020dcf..6694304e94815f3ec9301605328a7ab7d4d23b6f 100644 --- a/event/example/basic/timer_example.cpp +++ b/event/example/basic/timer_example.cpp @@ -14,7 +14,7 @@ void TimerCallback() void PrintUsage(const char *process_name) { - cout << "Usage:" << process_name << " libevent|libev" << endl; + cout << "Usage:" << process_name << " libevent|libev|epoll" << endl; } int main(int argc, char *argv[]) diff --git a/event/example/calc_game/Makefile b/event/example/calc_game/Makefile index f80ec21c66357bbf6f2e17f4b21bf015a693fb71..9a4eecb3d66a72f06521989438d4e7f1d17bd15d 100644 --- a/event/example/calc_game/Makefile +++ b/event/example/calc_game/Makefile @@ -2,7 +2,7 @@ include ../build_env.mk TARGET := calc_game OBJECTS := main.o game.o game_lite.o -LDFLAGS += -L.. -ltbox_event-ne -ltbox_base -levent_core -lev +LDFLAGS += -L.. -ltbox_event -ltbox_base -levent_core -lev CXXFLAGS += -fsanitize=address -fno-omit-frame-pointer LDFLAGS += -fsanitize=address -static-libasan diff --git a/event/forward.h b/event/forward.h index 4aa55ab950b64a1318d68b50e595efc382d5180c..ea8d8724344a7479f50c2be82c029fb90bce65ff 100644 --- a/event/forward.h +++ b/event/forward.h @@ -1,13 +1,15 @@ #ifndef TBOX_EVENT_FORWARD_H_20170627 #define TBOX_EVENT_FORWARD_H_20170627 -namespace tbox::event { +namespace tbox{ +namespace event { class Loop; class FdEvent; class TimerEvent; class SignalEvent; +} } #endif //TBOX_EVENT_FORWARD_H_20170627 diff --git a/event/loop.cpp b/event/loop.cpp index c7d5f28635f17b7a8e04ddda045b00c7a0c267ab..a65ab640242637f597235b5bcaa7c842c0be5b9b 100644 --- a/event/loop.cpp +++ b/event/loop.cpp @@ -1,13 +1,14 @@ #include "loop.h" - #include -#ifdef ENABLE_LIBEVENT +#if defined(ENABLE_LIBEVENT) #include "engins/libevent/loop.h" -#endif - -#ifdef ENABLE_LIBEV +#elif defined(ENABLE_LIBEV) #include "engins/libev/loop.h" +#elif defined(ENABLE_EPOLL) +#include "engins/epoll/loop.h" +#else +#error("no engin specified!!!") #endif namespace tbox { @@ -15,6 +16,9 @@ namespace event { Loop* Loop::New() { +#ifdef ENABLE_EPOLL + return new EpollLoop; +#endif #ifdef ENABLE_LIBEVENT return new LibeventLoop; #endif @@ -26,6 +30,10 @@ Loop* Loop::New() Loop* Loop::New(const std::string &engine_type) { +#ifdef ENABLE_EPOLL + if (engine_type == "epoll") + return new EpollLoop; +#endif #ifdef ENABLE_LIBEVENT if (engine_type == "libevent") return new LibeventLoop; @@ -40,6 +48,9 @@ Loop* Loop::New(const std::string &engine_type) std::vector Loop::Engines() { std::vector types; +#ifdef ENABLE_EPOLL + types.push_back("epoll"); +#endif #ifdef ENABLE_LIBEVENT types.push_back("libevent"); #endif diff --git a/event/signal_event_test.cpp b/event/signal_event_test.cpp new file mode 100644 index 0000000000000000000000000000000000000000..a38db6c8d5fb3be2d53c2a4aee10c917de66a752 --- /dev/null +++ b/event/signal_event_test.cpp @@ -0,0 +1,114 @@ +#include +#include + +#include "loop.h" +#include "signal_event.h" +#include "timer_event.h" + +using namespace std; +using namespace tbox::event; + +const int kAcceptableError = 10; + +TEST(SignalEvent, Oneshot) +{ + auto engins = Loop::Engines(); + for (auto e : engins) { + cout << "engin: " << e << endl; + auto sp_loop = Loop::New(e); + auto signal_event = sp_loop->newSignalEvent(); + EXPECT_TRUE(signal_event->initialize(SIGINT, Event::Mode::kOneshot)); + EXPECT_TRUE(signal_event->enable()); + + int run_time = 0; + signal_event->setCallback([&]() { ++run_time; }); + + sp_loop->run([] + { + raise(SIGINT); + } + ); + sp_loop->exitLoop(std::chrono::milliseconds(100)); + sp_loop->runLoop(); + + EXPECT_EQ(run_time, 1); + + delete signal_event; + delete sp_loop; + } +} + +TEST(SignalEvent, PersistWithTimerEvent) +{ + auto engins = Loop::Engines(); + for (auto e : engins) { + cout << "engin: " << e << endl; + auto sp_loop = Loop::New(e); + auto signal_event = sp_loop->newSignalEvent(); + EXPECT_TRUE(signal_event->initialize(SIGINT, Event::Mode::kPersist)); + EXPECT_TRUE(signal_event->enable()); + + auto timer_event = sp_loop->newTimerEvent(); + EXPECT_TRUE(timer_event->initialize(chrono::milliseconds(10), Event::Mode::kPersist)); + EXPECT_TRUE(timer_event->enable()); + int count = 0; + timer_event->setCallback([&] + { + ++count; + if (count <= 5) { + raise(SIGINT); + } + } + ); + + int run_time = 0; + signal_event->setCallback([&]() { ++run_time; }); + + sp_loop->exitLoop(std::chrono::milliseconds(100)); + sp_loop->runLoop(); + + EXPECT_EQ(run_time, 5); + + delete timer_event; + delete signal_event; + delete sp_loop; + } +} + +TEST(SignalEvent, IntAndTermSignal) +{ + auto engins = Loop::Engines(); + for (auto e : engins) { + cout << "engin: " << e << endl; + auto sp_loop = Loop::New(e); + auto int_signal_event = sp_loop->newSignalEvent(); + EXPECT_TRUE(int_signal_event->initialize(SIGINT, Event::Mode::kOneshot)); + EXPECT_TRUE(int_signal_event->enable()); + + auto term_signal_event = sp_loop->newSignalEvent(); + EXPECT_TRUE(term_signal_event->initialize(SIGTERM, Event::Mode::kOneshot)); + EXPECT_TRUE(term_signal_event->enable()); + + int int_run_time = 0; + int_signal_event->setCallback([&]() { ++int_run_time; }); + int term_run_time = 0; + term_signal_event->setCallback([&]() { ++term_run_time; }); + + sp_loop->run([] + { + raise(SIGINT); + raise(SIGTERM); + } + ); + sp_loop->exitLoop(std::chrono::milliseconds(100)); + sp_loop->runLoop(); + + EXPECT_EQ(int_run_time, 1); + EXPECT_EQ(term_run_time, 1); + + delete int_signal_event; + delete term_signal_event; + delete sp_loop; + } +} + diff --git a/eventx/Makefile b/eventx/Makefile index c2ebbff573cced4b34b9160cd53cd4f4fee48069..8ea70be9520ea331e94e0e5ae242383717c0e70c 100644 --- a/eventx/Makefile +++ b/eventx/Makefile @@ -17,7 +17,7 @@ TEST_CPP_SRC_FILES = \ thread_pool_test.cpp \ timer_pool_test.cpp \ -TEST_LDFLAGS := $(LDFLAGS) -ltbox_event-ne -ltbox_base -levent_core -lev +TEST_LDFLAGS := $(LDFLAGS) -ltbox_event -ltbox_base -levent_core -lev ENABLE_SHARED_LIB = no include ../tools/lib_common.mk diff --git a/eventx/example/thread-pool/Makefile b/eventx/example/thread-pool/Makefile index a1336b0d9862e372eb531c44be92137ea4880b46..e106c2a987356e5cd4cd07fe9b10c304fccb7d90 100644 --- a/eventx/example/thread-pool/Makefile +++ b/eventx/example/thread-pool/Makefile @@ -3,7 +3,7 @@ include ../build_env.mk TARGET := demo OBJECTS := main.o CXXFLAGS += -ggdb -DLOG_MODULE_ID='"demo"' -LDFLAGS += -L.. -ltbox_eventx -ltbox_event-ne -ltbox_base -levent_core -lev -lpthread +LDFLAGS += -L.. -ltbox_eventx -ltbox_event -ltbox_base -levent_core -lev -lpthread CXXFLAGS += -fsanitize=address -fno-omit-frame-pointer LDFLAGS += -fsanitize=address -static-libasan diff --git a/main/Makefile b/main/Makefile index 0425bd058d2b7971749a63979bfbd5ef7d145dd0..c88f3a2cbaf8e381a7922009685e5442481a30f7 100644 --- a/main/Makefile +++ b/main/Makefile @@ -13,7 +13,7 @@ CPP_SRC_FILES = \ apps_imp.cpp \ context_imp.cpp \ main.cpp \ - error_handle.cpp \ + signal.cpp \ misc.cpp \ args.cpp \ @@ -25,7 +25,7 @@ TEST_LDFLAGS := $(LDFLAGS) \ -ltbox_terminal \ -ltbox_network \ -ltbox_eventx \ - -ltbox_event-ne \ + -ltbox_event \ -ltbox_util \ -ltbox_base \ -levent_core -lev diff --git a/main/example/01_one_app/Makefile b/main/example/01_one_app/Makefile index 3b89ec161bfab80b8b7c2a12e36460dc09821fa6..62f47441a3dfd0c6e927f25d1cc93f0735eef2b6 100644 --- a/main/example/01_one_app/Makefile +++ b/main/example/01_one_app/Makefile @@ -7,7 +7,7 @@ CXXFLAGS += -ggdb -DLOG_MODULE_ID='"demo"' LDFLAGS += -L.. \ -ltbox_main \ -ltbox_eventx \ - -ltbox_event-ne \ + -ltbox_event \ -ltbox_util \ -ltbox_base \ -levent_core \ diff --git a/main/example/02_more_than_one_apps/Makefile b/main/example/02_more_than_one_apps/Makefile index 4883a4d7522318c796a50bf139ddf8797869015b..f780d035b6893bcbff9c35890cb89956a4b9fef3 100644 --- a/main/example/02_more_than_one_apps/Makefile +++ b/main/example/02_more_than_one_apps/Makefile @@ -13,7 +13,7 @@ CXXFLAGS += -ggdb -DLOG_MODULE_ID='"demo"' LDFLAGS += -L.. \ -ltbox_main \ -ltbox_eventx \ - -ltbox_event-ne \ + -ltbox_event \ -ltbox_util \ -ltbox_base \ -levent_core \ diff --git a/main/example/03_nc_client_and_echo_server/Makefile b/main/example/03_nc_client_and_echo_server/Makefile index 9582de0f25282b24afbdf1e4fd45bf5e6253c30d..b18cd40da054508082900711fc5d3b46fd668411 100644 --- a/main/example/03_nc_client_and_echo_server/Makefile +++ b/main/example/03_nc_client_and_echo_server/Makefile @@ -12,7 +12,7 @@ CXXFLAGS += -ggdb -DLOG_MODULE_ID='"demo"' LDFLAGS += -L.. \ -ltbox_main \ -ltbox_eventx \ - -ltbox_event-ne \ + -ltbox_event \ -ltbox_util \ -ltbox_base \ -levent_core \ diff --git a/main/main.cpp b/main/main.cpp index 918943297f21377ce1e25e1ff77ff72fe68cb0d1..6fe8559c8d988ec94787e1a66011dcad0393b219 100644 --- a/main/main.cpp +++ b/main/main.cpp @@ -1,4 +1,3 @@ -#include #include #include @@ -27,6 +26,7 @@ extern void RegisterApps(Apps &apps); //! 由用户去实现 extern void Run(ContextImp &ctx, AppsImp &apps, int loop_exit_wait); std::function error_exit_func; //!< 出错异常退出前要做的事件 +std::function normal_stop_func; //!< 正常退出前要做的事件 int Main(int argc, char **argv) { @@ -111,28 +111,19 @@ int Main(int argc, char **argv) void Run(ContextImp &ctx, AppsImp &apps, int loop_exit_wait) { auto feeddog_timer = ctx.loop()->newTimerEvent(); - auto sig_int_event = ctx.loop()->newSignalEvent(); - auto sig_term_event = ctx.loop()->newSignalEvent(); //! 预定在离开时自动释放对象,确保无内存泄漏 - SetScopeExitAction( - [feeddog_timer, sig_int_event, sig_term_event] { - delete sig_term_event; - delete sig_int_event; - delete feeddog_timer; - } - ); - - sig_int_event->initialize(SIGINT, event::Event::Mode::kOneshot); - sig_term_event->initialize(SIGTERM, event::Event::Mode::kOneshot); - auto normal_stop_func = [&] { - LogInfo("Got stop signal"); - apps.stop(); - ctx.stop(); - ctx.loop()->exitLoop(std::chrono::seconds(loop_exit_wait)); - LogInfo("Loop will exit after %d sec", loop_exit_wait); + SetScopeExitAction([feeddog_timer] { delete feeddog_timer; }); + + normal_stop_func = [&] { + ctx.loop()->runInLoop([&] { + LogInfo("Got stop signal"); + apps.stop(); + ctx.stop(); + ctx.loop()->exitLoop(std::chrono::seconds(loop_exit_wait)); + LogInfo("Loop will exit after %d sec", loop_exit_wait); + } + ); }; - sig_int_event->setCallback(normal_stop_func); - sig_term_event->setCallback(normal_stop_func); //! 创建喂狗定时器 feeddog_timer->initialize(std::chrono::seconds(2), event::Event::Mode::kPersist); @@ -143,8 +134,6 @@ void Run(ContextImp &ctx, AppsImp &apps, int loop_exit_wait) util::ThreadWDog::Register("main", 3); feeddog_timer->enable(); - sig_int_event->enable(); - sig_term_event->enable(); LogInfo("Start!"); diff --git a/main/error_handle.cpp b/main/signal.cpp similarity index 83% rename from main/error_handle.cpp rename to main/signal.cpp index ba83d31bd98f5b6788d1d01d4708a1b617d2948d..5de2369310a6934c0c874e6f4a555f06f0b715b3 100644 --- a/main/error_handle.cpp +++ b/main/signal.cpp @@ -10,9 +10,18 @@ namespace tbox::main { extern std::function error_exit_func; //!< 出错异常退出前要做的事件 +extern std::function normal_stop_func; //!< 正常退出前要做的事件 namespace { +void OnStopSignal(int) +{ + if (normal_stop_func) + normal_stop_func(); + else + exit(0); +} + //! 打印调用栈 void PrintCallStack() { @@ -59,6 +68,8 @@ void RegisterSignals() signal(SIGABRT, OnErrorSignal); signal(SIGBUS, OnErrorSignal); signal(SIGPIPE, OnWarnSignal); + signal(SIGINT, OnStopSignal); + signal(SIGTERM, OnStopSignal); } } diff --git a/mqtt/Makefile b/mqtt/Makefile index d4790da0de9f403473b3ec295637a26f8a201cbf..8efb1ebba8302a6f950a2598683c5278342dbaeb 100644 --- a/mqtt/Makefile +++ b/mqtt/Makefile @@ -11,7 +11,7 @@ CXXFLAGS := -DLOG_MODULE_ID='"mqtt"' $(CXXFLAGS) TEST_CPP_SRC_FILES = \ -TEST_LDFLAGS := $(LDFLAGS) -ltbox_event-ne -ltbox_base -lmosquitto -levent_core -lev +TEST_LDFLAGS := $(LDFLAGS) -ltbox_event -ltbox_base -lmosquitto -levent_core -lev ENABLE_SHARED_LIB = no diff --git a/mqtt/example/basic/Makefile b/mqtt/example/basic/Makefile index 8d86ab3d90efc32274c73ebf681b660de0dcbf00..c3b8f606211e76825d2f1f9bc406fc7b4c91f3ba 100644 --- a/mqtt/example/basic/Makefile +++ b/mqtt/example/basic/Makefile @@ -2,7 +2,7 @@ include ../build_env.mk TARGET := sub pub conn CXXFLAGS += -ggdb -DLOG_MODULE_ID='"demo"' -LDFLAGS += -L.. -ltbox_mqtt -ltbox_event-ne -ltbox_base -levent_core -lev -lmosquitto -lpthread +LDFLAGS += -L.. -ltbox_mqtt -ltbox_event -ltbox_base -lmosquitto -lpthread CXXFLAGS += -fsanitize=address -fno-omit-frame-pointer LDFLAGS += -fsanitize=address -static-libasan diff --git a/network/Makefile b/network/Makefile index 949455eba5e5cab85515e99c1b20df04aaa95133..0c75478f2a3aa02001b0ba37496d5d62b6bbd4b4 100644 --- a/network/Makefile +++ b/network/Makefile @@ -47,7 +47,7 @@ TEST_CPP_SRC_FILES = \ sockaddr_test.cpp \ udp_socket_test.cpp \ -TEST_LDFLAGS := $(LDFLAGS) -ltbox_event-ne -ltbox_base -levent_core -lev +TEST_LDFLAGS := $(LDFLAGS) -ltbox_event -ltbox_base -levent_core -lev ENABLE_SHARED_LIB = no diff --git a/network/example/buffered_fd/Makefile b/network/example/buffered_fd/Makefile index d9de1c476badb12bd048dc2ef813cbbc79846919..57fd8decaf757c6d5da6269964bccb1d0a1085a9 100644 --- a/network/example/buffered_fd/Makefile +++ b/network/example/buffered_fd/Makefile @@ -3,7 +3,7 @@ include ../build_env.mk TARGET := io_echo OBJECTS := io_echo.o CXXFLAGS += -ggdb -DLOG_MODULE_ID='"demo"' -LDFLAGS += -L.. -ltbox_network -ltbox_eventx -ltbox_event-ne -ltbox_base -levent_core -lev -lpthread +LDFLAGS += -L.. -ltbox_network -ltbox_eventx -ltbox_event -ltbox_base -levent_core -lev -lpthread CXXFLAGS += -fsanitize=address -fno-omit-frame-pointer LDFLAGS += -fsanitize=address -static-libasan diff --git a/network/example/stdio_stream/Makefile b/network/example/stdio_stream/Makefile index bce0cc9bde08483bdc83e3bdc63eff12f5fe45d2..ff580babcb0c1f1a5ab65d1b8f5fe9fe3c6098e3 100644 --- a/network/example/stdio_stream/Makefile +++ b/network/example/stdio_stream/Makefile @@ -1,7 +1,7 @@ include ../build_env.mk CXXFLAGS += -ggdb -DLOG_MODULE_ID='"demo"' -LDFLAGS += -L.. -ltbox_network -ltbox_eventx -ltbox_event-ne -ltbox_base -levent_core -lev -lpthread +LDFLAGS += -L.. -ltbox_network -ltbox_eventx -ltbox_event -ltbox_base -levent_core -lev -lpthread CXXFLAGS += -fsanitize=address -fno-omit-frame-pointer LDFLAGS += -fsanitize=address -static-libasan diff --git a/network/example/tcp_acceptor/Makefile b/network/example/tcp_acceptor/Makefile index f1f9f59938c03708ed18fa64afa9be9f10f8f3dd..a2352c0695c6d476254b4e0f670f4d9056043a98 100644 --- a/network/example/tcp_acceptor/Makefile +++ b/network/example/tcp_acceptor/Makefile @@ -1,7 +1,7 @@ include ../build_env.mk CXXFLAGS += -ggdb -DLOG_MODULE_ID='"demo"' -LDFLAGS += -L.. -ltbox_network -ltbox_eventx -ltbox_event-ne -ltbox_base -levent_core -lev -lpthread +LDFLAGS += -L.. -ltbox_network -ltbox_eventx -ltbox_event -ltbox_base -levent_core -lev -lpthread TARGETS = tcp_echo tcp_nc_server CXXFLAGS += -fsanitize=address -fno-omit-frame-pointer diff --git a/network/example/tcp_client/Makefile b/network/example/tcp_client/Makefile index 14431fd732183ad90d0e1a2b421a7d205810d581..061edb8c959bb301dc51e25a361750c3b53d2378 100644 --- a/network/example/tcp_client/Makefile +++ b/network/example/tcp_client/Makefile @@ -1,7 +1,7 @@ include ../build_env.mk CXXFLAGS += -ggdb -DLOG_MODULE_ID='"demo"' -LDFLAGS += -L.. -ltbox_network -ltbox_eventx -ltbox_event-ne -ltbox_util -ltbox_base -levent_core -lev -lpthread +LDFLAGS += -L.. -ltbox_network -ltbox_eventx -ltbox_event -ltbox_util -ltbox_base -levent_core -lev -lpthread TARGETS = tcp_echo tcp_nc_client tcp_hex_client CXXFLAGS += -fsanitize=address -fno-omit-frame-pointer diff --git a/network/example/tcp_connector/Makefile b/network/example/tcp_connector/Makefile index b01408d61b3e1f3ffdba7fc12676c67f07c42dc1..dea16c8b834321a10149be9c80c4a4b99df27420 100644 --- a/network/example/tcp_connector/Makefile +++ b/network/example/tcp_connector/Makefile @@ -1,7 +1,7 @@ include ../build_env.mk CXXFLAGS += -ggdb -DLOG_MODULE_ID='"demo"' -LDFLAGS += -L.. -ltbox_network -ltbox_eventx -ltbox_event-ne -ltbox_base -levent_core -lev -lpthread +LDFLAGS += -L.. -ltbox_network -ltbox_eventx -ltbox_event -ltbox_base -levent_core -lev -lpthread TARGETS = tcp_echo tcp_nc_client CXXFLAGS += -fsanitize=address -fno-omit-frame-pointer diff --git a/network/example/tcp_server/Makefile b/network/example/tcp_server/Makefile index f1f9f59938c03708ed18fa64afa9be9f10f8f3dd..a2352c0695c6d476254b4e0f670f4d9056043a98 100644 --- a/network/example/tcp_server/Makefile +++ b/network/example/tcp_server/Makefile @@ -1,7 +1,7 @@ include ../build_env.mk CXXFLAGS += -ggdb -DLOG_MODULE_ID='"demo"' -LDFLAGS += -L.. -ltbox_network -ltbox_eventx -ltbox_event-ne -ltbox_base -levent_core -lev -lpthread +LDFLAGS += -L.. -ltbox_network -ltbox_eventx -ltbox_event -ltbox_base -levent_core -lev -lpthread TARGETS = tcp_echo tcp_nc_server CXXFLAGS += -fsanitize=address -fno-omit-frame-pointer diff --git a/network/example/uart/Makefile b/network/example/uart/Makefile index e1e6f2de3bb1ecd5b7a7a2cb12858acda665309b..495f59b6279082d8a14993c975d94ab7ff75101a 100644 --- a/network/example/uart/Makefile +++ b/network/example/uart/Makefile @@ -1,7 +1,7 @@ include ../build_env.mk CXXFLAGS += -ggdb -DLOG_MODULE_ID='"demo"' -LDFLAGS += -L.. -ltbox_network -ltbox_eventx -ltbox_event-ne -ltbox_base -levent_core -lev -lpthread +LDFLAGS += -L.. -ltbox_network -ltbox_eventx -ltbox_event -ltbox_base -levent_core -lev -lpthread CXXFLAGS += -fsanitize=address -fno-omit-frame-pointer LDFLAGS += -fsanitize=address -static-libasan diff --git a/network/example/udp_socket/Makefile b/network/example/udp_socket/Makefile index 7007eadce2faa679e8cbe57eccf352df3c361412..2962e6684c7ab75b70c5f6fe28ad3b58d621174f 100644 --- a/network/example/udp_socket/Makefile +++ b/network/example/udp_socket/Makefile @@ -1,7 +1,7 @@ include ../build_env.mk CXXFLAGS += -ggdb -DLOG_MODULE_ID='"demo"' -LDFLAGS += -L.. -ltbox_network -ltbox_eventx -ltbox_event-ne -ltbox_base -levent_core -lev -lpthread +LDFLAGS += -L.. -ltbox_network -ltbox_eventx -ltbox_event -ltbox_base -levent_core -lev -lpthread TARGETS = send_only recv_only request respond ping_pong CXXFLAGS += -fsanitize=address -fno-omit-frame-pointer diff --git a/sample/Makefile b/sample/Makefile index 082f998686fbe535f5d4315c0d509ad272d639dd..48862e57701e7bb24e69d0519995caf79797048d 100644 --- a/sample/Makefile +++ b/sample/Makefile @@ -16,11 +16,10 @@ LDFLAGS += \ -ltbox_network \ -ltbox_eventx \ -ltbox_eventx \ - -ltbox_event-ne \ + -ltbox_event \ -ltbox_util \ -ltbox_base \ - -levent_core \ - -lev -lpthread + -lpthread TEST_LDFLAGS += $(LDFLAGS) diff --git a/terminal/Makefile b/terminal/Makefile index 72ba7985118349ffbfbe5fce4a3e9870c9f828e3..7e39803714e3c95b966dfe06d2613c95112522aa 100644 --- a/terminal/Makefile +++ b/terminal/Makefile @@ -30,7 +30,7 @@ CXXFLAGS := -DLOG_MODULE_ID='"terminal"' $(CXXFLAGS) TEST_CPP_SRC_FILES = \ impl/key_event_scanner_test.cpp \ -TEST_LDFLAGS := $(LDFLAGS) -ltbox_network -ltbox_event-ne -ltbox_util -ltbox_base -levent_core -lev +TEST_LDFLAGS := $(LDFLAGS) -ltbox_network -ltbox_event -ltbox_util -ltbox_base -levent_core -lev ENABLE_SHARED_LIB = no include ../tools/lib_common.mk diff --git a/terminal/example/basic/Makefile b/terminal/example/basic/Makefile index 8fa6149d1a7d7c617e92eceb5d6f9a3297c6318f..3cdd0167370851ec8f878e18b33cab886feda613 100644 --- a/terminal/example/basic/Makefile +++ b/terminal/example/basic/Makefile @@ -3,7 +3,7 @@ include ../build_env.mk TARGET := demo OBJECTS := main.o CXXFLAGS += -ggdb -DLOG_MODULE_ID='"demo"' -LDFLAGS += -L.. -ltbox_terminal -ltbox_util -ltbox_network -ltbox_event-ne -ltbox_base -levent_core -lev -lpthread +LDFLAGS += -L.. -ltbox_terminal -ltbox_util -ltbox_network -ltbox_event -ltbox_base -levent_core -lev -lpthread CXXFLAGS += -fsanitize=address -fno-omit-frame-pointer LDFLAGS += -fsanitize=address -static-libasan