libevent可以检测系统信号,我们这里以检测SIGINT为例

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
#include "common.h"
#include "event_config.h"
#include "event_base.h"
#include "event_signal.h"

using namespace std;
using namespace echo;

int two_sum(int a,int b)
{
std::cout<<"a + b = "<<a+b<<std::endl;
return a+b;
}

int main() {
Callback<int>two(two_sum,10,20);
auto methods = event_get_supported_methods();
std::shared_ptr<Base>bases = std::make_shared<Base>(9999,listen_callback, two);
Signal s(*(bases.get()),SIGINT, two);
s.signal_add();
bases->start_base_dispatch();
return 0;
}

初始化signal类时传入基础事件上下文,要检测的信号类型,以及信号触发时的回掉函数。

以下是Signal的实现

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
#ifndef LIBEVENT_TEST_EVENT_SIGNAL_H
#define LIBEVENT_TEST_EVENT_SIGNAL_H

#include "common.h"

namespace echo
{
class Signal
{
public:
Signal(Base& base,int signal,Callback<int>& callback)
//基础事件,注册信号,信号触发时要回掉的函数
{
init_signal = evsignal_new(base.get_instance(), signal, signal_callback, (void*)&callback);
error_nullptr(VNAME(init_signal), init_signal);
}
static void signal_add(event* signal)
{
error_return_value(0,VNAME(event_add), event_add,signal, nullptr);
}
void signal_add()
{
error_return_value(0,VNAME(event_add), event_add,init_signal, nullptr);
}
~Signal()
{
free_source(event_free,init_signal);
}
event* get_signal()
{
error_nullptr(VNAME(init_signal),init_signal);
return init_signal;
}
private:
event* init_signal;
};
};


#endif //LIBEVENT_TEST_EVENT_SIGNAL_H

其中evsignal_new函数为信号初始化函数,回初始化好信号的事件上下文,监听的信号,信号触发的回掉函数,以及回掉函数的参数,这里我们依然和之前一样传入包装器callback,以便调用自己的回掉函数。其中的signal_callback是原本触发的信号处理函数,但是里面我们什么也不做,只是调用我们包装器,以便达到扩展的目的。

1
2
3
4
5
//触发事件的socket,触发的事件类型,传递的事件参数,此处默认传递封装CallBack
void signal_callback(int socket,short which,void* arg)
{
std::cout<<reinterpret_cast<Callback<int>*>(arg)->instance()<<std::endl;
}

再往下是一个我弄的一个新的返回值处理的包装器,用于处理返回值异常的情况

1
2
3
4
5
6
7
8
9
10
11
12
template<class V,class F,class ...Arg>
inline static void error_return_value(V value,const std::string& f_name,F&& fn,Arg&&... arg)
//value 为函数预期返回值,f_name为debug输出的函数名,需要使用宏VNAME(function_name),fn为传入函数,arg为传入函数的参数
{
if(std::invoke(std::forward<F>(fn), std::forward<Arg>(arg)...))
{
std::cerr<<"return value error : "<<__FILE__<<__LINE__<<":\t"<<f_name
<<"return value is not expect "<<value<<std::endl;
exit(0);
}
}

资源释放依旧采用的是之前写好的指针类资源回收包装器

1
2
3
4
5
6
template<class F,class S>
inline static void free_source(F&& fn,S&& arg)
{
if(arg) fn(arg);
arg = nullptr;
}

回到libevent的信号注册,一个分为以下几个部分:获取监听事件上下文,注册要监听的信号,将监听信号绑定要监听的事件上,被监听的事件开始运行,相关资源的回收。