BIND9采用的是事件驱动的机制来工作,而事件的源头则是IO,IO在linux使用的EPOLL的边缘触发模式。

  本篇说的是epoll,BIND9如果创建了watcher线程(宏USE_WATCHER_THREAD控制),这里就讨论有线程的情况,实际上即使不创建

线程干的也都是一样的活。在lib/isc/socket.c中setup_watcher函数:(所有的代码都是截取的epoll下的片段,因为还有kqueue,devpoll,select等的实现代码,太多了)

#elif defined(USE_EPOLL)manager->nevents = ISC_SOCKET_MAXEVENTS;manager->events = isc_mem_get(mctx, sizeof(struct epoll_event) *manager->nevents);if (manager->events == NULL)return (ISC_R_NOMEMORY);manager->epoll_fd = epoll_create(manager->nevents);if (manager->epoll_fd == -1) {result = isc__errno2result(errno);isc__strerror(errno, strbuf, sizeof(strbuf));UNEXPECTED_ERROR(__FILE__, __LINE__,"epoll_create %s: %s",isc_msgcat_get(isc_msgcat, ISC_MSGSET_GENERAL,ISC_MSG_FAILED, "failed"),strbuf);isc_mem_put(mctx, manager->events,sizeof(struct epoll_event) * manager->nevents);return (result);}
#ifdef USE_WATCHER_THREADresult = watch_fd(manager, manager->pipe_fds[0], SELECT_POKE_READ);if (result != ISC_R_SUCCESS) {close(manager->epoll_fd);isc_mem_put(mctx, manager->events,sizeof(struct epoll_event) * manager->nevents);return (result);}
#endif    /* USE_WATCHER_THREAD */

View Code

先是创建了要监视的最大socket fd数目(manager->nevents)对应的epoll_event结构体数组,然后调用epoll_create函数创建一个epoll fd,参数则是指定监视的socket fd

最大数目。我的内核版本是3.13,man一下epoll_create发现它是这样说的:epoll_create()  creates  an  epoll(7) instance.  Since Linux 2.6.8, thesize argument is ignored, but must be  greater  than  zero。这个函数在2.6.8内核以后就忽略参数size了,但是传递的参数值一定要大于0。后来找了一下资料,网上的高手的博客说的就很清楚了http://www.cnblogs.com/apprentice89/p/3234677.html。继续往下说,后面的watch_fd实在创建线程的情况下才有,就是将pipe_fds[0]这个管道描述符,也就是一个可读的流,而上述的socket fd都是可以归为流。watch_fd的实现代码:

#elif defined(USE_EPOLL)struct epoll_event event;if (msg == SELECT_POKE_READ)event.events = EPOLLIN;elseevent.events = EPOLLOUT;memset(&event.data, 0, sizeof(event.data));event.data.fd = fd;if (epoll_ctl(manager->epoll_fd, EPOLL_CTL_ADD, fd, &event) == -1 &&errno != EEXIST) {result = isc__errno2result(errno);}return (result);

View Code

这是将pipe_fds[0]加入epoll_fd的监听队列,EPOLL_CTL_ADD是操作类型,注册该fd到epoll_fd上。这个管道的目的是接收管理该线程的消息,比如线程退出。

那么进入线程看:

