全部博文(51)
分类: C/C++
2016-05-17 11:23:29
static void signal_cb(evutil_socket_t fd, short event, void *arg)
{
struct event *signal = arg;
printf("%s: got signal %d\n", __func__, EVENT_SIGNAL(signal));
if (called >= 2)
event_del(signal);
called++;
}
int main(int argc, char **argv)
{
struct event signal_int;
struct event_base* base;
/* Initalize the event library */
base = event_base_new(); //运行期间总的管理实体;
/* Initalize one event */
event_assign(&signal_int, base, SIGINT, EV_SIGNAL|EV_PERSIST, signal_cb,
&signal_int); //libevent的管理结构为struct event, 这里初始化一个signal对应的管理结构,主要内容为信号SIGINT,及回调signal_cb
event_add(&signal_int, NULL); //将signal管理结构加入到base;
event_base_dispatch(base); //进入监听转台,若期间接收到信号,则调用signal_cb;
event_base_free(base);
return (0);
}
|
int evsig_init(struct event_base *base)
{
/*
* Our signal handler is going to write to one end of the socket
* pair to wake up our event loop. The event loop then scans for
* signals that got delivered.
*/
if (evutil_socketpair(
AF_UNIX, SOCK_STREAM, 0, base->sig.ev_signal_pair) == -1) { //这里会创建一对socket,其用处为当发生信号时,发送通知消息;
#ifdef WIN32
/* Make this nonfatal on win32, where sometimes people
have localhost firewalled. */
event_sock_warn(-1, "%s: socketpair", __func__);
#else
event_sock_err(1, -1, "%s: socketpair", __func__);
#endif
return -1;
}
evutil_make_socket_closeonexec(base->sig.ev_signal_pair[0]);
evutil_make_socket_closeonexec(base->sig.ev_signal_pair[1]);
base->sig.sh_old = NULL;
base->sig.sh_old_max = 0;
evutil_make_socket_nonblocking(base->sig.ev_signal_pair[0]);
evutil_make_socket_nonblocking(base->sig.ev_signal_pair[1]);
event_assign(&base->sig.ev_signal, base, base->sig.ev_signal_pair[1],
EV_READ | EV_PERSIST, evsig_cb, base); //注册文件描述符base->sig.ev_signal_pair[1]的处理函数evsig_cb
base->sig.ev_signal.ev_flags |= EVLIST_INTERNAL;
event_priority_set(&base->sig.ev_signal, 0);
base->evsigsel = &evsigops;
return 0;
}
|
int evutil_ersatz_socketpair(int family, int type, int protocol,
evutil_socket_t fd[2])
{
/* This code is originally from Tor. Used with permission. */
/* This socketpair does not work when localhost is down. So
* it's really not the same thing at all. But it's close enough
* for now, and really, when localhost is down sometimes, we
* have other problems too.
*/
#ifdef WIN32
#define ERR(e) WSA##e
#else
#define ERR(e) e
#endif
evutil_socket_t listener = -1;
evutil_socket_t connector = -1;
evutil_socket_t acceptor = -1;
struct sockaddr_in listen_addr;
struct sockaddr_in connect_addr;
ev_socklen_t size;
int saved_errno = -1;
if (protocol
|| (family != AF_INET
#ifdef AF_UNIX
&& family != AF_UNIX
#endif
)) {
EVUTIL_SET_SOCKET_ERROR(ERR(EAFNOSUPPORT));
return -1;
}
if (!fd) {
EVUTIL_SET_SOCKET_ERROR(ERR(EINVAL));
return -1;
}
listener = socket(AF_INET, type, 0);
if (listener < 0)
return -1;
memset(&listen_addr, 0, sizeof(listen_addr));
listen_addr.sin_family = AF_INET;
listen_addr.sin_addr.s_addr = htonl(INADDR_LOOPBACK); //绑定一个回环地址
listen_addr.sin_port = 0; /* kernel chooses port. */
if (bind(listener, (struct sockaddr *) &listen_addr, sizeof (listen_addr))
== -1)
goto tidy_up_and_fail;
if (listen(listener, 1) == -1)
goto tidy_up_and_fail;
connector = socket(AF_INET, type, 0); //创建连接socket
if (connector < 0)
goto tidy_up_and_fail;
/* We want to find out the port number to connect to. */
size = sizeof(connect_addr);
if (getsockname(listener, (struct sockaddr *) &connect_addr, &size) == -1)
goto tidy_up_and_fail;
if (size != sizeof (connect_addr))
goto abort_tidy_up_and_fail;
if (connect(connector, (struct sockaddr *) &connect_addr, //连接到回环地址&端口
sizeof(connect_addr)) == -1)
goto tidy_up_and_fail;
size = sizeof(listen_addr);
acceptor = accept(listener, (struct sockaddr *) &listen_addr, &size); // 获取连接成功的socket,
if (acceptor < 0)
goto tidy_up_and_fail;
if (size != sizeof(listen_addr))
goto abort_tidy_up_and_fail;
evutil_closesocket(listener);
/* Now check we are talking to ourself by matching port and host on the
two sockets. */
if (getsockname(connector, (struct sockaddr *) &connect_addr, &size) == -1)
goto tidy_up_and_fail;
if (size != sizeof (connect_addr)
|| listen_addr.sin_family != connect_addr.sin_family
|| listen_addr.sin_addr.s_addr != connect_addr.sin_addr.s_addr
|| listen_addr.sin_port != connect_addr.sin_port)
goto abort_tidy_up_and_fail;
fd[0] = connector; //作为写socket
fd[1] = acceptor; //作为读socket;
return 0;
abort_tidy_up_and_fail:
saved_errno = ERR(ECONNABORTED);
tidy_up_and_fail:
if (saved_errno < 0)
saved_errno = EVUTIL_SOCKET_ERROR();
if (listener != -1)
evutil_closesocket(listener);
if (connector != -1)
evutil_closesocket(connector);
if (acceptor != -1)
evutil_closesocket(acceptor);
EVUTIL_SET_SOCKET_ERROR(saved_errno);
return -1;
#undef ERR
}
|
static int evsig_add(struct event_base *base, evutil_socket_t evsignal, short old, short events, void *p)
{
struct evsig_info *sig = &base->sig;
(void)p;
EVUTIL_ASSERT(evsignal >= 0 && evsignal < NSIG);
/* catch signals if they happen quickly */
EVSIGBASE_LOCK();
if (evsig_base != base && evsig_base_n_signals_added) {
event_warnx("Added a signal to event base %p with signals "
"already added to event_base %p. Only one can have "
"signals at a time with the %s backend. The base with "
"the most recently added signal or the most recent "
"event_base_loop() call gets preference; do "
"not rely on this behavior in future Libevent versions.",
base, evsig_base, base->evsel->name);
}
evsig_base = base;
evsig_base_n_signals_added = ++sig->ev_n_signals_added;
evsig_base_fd = base->sig.ev_signal_pair[0]; //用于写的fd;
EVSIGBASE_UNLOCK();
event_debug(("%s: %d: changing signal handler", __func__, (int)evsignal));
if (_evsig_set_handler(base, (int)evsignal, evsig_handler) == -1) { //设置信号处理函数,当信号发生时调用evsig_handler
goto err;
}
if (!sig->ev_signal_added) {
if (event_add(&sig->ev_signal, NULL))
goto err;
sig->ev_signal_added = 1;
}
return (0);
err:
EVSIGBASE_LOCK();
--evsig_base_n_signals_added;
--sig->ev_n_signals_added;
EVSIGBASE_UNLOCK();
return (-1);
}
|
static void __cdecl evsig_handler(int sig)
{
int save_errno = errno;
#ifdef WIN32
int socket_errno = EVUTIL_SOCKET_ERROR();
#endif
ev_uint8_t msg;
if (evsig_base == NULL) {
event_warnx(
"%s: received signal %d, but have no base configured",
__func__, sig);
return;
}
#ifndef _EVENT_HAVE_SIGACTION
signal(sig, evsig_handler);
#endif
/* Wake up our notification mechanism */
msg = sig;
send(evsig_base_fd, (char*)&msg, 1, 0); //向evsig_base_fd写入了信号值,这样就会触发fd[1]的读动作,回调evsig_cb,将该信号对应的struct event实例添加到base->activequeues队列;文件描述法由select,poll,epoll机制监控;
errno = save_errno;
#ifdef WIN32
EVUTIL_SET_SOCKET_ERROR(socket_errno);
#endif
}
|