代码拉取完成,页面将自动刷新
同步操作将从 ivanallen/simple-libevent 强制同步,此操作会覆盖自 Fork 仓库以来所做的任何修改,且无法恢复!!!
确定后同步将在后台操作,完成时将刷新页面,请耐心等待。
/*
* Copyright 2000 Niels Provos <[email protected]>
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. All advertising materials mentioning features or use of this software
* must display the following acknowledgement:
* This product includes software developed by Niels Provos.
* 4. The name of the author may not be used to endorse or promote products
* derived from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
* IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
* NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
* THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#include <sys/types.h>
#include <sys/time.h>
//#include <sys/queue.h>
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <errno.h>
#include <string.h>
#ifdef USE_LOG
#include "log.h"
#else
#define LOG_DBG(x)
#define log_error(x) perror(x)
#endif
#include "queue.h"
#include "event.h"
#ifndef howmany
#define howmany(x, y) (((x)+((y)-1))/(y))
#endif
/* Prototypes */
void event_add_post(struct event *);
TAILQ_HEAD (timeout_list, event) timequeue;
TAILQ_HEAD (event_wlist, event) writequeue;
TAILQ_HEAD (event_rlist, event) readqueue;
TAILQ_HEAD (event_ilist, event) addqueue;
int event_inloop = 0;
int event_fds; /* Highest fd in fd set */
int event_fdsz;
fd_set *event_readset;
fd_set *event_writeset;
void
event_init(void)
{
TAILQ_INIT(&timequeue);
TAILQ_INIT(&writequeue);
TAILQ_INIT(&readqueue);
TAILQ_INIT(&addqueue);
}
/*
* Called with the highest fd that we know about. If it is 0, completely
* recalculate everything.
*/
// 这个函数,主要用来调整读写集合的大小,参数 max 表示最大的描述符
int
events_recalc(int max)
{
fd_set *readset, *writeset;
struct event *ev;
int fdsz;
event_fds = max;
// 找到最大的描述符
if (!event_fds) {
TAILQ_FOREACH(ev, &writequeue, ev_write_next)
if (ev->ev_fd > event_fds)
event_fds = ev->ev_fd;
TAILQ_FOREACH(ev, &readqueue, ev_read_next)
if (ev->ev_fd > event_fds)
event_fds = ev->ev_fd;
}
// NFDBITS = 32, sizeof(fd_mask) = 4
// howmany 表示这些描述符存到 fd_set 需要占用几个 4 字节
// fdsz 表示占用几个字节. fd_mask 实际上是一个 int 类型
fdsz = howmany(event_fds + 1, NFDBITS) * sizeof(fd_mask);
// 当前描述符容量不够了,才会调整大小
if (fdsz > event_fdsz) {
// 重新调整 event_readset 的大小
if ((readset = realloc(event_readset, fdsz)) == NULL) {
log_error("malloc");
return (-1);
}
if ((writeset = realloc(event_writeset, fdsz)) == NULL) {
log_error("malloc");
free(readset);
return (-1);
}
// 清空读写集合
memset(readset + event_fdsz, 0, fdsz - event_fdsz);
memset(writeset + event_fdsz, 0, fdsz - event_fdsz);
event_readset = readset;
event_writeset = writeset;
event_fdsz = fdsz;
}
return (0);
}
/*
* 1. 计算超时时间最小的那个超时时间(超时队列队头的那个事件)
* 2. select 监听读写事件,超时时间就是第 1 步计算出来的
* 3. 处理读写事件
* 4. 将 add 队列中未处理的描述符添加到读写集合
*/
int
event_dispatch(void)
{
struct timeval tv;
struct event *ev, *old;
int res, maxfd;
/* Calculate the initial events that we are waiting for */
// 初始化读写集合的大小
if (events_recalc(0) == -1)
return (-1);
while (1) {
// 清空描述符集合
memset(event_readset, 0, event_fdsz);
memset(event_writeset, 0, event_fdsz);
// 将读定队列中的事件添加到对应的读写集合中
TAILQ_FOREACH(ev, &writequeue, ev_write_next)
FD_SET(ev->ev_fd, event_writeset);
TAILQ_FOREACH(ev, &readqueue, ev_read_next)
FD_SET(ev->ev_fd, event_readset);
// 计算超时队列队头事件还有多久超时
// 如果超时队列为空,则 tv 设置成 5 秒
timeout_next(&tv);
printf("time remain: %lu s : %lu ms\n", tv.tv_sec, 1000*tv.tv_usec);
// 监听读写事件集合,超时时间为最小的那个事件的时间
if ((res = select(event_fds + 1, event_readset,
event_writeset, NULL, &tv)) == -1) {
if (errno != EINTR) {
log_error("select");
return (-1);
}
continue;
}
LOG_DBG((LOG_MISC, 80, __FUNCTION__": select reports %d",
res));
maxfd = 0;
// 事件循环开始
event_inloop = 1;
// 检查读事件
for (ev = TAILQ_FIRST(&readqueue); ev;) {
old = TAILQ_NEXT(ev, ev_read_next);
if (FD_ISSET(ev->ev_fd, event_readset)) {
// 将事件从所有队列移除
event_del(ev);
// 执行回调函数
(*ev->ev_callback)(ev->ev_fd, EV_READ,
ev->ev_arg);
} else if (ev->ev_fd > maxfd)
maxfd = ev->ev_fd;
ev = old;
}
// 检查写事件
for (ev = TAILQ_FIRST(&writequeue); ev;) {
old = TAILQ_NEXT(ev, ev_read_next);
if (FD_ISSET(ev->ev_fd, event_writeset)) {
event_del(ev);
(*ev->ev_callback)(ev->ev_fd, EV_WRITE,
ev->ev_arg);
} else if (ev->ev_fd > maxfd)
maxfd = ev->ev_fd;
ev = old;
}
// 事件循环结束
event_inloop = 0;
// 先将所有 add 队列中的事件,转移到读写队列中
for (ev = TAILQ_FIRST(&addqueue); ev;
ev = TAILQ_FIRST(&addqueue)) {
TAILQ_REMOVE(&addqueue, ev, ev_add_next);
ev->ev_flags &= ~EVLIST_ADD;
event_add_post(ev);
// 更新 maxfd
if (ev->ev_fd > maxfd)
maxfd = ev->ev_fd;
}
// 重新分配读写集合的大小
if (events_recalc(maxfd) == -1)
return (-1);
timeout_process();
}
return (0);
}
// 初始化事件对象
void
event_set(struct event *ev, int fd, short events,
void (*callback)(int, short, void *), void *arg)
{
ev->ev_callback = callback;
ev->ev_arg = arg;
ev->ev_fd = fd;
ev->ev_events = events;
ev->ev_flags = EVLIST_INIT;
}
/*
* Checks if a specific event is pending or scheduled.
*/
// 这个函数用来检查事件是否还是处理未决状态,即是否在 add 队列中。
// 如果是,则返回该事件的事件类型和超时时间。
int
event_pending(struct event *ev, short event, struct timeval *tv)
{
int flags = ev->ev_flags;
/*
* We might not have been able to add it to the actual queue yet,
* check if we will enqueue later.
*/
// 如果还在 add 队列中,就设置 flags
if (ev->ev_flags & EVLIST_ADD)
flags |= (ev->ev_events & (EV_READ|EV_WRITE));
// event 相当于掩码,你关心哪个事件,这一步是做一个规范化处理
event &= (EV_TIMEOUT|EV_READ|EV_WRITE);
/* See if there is a timeout that we should report */
if (tv != NULL && (flags & event & EV_TIMEOUT))
*tv = ev->ev_timeout;
// 返回未决事件的状态和绝对超时时间
return (flags & event);
}
void
event_add(struct event *ev, struct timeval *tv)
{
LOG_DBG((LOG_MISC, 55,
"event_add: event: %p, %s%s%scall %p",
ev,
ev->ev_events & EV_READ ? "EV_READ " : " ",
ev->ev_events & EV_WRITE ? "EV_WRITE " : " ",
tv ? "EV_TIMEOUT " : " ",
ev->ev_callback));
if (tv != NULL) {
struct timeval now;
struct event *tmp;
gettimeofday(&now, NULL);
// 设置绝对超时时间, tv 是相对超时时间
timeradd(&now, tv, &ev->ev_timeout);
LOG_DBG((LOG_MISC, 55,
"event_add: timeout in %d seconds, call %p",
tv->tv_sec, ev->ev_callback));
// 如果设置了 EVLIST_TIMEOUT,先将事件从超时队列移除,待会将其加入到
// 超时队列正确的位置
if (ev->ev_flags & EVLIST_TIMEOUT)
TAILQ_REMOVE(&timequeue, ev, ev_timeout_next);
/* Insert in right temporal order */
// 将 ev 插入到超时队列,超时时间由小到大。
for (tmp = TAILQ_FIRST(&timequeue); tmp;
tmp = TAILQ_NEXT(tmp, ev_timeout_next)) {
// 遍历超时队列,如果事件 ev 的超时时间 <= 队列中某个事件就 break
if (timercmp(&ev->ev_timeout, &tmp->ev_timeout, <=))
break;
}
// 将 ev 插入到 tmp 前面
if (tmp)
TAILQ_INSERT_BEFORE(tmp, ev, ev_timeout_next);
// 插入到超时队列尾端
else
TAILQ_INSERT_TAIL(&timequeue, ev, ev_timeout_next);
// 表示 ev 事件对象已经添加到了超时队列中
ev->ev_flags |= EVLIST_TIMEOUT;
}
// 事件循环已经开始, 则不能把事件加到读写队列,先加入到 add 队列等待处理
// 这种情况会在处理事件的事件回调函数中发生。
if (event_inloop) {
/* We are in the event loop right now, we have to
* postpone the change until later.
*/
// 如果事件已经被加到了 add 队列就直接返回
if (ev->ev_flags & EVLIST_ADD)
return;
// 将事件添加到 add 队列,同时置事件标志位为 EVLIST_ADD
TAILQ_INSERT_TAIL(&addqueue, ev, ev_add_next);
ev->ev_flags |= EVLIST_ADD;
} else
// 事件循环还没开始,根据事件类型,将事件添加到读队列或写队列
event_add_post(ev);
}
void
event_add_post(struct event *ev)
{
// 读事件,还没加到读队列的话,就添加到读队列
if ((ev->ev_events & EV_READ) && !(ev->ev_flags & EVLIST_READ)) {
TAILQ_INSERT_TAIL(&readqueue, ev, ev_read_next);
ev->ev_flags |= EVLIST_READ;
}
// 写事件,如果还没加到写队列的话,就添加到写队列
if ((ev->ev_events & EV_WRITE) && !(ev->ev_flags & EVLIST_WRITE)) {
TAILQ_INSERT_TAIL(&writequeue, ev, ev_write_next);
ev->ev_flags |= EVLIST_WRITE;
}
}
// 将事件从所有队列移除
void
event_del(struct event *ev)
{
LOG_DBG((LOG_MISC, 80, "event_del: %p, callback %p",
ev, ev->ev_callback));
// 从 add 队列移除
if (ev->ev_flags & EVLIST_ADD) {
TAILQ_REMOVE(&addqueue, ev, ev_add_next);
ev->ev_flags &= ~EVLIST_ADD;
}
if (ev->ev_flags & EVLIST_TIMEOUT) {
TAILQ_REMOVE(&timequeue, ev, ev_timeout_next);
ev->ev_flags &= ~EVLIST_TIMEOUT;
}
if (ev->ev_flags & EVLIST_READ) {
TAILQ_REMOVE(&readqueue, ev, ev_read_next);
ev->ev_flags &= ~EVLIST_READ;
}
if (ev->ev_flags & EVLIST_WRITE) {
TAILQ_REMOVE(&writequeue, ev, ev_write_next);
ev->ev_flags &= ~EVLIST_WRITE;
}
}
// 计算超时队列队头事件还有多久到期
int
timeout_next(struct timeval *tv)
{
struct timeval now;
struct event *ev;
// 超时队列为空,将 tv 设置为 5 秒
if ((ev = TAILQ_FIRST(&timequeue)) == NULL) {
timerclear(tv);
// TIMEOUT_DEFAULT = 5
tv->tv_sec = TIMEOUT_DEFAULT;
return (0);
}
// 获取当前时间
if (gettimeofday(&now, NULL) == -1)
return (-1);
// 如果当前超时队列队头元素超时时间已经到期,就清空 tv
if (timercmp(&ev->ev_timeout, &now, <=)) {
timerclear(tv);
return (0);
}
// 如果超时时间还没到,就计算还有多久到期
timersub(&ev->ev_timeout, &now, tv);
LOG_DBG((LOG_MISC, 60, "timeout_next: in %d seconds", tv->tv_sec));
return (0);
}
void
timeout_process(void)
{
struct timeval now;
struct event *ev;
gettimeofday(&now, NULL);
// 将所有到期的事件对象移除
while ((ev = TAILQ_FIRST(&timequeue)) != NULL) {
// 只要超时队列第一个事件没有超时,那后面的都没超时,退出循环
if (timercmp(&ev->ev_timeout, &now, >))
break;
TAILQ_REMOVE(&timequeue, ev, ev_timeout_next);
ev->ev_flags &= ~EVLIST_TIMEOUT;
LOG_DBG((LOG_MISC, 60, "timeout_process: call %p",
ev->ev_callback));
(*ev->ev_callback)(ev->ev_fd, EV_TIMEOUT, ev->ev_arg);
}
}
此处可能存在不合适展示的内容,页面不予展示。您可通过相关编辑功能自查并修改。
如您确认内容无涉及 不当用语 / 纯广告导流 / 暴力 / 低俗色情 / 侵权 / 盗版 / 虚假 / 无价值内容或违法国家有关法律法规的内容,可点击提交进行申诉,我们将尽快为您处理。