static isc_threadresult_t
watcher(void *uap) {isc__socketmgr_t *manager = uap;isc_boolean_t done;int ctlfd;int cc;
#ifdef USE_KQUEUEconst char *fnname = "kevent()";
#elif defined (USE_EPOLL)const char *fnname = "epoll_wait()";
#elif defined(USE_DEVPOLL)const char *fnname = "ioctl(DP_POLL)";struct dvpoll dvp;
#elif defined (USE_SELECT)const char *fnname = "select()";int maxfd;
#endifchar strbuf[ISC_STRERRORSIZE];
#ifdef ISC_SOCKET_USE_POLLWATCHpollstate_t pollstate = poll_idle;
#endif/** Get the control fd here.  This will never change.*/ctlfd = manager->pipe_fds[0];done = ISC_FALSE;while (!done) {do {
#ifdef USE_KQUEUEcc = kevent(manager->kqueue_fd, NULL, 0,manager->events, manager->nevents, NULL);
#elif defined(USE_EPOLL)cc = epoll_wait(manager->epoll_fd, manager->events,manager->nevents, -1);
#elif defined(USE_DEVPOLL)dvp.dp_fds = manager->events;dvp.dp_nfds = manager->nevents;
#ifndef ISC_SOCKET_USE_POLLWATCHdvp.dp_timeout = -1;
#elseif (pollstate == poll_idle)dvp.dp_timeout = -1;elsedvp.dp_timeout = ISC_SOCKET_POLLWATCH_TIMEOUT;
#endif    /* ISC_SOCKET_USE_POLLWATCH */cc = ioctl(manager->devpoll_fd, DP_POLL, &dvp);
#elif defined(USE_SELECT)LOCK(&manager->lock);memcpy(manager->read_fds_copy, manager->read_fds,manager->fd_bufsize);memcpy(manager->write_fds_copy, manager->write_fds,manager->fd_bufsize);maxfd = manager->maxfd + 1;UNLOCK(&manager->lock);cc = select(maxfd, manager->read_fds_copy,manager->write_fds_copy, NULL, NULL);
#endif    /* USE_KQUEUE */if (cc < 0 && !SOFT_ERROR(errno)) {isc__strerror(errno, strbuf, sizeof(strbuf));FATAL_ERROR(__FILE__, __LINE__,"%s %s: %s", fnname,isc_msgcat_get(isc_msgcat,ISC_MSGSET_GENERAL,ISC_MSG_FAILED,"failed"), strbuf);}#if defined(USE_DEVPOLL) && defined(ISC_SOCKET_USE_POLLWATCH)if (cc == 0) {if (pollstate == poll_active)pollstate = poll_checking;else if (pollstate == poll_checking)pollstate = poll_idle;} else if (cc > 0) {if (pollstate == poll_checking) {/** XXX: We'd like to use a more* verbose log level as it's actually an* unexpected event, but the kernel bug* reportedly happens pretty frequently* (and it can also be a false positive)* so it would be just too noisy.*/manager_log(manager,ISC_LOGCATEGORY_GENERAL,ISC_LOGMODULE_SOCKET,ISC_LOG_DEBUG(1),"unexpected POLL timeout");}pollstate = poll_active;}
#endif} while (cc < 0);#if defined(USE_KQUEUE) || defined (USE_EPOLL) || defined (USE_DEVPOLL)done = process_fds(manager, manager->events, cc);
#elif defined(USE_SELECT)process_fds(manager, maxfd, manager->read_fds_copy,manager->write_fds_copy);/** Process reads on internal, control fd.*/if (FD_ISSET(ctlfd, manager->read_fds_copy))done = process_ctlfd(manager);
#endif}manager_log(manager, TRACE, "%s",isc_msgcat_get(isc_msgcat, ISC_MSGSET_GENERAL,ISC_MSG_EXITING, "watcher exiting"));return ((isc_threadresult_t)0);
}

View Code

无限循环,epoll_wait当监听的epoll_fd队列上有IO事件发生时,将对应的socket fd和事件放入events数组中,并且将这些注册在epoll_fd上的socket fd对应事件清空。

process_fds遍历数组,找到对应的socket fd,并判断该fd是不是线程控制管道,如果是则会在执行完其他socket fd上的对应事件后再处理管道中的控制消息。

static isc_boolean_t
process_fds(isc__socketmgr_t *manager, struct epoll_event *events, int nevents)
{int i;isc_boolean_t done = ISC_FALSE;
#ifdef USE_WATCHER_THREADisc_boolean_t have_ctlevent = ISC_FALSE;
#endifif (nevents == manager->nevents) {manager_log(manager, ISC_LOGCATEGORY_GENERAL,ISC_LOGMODULE_SOCKET, ISC_LOG_INFO,"maximum number of FD events (%d) received",nevents);}for (i = 0; i < nevents; i++) {REQUIRE(events[i].data.fd < (int)manager->maxsocks);
#ifdef USE_WATCHER_THREADif (events[i].data.fd == manager->pipe_fds[0]) {have_ctlevent = ISC_TRUE;continue;}
#endifif ((events[i].events & EPOLLERR) != 0 ||(events[i].events & EPOLLHUP) != 0) {/** epoll does not set IN/OUT bits on an erroneous* condition, so we need to try both anyway.  This is a* bit inefficient, but should be okay for such rare* events.  Note also that the read or write attempt* won't block because we use non-blocking sockets.*/events[i].events |= (EPOLLIN | EPOLLOUT);}process_fd(manager, events[i].data.fd,(events[i].events & EPOLLIN) != 0,(events[i].events & EPOLLOUT) != 0);}#ifdef USE_WATCHER_THREADif (have_ctlevent)done = process_ctlfd(manager);
#endifreturn (done);
}

View Code

待续

转载于:https://www.cnblogs.com/ding-linux-coder/p/4432666.html

