libhv之hloop_process_ios源码分析

上一篇文章对hloop源码大概逻辑和思想进行了一个简单的分析,其中主要涉及三类(timer>io>idles)事件处理。下面将对hloop_process_ios事件做一下简单的分析。

int hloop_process_ios(hloop_t* loop, int timeout) {
    // That is to call IO multiplexing function such as select, poll, epoll, etc.
    //iowatcher_poll_events主要针对不同模型下的IO事件处理,代码将根据环境选择其一
    int nevents = iowatcher_poll_events(loop, timeout);
    if (nevents < 0) {
        hlogd("poll_events error=%d", -nevents);
    }
    return nevents < 0 ? 0 : nevents;
}

libhv之hloop_process_ios源码分析_第1张图片
下面将以epoll模型为例,对IO进行一个简单的分析。

iowatcher_poll_events总结

  1. epoll_wait检测io事件,如果存在则加入pendding队列,如果不存在则直接返回
int iowatcher_poll_events(hloop_t* loop, int timeout) {
    epoll_ctx_t* epoll_ctx = (epoll_ctx_t*)loop->iowatcher;
    if (epoll_ctx == NULL)  return 0;
    if (epoll_ctx->events.size == 0) return 0;
    //等待io事件,如果存在事件则加入pendding队列,单线程模型
    int nepoll = epoll_wait(epoll_ctx->epfd, epoll_ctx->events.ptr, epoll_ctx->events.size, timeout);
    if (nepoll < 0) {
        if (errno == EINTR) {
            return 0;
        }
        perror("epoll");
        return nepoll;
    }
    if (nepoll == 0) return 0;
    int nevents = 0;
    for (int i = 0; i < epoll_ctx->events.size; ++i) {
        struct epoll_event* ee = epoll_ctx->events.ptr + i;
        int fd = ee->data.fd;
        uint32_t revents = ee->events;
        if (revents) {
            ++nevents;
            hio_t* io = loop->ios.ptr[fd];
            if (io) {
                if (revents & (EPOLLIN | EPOLLHUP | EPOLLERR)) {
                    io->revents |= HV_READ;
                }
                if (revents & (EPOLLOUT | EPOLLHUP | EPOLLERR)) {
                    io->revents |= HV_WRITE;
                }
                //加入pendding队列
                EVENT_PENDING(io);
            }
        }
        if (nevents == nepoll) break;
    }
    return nevents;
}

此时看看epoll.c源码接口

int iowatcher_init(hloop_t* loop);
int iowatcher_cleanup(hloop_t* loop);
int iowatcher_add_event(hloop_t* loop, int fd, int events);
int iowatcher_del_event(hloop_t* loop, int fd, int events);
int iowatcher_poll_events(hloop_t* loop, int timeout);

发现模型接口很简单也很统一:初始化模型,加入事件,检测事件,删除事件,清理模型

1. io模型何时与loop绑定的呢?loop初始化即绑定或者在add_event的时候检测绑定
void hloop_init(hloop_t* loop) {
	.....
	 // 初始化iowatcher
    iowatcher_init(loop);
	......
}

int iowatcher_add_event(hloop_t* loop, int fd, int events) {
    if (loop->iowatcher == NULL) {
        iowatcher_init(loop);
    }
    ......
}
2. fd何时与IO模型绑定的呢?io异步读写的时候进行io模型绑定
//read的时候添加io,
int hio_read (hio_t* io) {
    if (io->closed) {
        hloge("hio_read called but fd[%d] already closed!", io->fd);
        return -1;
    }
    hio_add(io, hio_handle_events, HV_READ);
    if (io->readbuf.tail > io->readbuf.head &&
        io->unpack_setting == NULL &&
        io->read_flags == 0) {
        hio_read_remain(io);
    }
    return 0;
}

//将IO和模型绑定iowatcher_add_event
int hio_add(hio_t* io, hio_cb cb, int events) {
    printd("hio_add fd=%d io->events=%d events=%d\n", io->fd, io->events, events);
#ifdef OS_WIN
    // Windows iowatcher not work on stdio
    if (io->fd < 3) return -1;
#endif
    hloop_t* loop = io->loop;
    if (!io->active) {
        EVENT_ADD(loop, io, cb);
        loop->nios++;
    }

    if (!io->ready) {
        hio_ready(io);
    }

    if (cb) {
        io->cb = (hevent_cb)cb;
    }

    if (!(io->events & events)) {
        iowatcher_add_event(loop, io->fd, events);
        io->events |= events;
    }
    return 0;
}

至此io和loop关联完成。

总结

  1. 代码根据编译选项()选则某一种IO模型
  2. loop在初始化的时候将loop和IO模型绑定,默认创建custom event,即socket
  3. 在fd进行读(hio_read )写(hio_write)的时候将fd添加到IO模型
  4. hloop_process_ios 在IO模型检测(epoll_wait)已经准备就绪的IO事件,并且加入pendding队列。

为了更一步了解io细节,下一步将对hio源码进行讲解分析。

你可能感兴趣的:(libhv,libhv,c++,hloop)