事件循环插件主要通过封装libevent、evpp开源库实现事件循环处理,通过Yate实现事件处理插件化,通过Yate框架,可用将event的处理通过接口的方式,提供为不同的插件,方便使用事件方式进行代码开发。
事件循环处理
为了支撑事件处理接口定义,定义了几个基础类进行支撑,即Any(任意数据指针包装类),Duration(时间周期类),Timer(定时器类)
Any类
Any类的定义如下,
// A variant type that can hold any other type.
//
// Usage 1 :
//
// Buffer* buf(new Buffer());
// Any any(buf);
// Buffer* b = any_cast<Buffer*>(any);
// assert(buf == b);
// delete buf;
//
//
// Usage 2 :
//
// std::shared_ptr<Buffer> buf(new Buffer());
// Any any(buf);
// std::shared_ptr<Buffer> b = any_cast<std::shared_ptr<Buffer>>(any);
// assert(buf.get() == b.get());
//
//
// Usage 3 :
//
// std::shared_ptr<Buffer> buf(new Buffer());
// Any any(buf);
// std::shared_ptr<Buffer> b = any.Get<std::shared_ptr<Buffer>>();
// assert(buf.get() == b.get());
//
class Any {
public:
Any() : content_(nullptr) {}
~Any() {
delete content_;
}
template<typename ValueType>
explicit Any(const ValueType& value)
: content_(new Holder<ValueType>(value)) {}
Any(const Any& other)
: content_(other.content_ ? other.content_->clone() : nullptr) {}
public:
Any& swap(Any& rhs) {
std::swap(content_, rhs.content_);
return*this;
}
template<typename ValueType>
Any& operator=(const ValueType& rhs) {
Any(rhs).swap(*this);
return*this;
}
Any& operator=(const Any& rhs) {
Any(rhs).swap(*this);
return*this;
}
bool IsEmpty() const {
return !content_;
}
const std::type_info& GetType() const {
return content_ ? content_->GetType() : typeid(void);
}
template<typename ValueType>
ValueType operator()() const {
return Get<ValueType>();
}
template<typename ValueType>
ValueType Get() const {
if (GetType() == typeid(ValueType)) {
return static_cast<Any::Holder<ValueType>*>(content_)->held_;
}
else {
return ValueType();
}
}
protected:
class PlaceHolder {
public:
virtual ~PlaceHolder() {}
public:
virtual const std::type_info& GetType() const = 0;
virtual PlaceHolder* clone() const = 0;
};
template<typename ValueType>
class Holder : public PlaceHolder {
public:
Holder(const ValueType& value)
: held_(value) {}
virtual const std::type_info& GetType() const {
return typeid(ValueType);
}
virtual PlaceHolder* clone() const {
return new Holder(held_);
}
ValueType held_;
};
protected:
PlaceHolder* content_;
template<typename ValueType>
friend ValueType* any_cast(Any*);
};
template<typename ValueType>
ValueType* any_cast(Any* any) {
if (any && any->GetType() == typeid(ValueType)) {
return &(static_cast<Any::Holder<ValueType>*>(any->content_)->held_);
}
return nullptr;
}
template<typename ValueType>
const ValueType* any_cast(const Any* any) {
return any_cast<ValueType>(const_cast<Any*>(any));
}
template<typename ValueType>
ValueType any_cast(const Any& any) {
const ValueType* result = any_cast<ValueType>(&any);
//assert(result);
if (!result) {
return ValueType();
}
return *result;
}
Any类即可以包装裸指针,也可以包装shared_ptr指针,
裸指针用法:
Buffer* buf(new Buffer());
Any any(buf);
Buffer* b = any_cast<Buffer*>(any);
assert(buf == b);
delete buf;
shared_ptr指针用法
std::shared_ptr<Buffer> buf(new Buffer());
Any any(buf);
std::shared_ptr<Buffer> b1 = any_cast<std::shared_ptr<Buffer>>(any);
std::shared_ptr<Buffer> b2 = any.Get<std::shared_ptr<Buffer>>();
Duration类
Duration定义如下:
// A Duration represents the elapsed time between two instants
// as an int64 nanosecond count. The representation limits the
// largest representable duration to approximately 290 years.
class Duration {
public:
//static const int64_t kNanosecond; // = 1LL
//static const int64_t kMicrosecond;// = 1000
//static const int64_t kMillisecond;// = 1000 * kMicrosecond
//static const int64_t kSecond; // = 1000 * kMillisecond
//static const int64_t kMinute; // = 60 * kSecond
//static const int64_t kHour; // = 60 * kMinute
public:
Duration();
explicit Duration(const struct timeval& t);
explicit Duration(int64_t nanoseconds);
explicit Duration(int nanoseconds);
explicit Duration(double seconds);
// Nanoseconds returns the duration as an integer nanosecond count.
int64_t Nanoseconds() const;
// These methods return double because the dominant
// use case is for printing a floating point number like 1.5s, and
// a truncation to integer would make them not useful in those cases.
// Seconds returns the duration as a floating point number of seconds.
double Seconds() const;
double Milliseconds() const;
double Microseconds() const;
double Minutes() const;
double Hours() const;
struct timeval TimeVal() const;
void To(struct timeval* t) const;
bool IsZero() const;
bool operator< (const Duration& rhs) const;
bool operator<=(const Duration& rhs) const;
bool operator> (const Duration& rhs) const;
bool operator>=(const Duration& rhs) const;
bool operator==(const Duration& rhs) const;
Duration operator+=(const Duration& rhs);
Duration operator-=(const Duration& rhs);
Duration operator*=(int ns);
Duration operator/=(int ns);
private:
int64_t ns_; // nanoseconds
};
类的功能比较简单,看代码就能够确定其具体意义了。
Timer类
Timer类定义如下
class Timer;
typedef std::shared_ptr<Timer> TimerPtr;
class Timer : public std::enable_shared_from_this<Timer> {
public:
typedef std::function<void()> Functor;
virtual ~Timer() = default;
// It is thread safe.
// Start this timer.
virtual void Start() = 0;
// Cancel the timer and the cancel_callback_ will be invoked.
virtual void Cancel() = 0;
virtual void set_cancel_callback(const Functor& fn) = 0;
};
Timer类为定时器的接口类,定义了定时器启动、定时器取消,以及设置定时器取消的回调函数功能的接口功能,该接口会被EventLoop实现和调用。
事件循环处理
事件循环接口通过EventLoop类定义,类的代码如下:
class EventLoop {
public:
typedef std::function<void()> Functor;
public:
virtual ~EventLoop() = default;
virtual TimerPtr RunAfter(Duration delay, const Functor& f) = 0;
TimerPtr RunAfter(double delay_ms, const Functor& f) {
return RunAfter(Duration(delay_ms / 1000), f);
}
// RunEvery executes Functor f every period interval time.
virtual TimerPtr RunEvery(Duration interval, const Functor& f) = 0;
TimerPtr RunEvery(double interval_ms, const Functor& f) {
return RunEvery(Duration(interval_ms / 1000), f);
}
//======================================================================
virtual TimerPtr RunAfter(Duration delay, Functor&& f) = 0;
TimerPtr RunAfter(double delay_ms, Functor&& f) {
return RunAfter(Duration(delay_ms / 1000), f);
}
// RunEvery executes Functor f every period interval time.
virtual TimerPtr RunEvery(Duration interval, Functor&& f) = 0;
TimerPtr RunEvery(double interval_ms, Functor&& f) {
return RunEvery(Duration(interval_ms / 1000), f);
}
//======================================================================
virtual void RunInLoop(const Functor& handler) = 0;
virtual void QueueInLoop(const Functor& handler) = 0;
virtual void RunInLoop(Functor&& handler) = 0;
virtual void QueueInLoop(Functor&& handler) = 0;
virtual size_t GetPendingQueueSize() = 0;
virtual bool IsPendingQueueEmpty() = 0;
virtual bool IsInLoopThread() const = 0;
virtual const std::thread::id& tid() const = 0;
void set_context(const Any& c) {
context_[0] = c;
}
const Any& context() const {
return context_[0];
}
void set_context(int index, const Any& c) {
assert(index < kContextCount && index >= 0);
context_[index] = c;
}
const Any& context(int index) const {
assert(index < kContextCount && index >= 0);
return context_[index];
}
//======================================================================
// @brief Run the IO Event driving loop forever
// @note It must be called in the IO Event thread
virtual void Run() = 0;
// @brief Stop the event loop
virtual void Stop() = 0;
protected:
enum { kContextCount = 16, };
Any context_[kContextCount];
};
}
一次定时器事件通过接口RunAfter实现,接口参数包括定时间隔和响应函数,返回定时器指针,可以通过该指针取消还未触发的定时器事件。
周期定时器通过接口RunEvery实现,接口参数包括定时间隔和响应函数,返回定时器指针,可以通过该指针取消该的定时器事件。
在事件循环中处理事件通过接口RunInLoop实现,如果在事件循环中调用,则会直接处理,如果在事件循环外调用,则会将该事件插入到RunInLoop事件循环队列中,等待循环线程依次处理。
接口QueueInLoop将事件处理插入到EventLoop事件循环队列中,等待循环线程依次处理。
GetPendingQueueSize接口获取事件队列中还未处理事件的数量。
IsPendingQueueEmpty接口判断事件队列是否为空。
IsInLoopThread接口用于判断当前代码是否在EventLoop线程中进行处理。
QueueInLoop还提供了多个任意对象的Any包装,可以方便管理处理循环的上下文信息。
关于事件循环的详细信息,请参看Evpp的代码。
循环事件插件隔离
通过Yate插件系统,可以进行接口隔离,即在一个特定的插件中实现事件循环插件,而在其他的插件中通过接口调用事件循环接口,由于插件的隔离作用,可以有效避免接口实现与接口调用之间可能导致的库冲突等问题,接口实现也可以采用多种技术实现,而事件接口调用方通过插件系统的消息机制,选择合适的接口实现。
事件接口API
事件接口API通过类RxEventApi定义
class RxEventApi : public std::enable_shared_from_this<RxEventApi> {
public:
virtual ~RxEventApi() = default;
virtual const std::string& get_name() = 0;
virtual const std::string& get_version() = 0;
virtual EventLoop* get_main_loop_np() = 0;
virtual std::shared_ptr< EventLoop > get_main_loop() = 0;
virtual std::vector< EventLoopPtr > get_loop_pool() = 0;
virtual std::shared_ptr< EventLoop > get_task_loop(const std::string& task) = 0;
virtual std::vector< EventLoopPtr > get_task_thread_pool(const std::string& task) = 0;
};
定义了主事件处理循环获取接口,事件循环池获取接口,根据名称获取事件循环、事件循环池的功能。
事件循环接口实现
事件循环接口实现插件通过开源工程demoevpploop: evpp事件处理提供,该工程的实现依赖libevent、evpp、librxevent开源库。
libevent库地址:https://gitee.com/iseelgy/libevent
evpp库地址:https://gitee.com/iseelgy/evpp
librxevent:https://gitee.com/iseelgy/librxevent
librxevent提供了RxEventApi接口的实现,demoevpploop提供了RxEventApi的实例化和Yate消息处理,提供RxEventApi的查询、关闭和生成等功能。
在demoevpploop插件工程中,事件循环接口主要通过EvppShop进行管理,
EvppShop类定义如下
class EvppShop {
using RxEventApi = TE::RxEventApi;
using RxEventApiImpl = TE::RxEventApiImpl;
using Duration = TE::Duration;
using EventLoop = TE::EventLoop;
typedef std::function<void()> DoneCallback;
public:
EvppShop();
~EvppShop();
EventLoop* loop() {
if (_rx_event_api) {
return _rx_event_api->get_main_loop_np();
}
return 0;
}
bool start(uint32_t thread_num=0);
void stop(DoneCallback cb = DoneCallback());
void stopInLoop(DoneCallback on_stopped_cb);
void onStart();
// 接口
std::shared_ptr<RxEventApiImpl> _rx_event_api;
// 服务端
std::shared_ptr<EvppServer> _evpp_server;
bool onMessage(TE::Message& msg);
public:
void demo();
public:
};
EvppShop主要提供start、stop接口,用于启动和关闭事件循环。
start函数
代码如下
bool EvppShop::start(uint32_t thread_num )
{
if (_rx_event_api) {
Y_ERROR("already running");
return false;
}
auto api = std::make_shared<RxEventApiImpl>("Demo");
RxEventApiImpl* impl = (RxEventApiImpl * )api.get();
if (!impl->start(thread_num, std::bind(&EvppShop::onStart, this))) {
Y_ERROR("RxEventApiImpl start error");
return false;
}
_rx_event_api = api;
return true;
}
start的功能比较简单,
1. 首先判断接口是否已经实现,如果已经实现,返回失败
2. 生成接口的实现对象RxEventApiImpl,并进行启动(将启动主事件循环、thread_num个事件循环池),如果失败,返回错误; 启动成功后,将调用EvppShop::onStart进行后续处理。
3. 保存对象指针,返回结果,并在事件循环中进行后续处理。
后续处理的代码如下,
void EvppShop::onStart()
{
EventLoop* l = loop();
Y_INFO("EvppShop::onStart(), ******");
//loop()->IsRunning();
loop()->RunInLoop([]() {
Y_INFO("loop()->RunInLoop(), ++++++");
});
auto* cfg = get_configuration();
// 配置启动任务相关事件循环
for (unsigned int i = 0; i < cfg->sections(); i++) {
TE::NamedList* acct = cfg->getSection(i);
if (!acct) {
continue;
}
if (!acct->startsWith("loop_")) {
continue;
}
bool start = cfg->getBoolValue(*acct, "start", true);
if (!start) {
return;
}
std::string task = acct->substr(5).safe();
_rx_event_api->create_task_loop(task);
}
evpp::EventLoop* evloop = 0;
evpp::EventLoopThreadPool* evpool = 0;
if (typeid(l) == typeid(evloop)) {
evpp::RxEventApiImpl* impl = (evpp::RxEventApiImpl*)_rx_event_api.get();
evpool = impl->_tpool.get();
evloop = (evpp::EventLoop * )l;
}
else {
TE::RxEventApiImpl* impl = (TE::RxEventApiImpl*)_rx_event_api.get();
evloop = impl->get_evpp_main_loop().get();
evpool = impl->get_evpp_thread_pool().get();
}
_evpp_server = std::make_shared<EvppServer>(_rx_event_api);
// 通知消息, 已经启动
TE::Message* msg = new TE::Message(MSG_YATE, 0, true);
msg->setParam("Op", "EventLoop.start");
msg->setParam("app.name", get_app_name());
AnyRefObject<RxEventApi>* user_data = new AnyRefObject<RxEventApi>();
user_data->set(_rx_event_api);
msg->userData(user_data);
// 释放本地引用,由msg消息持有引用
user_data->deref();
TE::Engine::enqueue(msg);
}
在onStart函数中,会通过Yate消息,发送广播消息,系统中的其他插件,可以通过订阅消息,处理事件循环上线的情况。
stop函数
代码如下:
void EvppShop::stop(DoneCallback cb)
{
if (!_rx_event_api) {
return;
}
S_INFO("EvppShop::stop, ****");
TE::Message msg(MSG_YATE, nullptr, true);
msg.setParam("Op", "EventLoop.stop");
msg.setParam("app.name", get_app_name());
// 处理结束, 通过消息进行
TE::Engine::dispatch( msg );
stopInLoop( cb );
RxEventApiImpl* impl = (RxEventApiImpl*)_rx_event_api.get();
impl->stop();
_rx_event_api.reset();
}
首先通过TE::Engine::dispatch( msg )消息,通知其他插件,关闭对于接口RxEventApi的使用,并调用,
然后进行清理动作,释放相关资源;
最后关闭事件循环框架,置空_rx_event_api指针。
插件提供了几个Yate消息处理函数,用于管理_rx_event_api,代码如下:
bool MyPlugin::onYateMessage(Message& msg)
{
String Op = msg.getParam("Op");
if (Op == "RxEventApi") {
Lock lck(this); // 消息多线程保护
if (!_evpp_shop) {
return false;
}
if (!_evpp_shop->_rx_event_api) {
return false;
}
AnyRefObject<TE::RxEventApi>* user_data = new AnyRefObject<TE::RxEventApi>();
user_data->set(_evpp_shop->_rx_event_api);
msg.userData(user_data);
// 释放本地引用,由msg消息持有引用
user_data->deref();
msg.retValue() = "ok";
return true;
}
if (Op == "evpp::RxEventApi") {
Lock lck(this); // 消息多线程保护
if (!_evpp_shop) {
return false;
}
if (!_evpp_shop->_rx_event_api) {
return false;
}
if (!_evpp_shop->_rx_event_api->_attch_evpp_api) {
return false;
}
AnyRefObject<evpp::RxEventApi>* user_data = new AnyRefObject<evpp::RxEventApi>();
user_data->set(_evpp_shop->_rx_event_api->_attch_evpp_api);
msg.userData(user_data);
// 释放本地引用,由msg消息持有引用
user_data->deref();
msg.retValue() = "ok";
return true;
}
if (Op == "close.RxEventApi") {
Lock lck(this); // 消息多线程保护
if (!_evpp_shop) {
return false;
}
_evpp_shop->stop();
_evpp_shop.reset();
return true;
}
if (Op == "Evpp.loop") {
Lock lck(this); // 消息多线程保护
if (!_evpp_shop) {
return false;
}
return _evpp_shop->onMessage(msg);
}
return false;
}
事件循环接口调用
事件循环接口RxEventApi的使用Demo,在工程demo02中,源码地址为 https://gitee.com/iseelgy/demo02,
通过类YateLoopShop进行管理,类定义如下
class YateLoopShop {
public:
using Duration = TE::Duration;
using EventLoop = TE::EventLoop;
using RxEventApi = TE::RxEventApi;
public:
YateLoopShop(std::shared_ptr<RxEventApi> api);
~YateLoopShop();
EventLoop* loop() {
return _yateloop;
}
public:
void stop();
void start();
protected:
// 接口
std::shared_ptr<RxEventApi> _rx_event_api;
std::atomic_bool _stopped;
EventLoop* _yateloop = nullptr;
void stopInLoop();
// 判断资源是否已经清理完成
bool is_clean();
// 等待资源清理
void waiting_clean();
};
typedef std::shared_ptr<YateLoopShop> YateLoopShopPtr;
在插件中,定义了消息处理函数,用于处理与API相关的消息事件
if (Op == "EventLoop.start"){
String app = s_cfg.getValue("general", "app.name", __plugin.name());
if (app != msg.getParam("app.name")) {
return false;
}
std::shared_ptr<RxEventApi> api;
api = AnyRefObject_sp<TE::RxEventApi>(msg);
if (!api) {
return false;
}
_evpp_shop = std::make_shared<YateLoopShop>(api);
api->get_main_loop_np()->QueueInLoop(
std::bind(&YateLoopShop::start, _evpp_shop.get())
);
return false;
}
if (Op == "EventLoop.stop"){
String app = s_cfg.getValue("general", "app.name", __plugin.name());
if (app != msg.getParam("app.name")) {
return false;
}
if (_evpp_shop) {
_evpp_shop->stop();
_evpp_shop.reset();
}
return false;
}
用于处理消息处理循环上线通知、下线通知;在上线通知中,通过Yate消息体携带的接口指针,初始化YateLoopShop对象,后续即可通过RxEventApi,使用事件处理机制。
在下线通知中,释放资源,关闭事件循环处理流程。