BIND9的架构与机制笔记1

2023-11-18

  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_THREAD
    result = 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;
        else
                event.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_KQUEUE
    const 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;
#endif
    char strbuf[ISC_STRERRORSIZE];
#ifdef ISC_SOCKET_USE_POLLWATCH
    pollstate_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_KQUEUE
            cc = 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_POLLWATCH
            dvp.dp_timeout = -1;
#else
            if (pollstate == poll_idle)
                dvp.dp_timeout = -1;
            else
                dvp.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_THREAD
    isc_boolean_t have_ctlevent = ISC_FALSE;
#endif

    if (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_THREAD
        if (events[i].data.fd == manager->pipe_fds[0]) {
            have_ctlevent = ISC_TRUE;
            continue;
        }
#endif
        if ((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_THREAD
    if (have_ctlevent)
        done = process_ctlfd(manager);
#endif

    return (done);
}
View Code

 待续

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

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

BIND9的架构与机制笔记1 的相关文章

  • Java 断点调试 循环调试

    java断点调试 以eclipse为例 1 基础调试 这里都是一些基础 除了最后一个都十分常用 名称 快捷键 作用 Resume F8 运行至下一断点 Step Into F5 进入方法 Step Over F6 运行完当前语句 User
  • PCL 点云按高程渲染颜色

    目录 一 算法原理 二 代码实现 三 结果展示 四 CloudCompare 五 备注 一 算法原理 首先按照Z轴方向求取所在点云的高程极值 包括高程最大值与最小值 计算高程中值 然后选取渲染的红 绿 蓝三种颜色的值 最后 自上而下 为红绿
  • NBA的字母哥如何拿到2415万美金年薪

    前言 NBA是世界上最成功的体育联盟之一 为了制定合理的运作规范 联盟会与球员工会签署劳资协议 协议里规定了球队的工资帽 一支球队球员工资总额的上限 顶薪 球员薪水的上限 底薪 球员的最低薪水 和其他规范 2011年 经历了停摆事件 联盟和
  • 一张图理清ASP.NET Core启动流程

    1 引言 对于ASP NET Core应用程序来说 我们要记住非常重要的一点是 其本质上是一个独立的控制台应用 它并不是必需在IIS内部托管且并不需要IIS来启动运行 而这正是ASP NET Core跨平台的基石 ASP NET Core应
  • JS 数组定义及详解

    一 数组简介 1 什么是数组 数组是值的有序集合 每个值叫做元素 每个元素在数组中都有数字位置编号 也就是索引 JS中的数组是弱类型的 数组中可以含有不同类型的元素 数组元素甚至可以是对象或其他数组 例如 var arr 1 true nu
  • kubernetes运维---calico之ipip模式抓包分析

    一 calico介绍 Calico是Kubernetes生态系统中另一种流行的网络选择 虽然Flannel被公认为是最简单的选择 但Calico以其性能 灵活性而闻名 Calico的功能更为全面 不仅提供主机和pod之间的网络连接 还涉及网
  • 功能实现:Unity中一个动画,只播放中间指定的一截,而且循环播放

    一 要播放的动画 直播中间一截 如图 总的动画为长度为2分钟零8秒 二 Button和对应事件 三 事件的代码 在Start 里面绑定 private void Awake myAnim animGo GetComponent
  • Flutter实现app自动升级

    话不多说 有过开发过移动应用的人都应该自动升级流程 首先获取本地应用版本 然后从服务器获取线上移动应用版本号作比较是否升级 第一步获取版本信息 API https pub dev packages package info 获取应用版本号
  • iview on-change用法

    原地址 https segmentfault com q 1010000011589626 iview框架select选择框on change事件如何返回当前选中的值 这是文档中的解释 on change 选中的Option变化时触发 默认
  • C++类与封装实例说明

    众所周知 C 具有三大特性 分别为封装 继承 多态 今天有位同学问到我应该如何去理解 我翻了翻笔记本 找到以前上课时学到的案例来解释 首先 成员函数存在希望公开或不希望公开的属性 这也构成了定义成员函数访问级别的三项 1 public 公开
  • 架构师--IT策略灵魂的创造者

    http blog csdn net aspop archive 2006 01 21 585823 aspx 在比尔 盖茨的众多称谓中 据说他更偏爱 首席软件架构师 同样 在网易创始人丁磊名字前 也有 首席架构师 这样的称谓 对于企业来说
  • IDEA国际化资源Key无法全局重命名的解决方案

    一 前言 最近在开发中使用到了HibernateValidator进行入参校验以及错误消息的国际化支持 大家应该都知道在使用HibernateValidator进行校验的时候 我们只需在需要在校验的变量上添加相应的注解 同时在message
  • Flutter 应用程序更新

    Flutter 应用程序更新 原文 https medium com flutter community in app update the flutter way 2f25e4a02c02 前言 当您推出应用程序的新版本时 您希望您的用户
  • CSS3背景渐变

    我们经常可以看到有些背景色并不是纯色 而是好看的渐变色 css3知我懂我 给我们提供了制作渐变背景色的属性 渐变主要包括线性渐变和径向渐变 接下来逐一介绍用法 1 线性渐变 线性渐变 linear gradients 表示颜色沿着一条直线过
  • 设计模式--原型模式

    原型模式 属于创建型模式 基本原理 又称为克隆模式 拷贝本身对象 可以直接使用语言中的拷贝构造 主要流程 在构建对象的时候实现一个对本身的拷贝函数 特别注意 要有对应的销毁方法 include
  • 集合框架(二)

    集合框架 二 回顾 Collection List Set的特点 Collection 不唯一的 无序的 List 不唯一的 有序 Set 唯一的 无序的 Collection和Collections的区别 Collection是集合的顶级
  • C语言/C++实现栈操作

    一 栈的概念 栈是一种常用的数据结构 它遵循先入后出 Last In First Out LIFO 的原则 栈的操作只在栈的一端进行 该端被称为栈顶 而另一端称为栈底 栈的基本操作包括压栈 入栈 push 和弹栈 出栈 pop 分别用于将元
  • HTTP 常见错误

    HTTP 错误 400 400 请求出错 由于语法格式有误 服务器无法理解此请求 不作修改 客户程序就无法重复此请求 HTTP 错误 401 401 1 未授权 登录失败 此错误表明传输给服务器的证书与登录服务器所需的证书不匹配 请与 We
  • 【Python与机器学习2-1】pandas 基本数据对象及操作

    series 相当于一维数组 要有向量化操作思想 series是类似一维数组的对象 即一个列向量 初始化series 通过列表初始化series 默认数字为索引 ser obj pandas Series list 通过字典初始化serie
  • JSP页面中page指令contentPage/pageEncoding具有什么功能呢?

    转自 JSP页面中page指令contentPage pageEncoding具有什么功能呢 下文将讲述page指令的contentPage及pageEncoding指令的功能简介说明 如下所示 page指令的contentPage及pag

随机推荐

  • Antd DatePicker 设置默认值报clone.weekday is not a function

    代码 dayjs版本1 11 7 页面 当点击页面日期框会报clone weekday is not a function 解决方法 在jsx文件中添加如下js import dayjs from dayjs import advanced
  • AngularJS单元测试环境搭建及验证

    AngularJS的单元测试 要测试AngularJS 需要先搭建相关的测试环境 之前已经安装了Node js并验证了基本的功能 同时下载了AngularJS的包 成功运行了AngularJS编写的程序 也就是说基本的开发环境已经构建完成
  • ArcGIS处理自相交面

    问题 我们在获取一些osm等开源地理数据网站获取数据后 比如建筑物数据 往往需要对数据进行处理后 才可以进行分析 对于面数据 处理面自相交问题是必须操作 如下图 就是自相交的面 解决方案 该问题可以使用ArcGIS轻松解决 新建线要素 选择
  • ARm 移植最新版QT5.12

    转载 https blog csdn net weixin 37771089 article details 84989447 一 准备 ubuntu 12 04 源码 http download qt io archive qt 5 12
  • IDEA使用maven进行多模块项目打包并梳理正确的打包顺序

    maven多模块打包一般相互之间都有互相的依赖关系 如果没有按照正确的依赖关系顺序进行打包就会报错 例如有三个模块web service common 其中web依赖service web和service都依赖common 那么正确的打包顺
  • hsql获取数组中最后一个值的写法

    一 问题抛出 在数据分析中我们有时候会遇到需要取出数组中最后一个值的方法 1 表xxx数据如下图所示 2 现在需要取出字符串最后的 321 和 987 二 方案探讨 1 反转字符串后 使用切割函数切割获取第一个值 然后再反转一下 代码如下
  • Spring Boot starter 启动流程(无废话版)

    如果无产阶级不能发出自己的声音 他们就会被社会遗忘 一 pom xml文件 1 父依赖 其中它主要是依赖一个父项目 主要是管理项目的资源过滤及插件
  • Superset整合keycloak系统

    本篇主要介绍superset如何整合单点登陆系统keycloak 现在网上的博客大部分都是失效了 这里我相当于更新一下 避免大家再走弯路 一 环境配置 Macos keycloak 18 0 0 superset 2 1 0 keycloa
  • PMSM学习笔记1——永磁同步电机的工作原理与数学模型

    文章目录 一 PMSM工作原理 1 同步电机工作原理 来源 电机学 李发海 2 永磁同步电机数学模型及坐标变换 来源 现代电机控制技术 王成元 2 1旋转磁场 2 2三相PMSM的基本数学模型 2 3三相PMSM的坐标变换 2 3 1 Cl
  • 【Unity 3D】学习笔记 - 粒子系统制作

    这次的任务是制作一个简单的粒子系统 并用代码控制使之在不同的场景下呈现出不同的效果 我想要制作出颜色渐变的烟花效果 关于粒子系统 可以参考 Unity 3D 学习笔记 粒子系统初探 粒子系统基本设置如下 其中Simulation Rotat
  • 学生用计算机怎么恢复出厂设置,电脑怎么恢复出厂设置

    关机或重启时 按住电脑键盘的 Del 键进入BIOS 使用Enter回车键选中 Load Optimized Defaults 选项 使用方向键选中 Y 确认 点击 Save Exit Step 或者按 F10 退出即可 以下是详细介绍 电
  • Go语言实现Onvif客户端:2、获取设备信息

    Go语言实现Onvif客户端 2 获取设备信息 文章目录 Go语言实现Onvif客户端 2 获取设备信息 1 思路 2 代码 1 思路 搜索设备 获取设备能力 通过设备能力的设备接口读取设备信息 我们上节说了 主要是通过设备信息中的内容来区
  • 线性代数 【基础1】

    文章目录 行列式 方阵的行列式公式 矩阵 矩阵的逆 矩阵的秩 伴随矩阵 初等变换与初等矩阵 分块矩阵 向量 正交矩阵 正交化 线性表示 线性无关与线性相关 极大无关组与向量组的秩 线性方程组 解的性质与判定 齐次线性方程组 非齐次线性方程组
  • 大型网站在架构上应当考虑哪些问题?

    分层 分层是处理任何复杂系统最常见的手段之一 将系统横向切分成若干个层面 每个层面只承担单一的职责 然后通过下层为上层提供的基础设施和服务以及上层对下层的调用来形成一个完整的复杂的系统 计算机网络的开放系统互联参考模型 OSI RM 和In
  • Java8 CompletableFuture处理多个异步任务

    CompletableFuture Java5引入了Future和 FutureTask 用于异步处理 Future可以通过get 方法获取异步的返回值 在Java8引入了CompletableFuture CompletableFutur
  • 设置GPU及显存大小

    20210128 引言 之前搜索过设置GPU和显存大小的方式 但是升级了新的版本的keras以及tensorflow 导致之前的代码失效了 这里记录一下 本质上 就是版本更换的原因 很多api可能被取消 或者改了别的 原始代码 import
  • 计算机网络ip尽最大努力交付,计算机网络知识(IP、TCP、UDP)--持续更新

    互联网的两个重要的基本特点 连通性和共享 计算机网络由若干结点和连接这些结点的链路组成 互联网的组成 边缘部分 核心部分 网络边缘的端系统之间的通信可分为两大类 客户 服务器方式 C S方式 和对等方式 P2P方式 互联网的核心部分 许多网
  • 原始传奇手游服务器不显示,原始传奇手游为什么进不去 无法登录游戏解决方法...

    近日有一款由古力娜扎代言的手游 原始传奇 上线了 不少玩家也很想体验一番 可是却发现原始传奇手游进不去 不知道是为什么 下面悠小悠就为大家详细介绍下无法登录游戏的原因和解决方法 一起探讨下吧 原始传奇手游进不去原因及解决方法 1 如果是登录
  • tomcat没有日志输出--解决办法

    程序没有问题 只是控制台信息卡 感觉像程序休眠了一样 然后在控制台点backspace或是enter 程序恢复正常 控制台日志正常输出 静态文件访问可以 解决办法 转载于 https blog 51cto com 13693838 2398
  • BIND9的架构与机制笔记1

    BIND9采用的是事件驱动的机制来工作 而事件的源头则是IO IO在linux使用的EPOLL的边缘触发模式 本篇说的是epoll BIND9如果创建了watcher线程 宏USE WATCHER THREAD控制 这里就讨论有线程的情况