BIND9的架构与机制笔记1相关推荐

  1. 《大型网站技术架构》读书笔记四:瞬时响应之网站的高性能架构

    来源:http://www.cnblogs.com/edisonchou/p/3809839.html 此篇已收录至<大型网站技术架构>读书笔记系列目录贴,点击访问该目录可获取更多内容. ...

  2. 《大型网站技术架构》读书笔记三:大型网站核心架构要素

    来源:http://www.cnblogs.com/edisonchou/p/3806348.html 此篇已收录至<大型网站技术架构>读书笔记系列目录贴,点击访问该目录可获取更多内容. ...

  3. 《大型网站技术架构》读书笔记一:大型网站架构演化

    来源:http://www.cnblogs.com/edisonchou/p/3773891.html 此篇已收录至<大型网站技术架构>读书笔记系列目录贴,点击访问该目录可获取更多内容. ...

  4. 《大型网站技术架构》读书笔记之七:随需应变之网站的可扩展架构

    来源:http://www.cnblogs.com/edisonchou/p/3862389.html 此篇已收录至<大型网站技术架构>读书笔记系列目录贴,点击访问该目录可获取更多内容. ...

  5. Flux架构小白入门笔记

    Flux架构小白入门笔记 Flux是facebook提出的一种处理前端数据的架构,学习Flux就是学习它的思想. 这个笔记是我在学习了阮一峰老师的Flux 架构入门教程之后得出, 里面的例子和部分原文 ...

  6. 系统架构师学习笔记_第六章(下)_连载

    系统架构师学习笔记_第六章(下)_连载 6.3 基于 UML 的软件开发过程 6.3.1  开发过程概述 UML 是独立于软件开发过程的,能够在几乎任何一种软件开发过程中使用.迭代的渐进式软件开发过程 ...

  7. 阿里P8架构师进阶心得:分布式数据库架构MyCat学习笔记送给你

    前言: MyCat 是一个数据库分库分表中间件,使用 MyCat 可以非常方便地实现数据库的分库分表查询,并且减少项目中的业务代码.今天我们将通过数据库架构发展的演变来介绍 MyCat 的诞生背景,以 ...

  8. 【Azure 架构师学习笔记】-Azure Data Factory (4)-触发器详解-事件触发器

    本文属于[Azure 架构师学习笔记]系列. 本文属于[Azure Data Factory]系列. 接上文[Azure 架构师学习笔记]-Azure Data Factory (3)-触发器详解-翻 ...

  9. 好家伙,阿里P8撰写的Java微服务架构全栈笔记GitHub一夜飞到榜首

    Java微服务作为当下最常用的架构技术,快速实现编程开发而且维护起来十分的方便,可以简单是实现高可用,分布式开发而且也很安全! 今天给大家分享的这份<Java微服务架构全栈笔记>,用140 ...

最新文章

  1. Linux上安装jdk并配置环境变量
  2. 爬虫的系统框架组成-解析器
  3. 应用程序启动器选项卡以及页面内容的设置
  4. mysql PREPARE用法_PHP5 mysqli的
  5. Interference Signal 第八届
  6. 小试牛刀JavaScript鼠标事件
  7. 用Prime31实现Google Play In-App-Blling
  8. 飞鸽传书下载2013
  9. 淘宝网架构分享总结[转]
  10. makefile函数集锦【转】
  11. java计算机毕业设计劳务外包管理系统源码+系统+mysql数据库+lw文档
  12. 百度地图生成器不显示图片的原因
  13. Ubuntu Install Zhengma
  14. 康师傅红烧牛肉面:守护平凡英雄,成就烟火人生
  15. 不老嘞 - 2004和老婆游香山
  16. 重新振作起来,继续战斗
  17. RJ45接头 和 RJ48接头的区别
  18. 上下文无关文法的分析树(Context-Free Grammar, CFG)的分析树--编译原理
  19. XShell4 SSH服务器拒绝了密码解决办法
  20. alpine是什么 ?

热门文章

  1. 如何获取Google地图API密钥?
  2. 后端返回数据ios接收精度丢失问题
  3. 美白,去斑,去黄,调理,中药面膜粉
  4. ECOS 3.0 SDK USER GUIDE
  5. 5G NR CSI Report在PUSCH和PUCCH上反馈
  6. 颠覆传统铝型材挤压生产,数字孪生生产方式来袭
  7. Android进阶——自定义View之自己绘制彩虹圆环调色板
  8. 返回空 Buckets
  9. 自动生成数据库表结构word文档的工具(一)---- DBDocumentGenerator
  10. 计算机组成 并行体系 Flynn分类法