Squid Epoll网络模型

来源:互联网 发布:单点登录系统源码 编辑:程序博客网 时间:2024/05/17 01:05

Squid Epoll网络模型

Squid 历经2.x, 3.x,官网已经有正在开发中的4.0版本。Squid如今以20万行风骚代码让码农们找不着北了,本文就以Squid-4.0.0的源码为例吐槽一下。Squid编译时可以根据OS自动选择支持的网络模型,对网络的支持最终会编译到ModEpoll.cc、ModKqueue.cc、ModPoll.cc、ModSelect.cc。这些文件针对不同网络都有实现,最终导出几个公共函数SelectLoopInit、SetSelect、ResetSelect、DoSelect。

风骚的SetSelect

SetSelect(int fd, unsigned int type, PF * handler, void *client_data, time_t timeout)    // If read is an interest    if (type & COMM_SELECT_READ) {        if (handler) {            // Hack to keep the events flowing if there is data immediately ready            if (F->flags.read_pending)                ev.events |= EPOLLOUT;            ev.events |= EPOLLIN;        }        F->read_handler = handler;        F->read_data = client_data;        // Otherwise, use previously stored value    } else if (F->epoll_state & EPOLLIN) {        ev.events |= EPOLLIN;    }    // If write is an interest    if (type & COMM_SELECT_WRITE) {        if (handler)            ev.events |= EPOLLOUT;        F->write_handler = handler;        F->write_data = client_data;        // Otherwise, use previously stored value    } else if (F->epoll_state & EPOLLOUT) {        ev.events |= EPOLLOUT;    }    if (ev.events)        ev.events |= EPOLLHUP | EPOLLERR;    if (ev.events != F->epoll_state) {        if (F->epoll_state) // already monitoring something.            epoll_ctl_type = ev.events ? EPOLL_CTL_MOD : EPOLL_CTL_DEL;        else            epoll_ctl_type = EPOLL_CTL_ADD;        F->epoll_state = ev.events;
根据SetSelect设置的读写类型Read或者Write保留其它事件不变,从而达到每次只改变需要设置的事件回调。最终根据ev.events的值判断是否需要Mod或者Del。

吊的不行的DoSelect

        if (cevents->events & (EPOLLIN|EPOLLHUP|EPOLLERR) || F->flags.read_pending) {            if ((hdl = F->read_handler) != NULL) {                debugs(5, DEBUG_EPOLL ? 0 : 8, HERE << "Calling read handler on FD " << fd);                PROF_start(comm_write_handler);                F->flags.read_pending = 0;                F->read_handler = NULL;                hdl(fd, F->read_data);                PROF_stop(comm_write_handler);                ++ statCounter.select_fds;            } else {                debugs(5, DEBUG_EPOLL ? 0 : 8, HERE << "no read handler for FD " << fd);                // remove interest since no handler exist for this event.                SetSelect(fd, COMM_SELECT_READ, NULL, NULL, 0);            }        }        if (cevents->events & (EPOLLOUT|EPOLLHUP|EPOLLERR)) {            if ((hdl = F->write_handler) != NULL) {                debugs(5, DEBUG_EPOLL ? 0 : 8, HERE << "Calling write handler on FD " << fd);                PROF_start(comm_read_handler);                F->write_handler = NULL;                hdl(fd, F->write_data);                PROF_stop(comm_read_handler);                ++ statCounter.select_fds;            } else {                debugs(5, DEBUG_EPOLL ? 0 : 8, HERE << "no write handler for FD " << fd);                // remove interest since no handler exist for this event.                SetSelect(fd, COMM_SELECT_WRITE, NULL, NULL, 0);            }        }
每次执行完回调后handler = NULL,epoll在该套接字下一次事件中SetSelect(fd, COMM_SELECT_WRITE, NULL, NULL, 0)将该套接字删除,所以如果还想继续监听套接字事件必需在回调函数中手动执行SetSelect。

提取的Epoll模型
感受到Squid的如此强大,不由自主的提取了框架并做了一个小Demo。
顺便献上git地址https://github.com/strong46066999/epoll。

0 0
原创粉丝点击