bind-架构分析

从main函数开始,解析配置参数,解析配置文件


void run()
{
    dispatch(manager);
    {
        //finish就是它的exiting为true同时它的task队列为空
        while (!FINISHED(manager))
        {
            #ifdef USE_WORKER_THREADS
            //这里进去wait的条件是ready_task队列为空或者pause_requested为1或者exclusive_requested为1
            //注意是所有的线程刚开始都会睡眠在work_available条件变量上,只唤醒一个线程,唤醒以后又会去陷入第二个循环,如果发现没有任务了就继续睡眠
            while ((empty_readyq(manager) || manager->pause_requested ||
                        manager->exclusive_requested) && !FINISHED(manager))
            {
                //线程创建好的时候,就阻塞在这个work_available条件变量上
                WAIT(&manager->work_available, &manager->lock);
            }
            //从ready_task队列中获取到任务
            task = pop_readyq(manager)
            if (task != NULL)
            {
                manager->tasks_ready--;
                manager->tasks_running++;
                task->state = task_state_running;
                //这个是调用回调函数并且修改task的状态的
                //一个task处理的事件个数是有上限的。当task的事件为空或者处理的事件超过阈值的时候,就跳出循环了
                do
                {
                    //这是针对task做的
                    event = HEAD(task->events);
                    DEQUEUE(task->events, event, ev_link);
                    task->nevents--;
                    //执行封装好的回调
                    (event->ev_action)((isc_task_t *)task,event);
                     dispatch_count++;
                    if (task->references == 0 &&
                                    EMPTY(task->events) &&
                                    !TASK_SHUTTINGDOWN(task))  
                    //处理shutdown事件  
                    if (EMPTY(task->events))   
                        done = true
                        finished = true
                    //一个task处理的事件的个数是有上限的超过5个就拒绝处理了
                    else if dispatch_count >= task->quantum
                        requeue = true;
                        done = true;
                                     
                }while (!done);
                //如果一个task是finished的,那么他就结束,释放掉该task的内存
                if (finished)
                    task_finished(task);
                manager->tasks_running--;
                #ifdef USE_WORKER_THREADS
                //exclusive_requested为true同时只剩下一个task,那就唤醒阻塞的线程
                if (manager->exclusive_requested &&manager->tasks_running == 1)
                    SIGNAL(&manager->exclusive_granted);
                else if (manager->pause_requested &&manager->tasks_running == 0)
                {
                    SIGNAL(&manager->paused);
                }
                //该task是由于超过上限才退出的,因此还要再次入队到ready_task
                if (requeue)
                    push_readyq(manager, task);
                //如果这种,
                if (manager->tasks_running == 0 && empty_readyq(manager))
                    BROADCAST(&manager->work_available);
            }
        }
    }
}
isc_result_t
isc_taskmgr_create(isc_mem_t *mctx, unsigned int workers,
                   unsigned int default_quantum, isc_taskmgr_t **managerp)
{
    {
        manager = isc_mem_get(mctx, sizeof(*manager));
        //taskmgrmethods方法是外面写好的
        manager->common.methods = &taskmgrmethods;
        #ifdef USE_WORKER_THREADS
            //这里是关键,创建named_g_cpus个线程
            manager->threads = isc_mem_allocate(mctx,
                                            workers * sizeof(isc_thread_t));
        #endif /* USE_WORKER_THREADS */
        //如果不用多线程的话,就直接单线程
        //初始化三个条件变量
        if (isc_condition_init(&manager->work_available) != ISC_R_SUCCESS)
        if (isc_condition_init(&manager->exclusive_granted) != ISC_R_SUCCESS)
        if (isc_condition_init(&manager->paused) != ISC_R_SUCCESS)
        //初始化三个队列
        manager->default_quantum = default_quantum;
        INIT_LIST(manager->tasks);
        INIT_LIST(manager->ready_tasks);
        INIT_LIST(manager->ready_priority_tasks);
        manager->tasks_running = 0;
        manager->tasks_ready = 0;
        manager->exclusive_requested = false;
        manager->pause_requested = false;
        manager->exiting = false;
        manager->excl = NULL;

        #ifdef USE_WORKER_THREADS
        //这里开始创建线程,每个线程跑的函数是run
        for (i = 0; i < workers; i++)
        {
            isc_thread_create(run, manager,&manager->threads[manager->workers]) ==
                    ISC_R_SUCCESS)
        }
        #endif /* USE_WORKER_THREADS */
    }
}
// 注意调用该函数的时候会获取sock的锁,也就是说最终只有一个线程可能进入到while循环中去
void internal_recv()
{
    //加锁
    dev = ISC_LIST_HEAD(sock->recv_list);
    while (dev != NULL)
    {
        //doio_recv内部调用的就是recvmsg函数来接收报文
        switch (doio_recv(sock, dev))
        {
            case DOIO_HARD:
                send_recvdone_event(sock, &dev);
                {
                    //
                    task = (*dev)->ev_sender;
                    (*dev)->ev_sender = sock;
                    //这里由于本次事件已经处理完了,所以把该事件从该task中移除
                    ISC_LIST_DEQUEUE(sock->recv_list, *dev, ev_link);
                    //每次无论新增还是删除一个事件,都要对task进行一次处理
                    if (((*dev)->attributes & ISC_SOCKEVENTATTR_ATTACHED)
            == ISC_SOCKEVENTATTR_ATTACHED)
                    {
                        isc_task_sendanddetach(&task, (isc_event_t **)dev);
                        {
                            //把事件添加到task中
                            idle1 = task_send(task, eventp);
                            //如果task没有事件了,并且状态为idle的,则修改状态返回true
                            idle2 = task_detach(task);
、
                            //满足任意一个都添加进去
                            if (idle1 || idle2)
                                task_ready(task);
                        }
                    }
                    else
                    {
                        //只负责添加event进到task中
                        isc_task_send(task, (isc_event_t **)dev);
                    }
                }
                break;
        }
        dev = ISC_LIST_HEAD(sock->recv_list);
    }
    //如果说recv_list中不为空的话,则说明还有新的数据到来,则添加53端口对应的fd到epoll中,具体方法是通过pipe[1]写入,这样的话watcher线程就会从pipi[0]中读取数据,然后调用process_ctlfd函数内部是epoll_ctrl,把该fd再次添加进去进行监听
    if (!ISC_LIST_EMPTY(sock->recv_list))
        select_poke(sock->manager, sock->fd, SELECT_POKE_READ);
        {
            cc = write(mgr->pipe_fds[1], buf, sizeof(buf));
        }
    //释放锁
}
void watcher()
{
    while (!done)
    {
        do
        {
            //调用poll_wait进行监听了
            cc = epoll_wait(manager->epoll_fd, manager->events,manager->nevents, -1);
        }} while (cc < 0);
        done = process_fds(manager, manager->events, cc);
        {
            bool done = false;
            bool have_ctlevent = false;
            //开始处理有事件发生的套接字
            for (i = 0; i < nevents; i++)
            {
                //就是主进程监听的那个socket传来的信息
                if (events[i].data.fd == manager->pipe_fds[0])
                {
                    have_ctlevent = true;
                    continue;
                }
                //传进去的参数的意义是,该fd是可读的还是可写的
                process_fd(manager, events[i].data.fd,
                           (events[i].events & EPOLLIN) != 0,
                           (events[i].events & EPOLLOUT) != 0);
                {
                    //当套接字来了消息以后
                    //取出对应fd的socket信息
                    sock = manager->fds[fd];
                    //如果可读
                    if (readable)
                    {
                        if sock==NULL:
                                    goto unlock_fd;
                        if (sock->listener)
                               
                                //这个是tcp协议的
                                dispatch_accept(sock);
                        else
                                dispatch_recv(sock);
                                {
                                    //设置事件的action, 并且封装event到task中,如果是新的task的话,就会把task添加到ready_task中,这样的话阻塞的run线程就会执行了
                                    iev->ev_action = internal_recv;
                                    iev->ev_arg = sock;
                                    //该函数的功效是将事件添加到处于running或者ready的task中,如果说task是idle的状态的话,则最后还要把 task添加到ready_task队列中去
                                    isc_task_send(sender, (isc_event_t **)&iev);
                                    
                                }
                        unwatch_read = true;
                    }
                    if (writeable)
                    {
                        if sock==NULL:
                                    goto unlock_fd;
                        if (sock->connecting)
                                //tcp的暂且不关注
                                dispatch_connect(sock);
                        else
                                dispatch_send(sock);
                                {
                                    iev->ev_action = internal_send;
                                    iev->ev_arg = sock;
                                    isc_task_send(sender, (isc_event_t **)&iev);
                                }
                        unwatch_write = true;
                    
                    }
                    unlock_fd:
                        //这里是如果fd对应的sock为空的情况,则再次调用epoll_ctrl添加socket进去
                }
                
            }
            //以上处理完了来信息的所有fd以后,这里就处理pipe[0]来信息的情况
            if (have_ctlevent)
                done = process_ctlfd(manager);
                {
                    for(;;)
                    {
                        //这个函数就是从pipe[0]中读数据,然后把fd和msg返回
                        select_readmsg(manager, &fd, &msg);
                        //如果是关机事件的话,那就尽量让该waicher线程退出
                        if (msg == SELECT_POKE_SHUTDOWN)
                            return (done = true);
                        //这个函数就是调用epoll_ctrl
                        wakeup_socket(manager, fd, msg);
                    }
                    return done=false
                }
        }
    }                                
}
void setup_watcher()
{
    //设置epoll的结构
    manager->nevents = ISC_SOCKET_MAXEVENTS;
    manager->events = isc_mem_get(mctx, sizeof(struct epoll_event) *
                                      manager->nevents);
    //创建fd
    manager->epoll_fd = epoll_create(manager->nevents);
    //这里把管道的一端添加到epoll中,
    result = watch_fd(manager, manager->pipe_fds[0], SELECT_POKE_READ);
    {
        //这里将管道的一段添加到epoll中进行监听,且监听读事件
        ret = epoll_ctl(manager->epoll_fd, op, fd, &event);
    }
}
isc_socketmgr_create2()
{
    if (maxsocks == 0)
        maxsocks = ISC_SOCKET_MAXSOCKETS;
    //manager
    manager = isc_mem_get(mctx, sizeof(*manager));
    manager->maxsocks = maxsocks;
    //预留socket的位置
    manager->fds = isc_mem_get(mctx,manager->maxsocks * sizeof(isc__socket_t *));
    manager->fdstate = isc_mem_get(mctx, manager->maxsocks * sizeof(int));
    //预留epoll的位置
    manager->epoll_events = isc_mem_get(mctx, (manager->maxsocks *sizeof(uint32_t))); 
    //设置预处理方法
    manager->common.methods = &socketmgrmethods;
    
    #ifdef USE_WATCHER_THREAD
        //创建条件变量
        if (isc_condition_init(&manager->shutdown_ok) != ISC_R_SUCCESS)
        //创建管道
        if (pipe(manager->pipe_fds) != 0)
    //这里只看使用epoll的情况
    result = setup_watcher(mctx, manager);
    //这里开始创建watcher线程
    if (isc_thread_create(watcher, manager, &manager->watcher))
    
                                                                            
}
void create_managers()
{
    //如果使用多线程的话就设置为CPU的个数
    #ifdef ISC_PLATFORM_USETHREADS
    if (named_g_cpus == 0)
        named_g_cpus = named_g_cpus_detected;
    else
        named_g_cpus = 1;
    //线程分发个数的设置
    if (named_g_udpdisp == 0)
        if (named_g_cpus_detected == 1)
            named_g_udpdisp = 1;
        else
            named_g_udpdisp = named_g_cpus_detected - 1;
    //创建一个task的管理器,内部创建named_g_cpus个run线程,run线程在满足某些条件后要么都睡眠在某个条件变量上,要么就循环去执行task中的事件的回调,线程通过锁来竞争,通过条件变量来同步
    result = isc_taskmgr_create(named_g_mctx, named_g_cpus, 0,
                                    &named_g_taskmgr);
    //这个是建立监听端口的,重点只看udp协议的
    result = isc_socketmgr_create2(named_g_mctx, &named_g_socketmgr,
                                       maxsocks);
    
}
void run_server()
{
    //这个就是创建一个分发管理器
    dns_dispatchmgr_create();
    ns_interfacemgr_create();
    //这个是最主要的,是打开一些socket的
    load_configuration()
    {
        //内部有一系列的函数调用,直到调用到ns_interface_setup
        //这个函数主要就是初始化ifp的一些内容
        result = ns_interface_create(mgr, addr, name, &ifp);
        {
            //
            ifp = isc_mem_get(mgr->mctx, sizeof(*ifp));
            result = ns_clientmgr_create()
            for (disp = 0; disp < MAX_UDP_DISPATCH; disp++)
                ifp->udpdispatch[disp] = NULL;
        }
        result = ns_interface_listenudp(ifp)
        {
            for (disp = 0; disp < ifp->nudpdispatch; disp++)
            {
                result = dns_dispatch_getudp_dup()
                {
                    result = dns_dispatchmgr_setudp()
            
                    //没有的话就创建一个,disp=0的时候传递进去的dup_socket是NULL,对于后面所有的disp传递进去的都是第一个创建好的dispatch的socket,注意采用dup的方式进行地址复用
                    result = dispatch_createudp()
                    {
                        disp->socktype = isc_sockettype_udp;
                        //就是socket,bind那一系列
                        result = get_udpsocket()
        
                        result = open_socket(sockmgr, localaddr, 0, &sock, NULL);
                        disp->socket = sock;
                        disp->local = *localaddr;
                        //分配64个task
                        for (i = 0; i < disp->ntasks; i++)
                        {
                            result = isc_task_create(taskmgr, 0, &disp->task[i]);
                        }
                        ISC_LIST_APPEND(mgr->list, disp, link);
                        disp->ctlevent = isc_event_allocate()
                    }
                }
            }
            //创建client,为每个client创建不同的事件
            result = ns_clientmgr_createclients
            {
                for (disp = 0; disp < n; disp++) 
                {
                    result = get_client()    
                    {
                        //每一个dispatch就有一个client,client里面的是dns信息,task等
                        result = client_create(manager, &client);
                        {
                            result = isc_task_create(manager->taskmgr, 0, &client->task);
                            result = dns_message_create()
                            //设置client_senddone事件
                            client->sendevent = isc_socket_socketevent()    
                            //设置ns__client_request事件
                            client->recvevent = isc_socket_socketevent()
                            //初始化查询的一些信息
                            result = ns_query_init(client);
                        }
                        isc_socket_t *sock;
                        //赋值client的dispatch,
                        dns_dispatch_attach(disp, &client->dispatch);
                        //获取到前面创建的socket
                        sock = dns_dispatch_getsocket(client->dispatch);
                        //赋值client的udpsocket
                        isc_socket_attach(sock, &client->udpsocket);
                        //就是client_start事件,然后工作线程就开始执行client_start事件了
                        ev = &client->ctlevent;
                        isc_task_send(client->task, &ev);

                        //然后就是多个线程开始执行client_start函数了,
                        client_start
                        {
                            client_udprecv(client);
                            {
                                它的内部就是recvmsg函数
                                下面有一个比较关键的一步操作是,这个就是把fd加入到了watcher线程中进行监听了,如果监听到信息了就调用internal_recv处理了,它内部仍然是recvmsg函数
                                if (ISC_LIST_EMPTY(sock->recv_list) && !sock->pending_recv)
                                    select_poke(sock->manager, sock->fd, SELECT_POKE_READ);
                            }
                        }
                    }
                }
            }
        }
    }
   
}
void
named_server_create(isc_mem_t *mctx, named_server_t **serverp)
{
    named_server_t *server = isc_mem_get(mctx, sizeof(*server));
    //设置server的一些信息
    isc_task_create(named_g_taskmgr, 0, &server->task),"creating server task")
    //把run_server添加到onrun中,这样的话主程序一起起来就会调用run_server
    isc_app_onrun(named_g_mctx, server->task, run_server, server)
                                
}
void setup()
{
    //这里是查询系统cpu的个数
    #ifdef ISC_PLATFORM_USETHREADS
    named_g_cpus_detected = isc_os_ncpus();
    //如果是后台的话这里就启动一个后台进程
    if (!named_g_foreground)
                named_os_daemonize();
    //这部分内容开始日志输出,有限资源获取,直接略过
    //
    result = create_managers();
    
    named_server_create(named_g_mctx, &named_g_server);
}
//解析参数,初始化各个变量中
parse_command_line(argc, argv);
//这中间会处理很多用户和权限的问题
setup();

 

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值