1. 程式人生 > >Bind-9.6.0-P1原始碼分析之一:整體架構(初稿)

Bind-9.6.0-P1原始碼分析之一:整體架構(初稿)

轉載至:不知轉載源

一、 說明

這是bind解析程式的入口

事件bind程式也事件驅動型,以任務作為主要的執行。

當一個解析請求到來時,就會通過事件的產生來觸發任務dispatch處理。這樣的處理有相應

if (event->ev_action != NULL) {

861                                                 UNLOCK(&task->lock);

862                                                 (event->ev_action)(

task,event);

863                                                 LOCK(&task->lock);

這裡 action就是執行函式

本文主要關注整體的執行結構,主要參考檔案是main.c

二、 啟動入口

870 int

871 main(int argc, char *argv[]) { 命令列引數傳入

以上為設定錯誤訊息

898初始化系統日誌,許可權等

900初始化工作

904 命令列引數分析,如-g將日誌輸出到front-end

注意以

用到了鎖機制

830         LOCK(&lock);

832         UNLOCK(&lock);

833 

記憶體生成採用標準的系統呼叫 malloc和free,但考慮到多執行緒下的競爭情況,對記憶體塊訪問需要鎖機制。Ns_g_mctx是訊號量,要求ns_g_mctx!=NULL&&*ns_g_mctx=NULL

}

921                 ns_main_earlyfatal("isc_mem_create() failed: %s",

對設定

923         isc_mem_setname

(ns_g_mctx, "main", NULL);

924 //setup是重要的一部分,見分析三

925         setup();

接下來就是解析主體程式了,是通過迴圈來做的,直到錯誤或者接收到退出訊號。遞

/*

928          * Start things running and then wait for a shutdown request

929          * or reload.

930          */

931         do {

933 

934                 if (result == ISC_R_RELOAD) { //通過我們會做這種操作,當配置了一個新的zone檔案時

938                                          "isc_app_run(): %s",

940                         /*

941                          * Force exit.

942                          */

944                 }

946 

947 #ifdef HAVE_LIBSCF

948         if (ns_smf_want_disable == 1) {

951                         if (smf_disable_instance(instance, 0) != 0)

953                                                  "smf_disable_instance() "

954                                                  "failed for %s : %s",

955                                                  instance,

956                                                  scf_strerror(scf_error()));

957                 }

958                 if (instance != NULL)

959                         isc_mem_free(ns_g_mctx, instance);

960         }

961 #endif /* HAVE_LIBSCF */

962 

964 

966                 isc_mem_stats(ns_g_mctx, stdout);

968         }

969 

970         if (ns_g_memstatistics && memstats != NULL) {

971                 FILE *fp = NULL;

977                 }

978         }

981 

983 

985 

987 

989 

990         return (0);

991 }

三、 初始設定setup

596 

599 #ifdef HAVE_LIBSCF 是否solaris的smf管理機制

600         /* Check if named is under smf control, before chroot. */

602         /* We don't care about instance, just check if we got one. */

604                 ns_smf_got_instance = 1;

605         else

606                 ns_smf_got_instance = 0;

607         if (instance != NULL)

608                 isc_mem_free(ns_g_mctx, instance);

609 #endif /* HAVE_LIBSCF */

如果是chroot執行方式化,初始化可用資源。Chroot是以普通使用者執行超級資源,是unix系統的一種機制

612         /*

613          * Initialize system's random device as fallback entropy source

614          * if running chroot'ed.

615          */

616         if (ns_g_chrootdir != NULL) {

617                 result = isc_entropy_create(ns_g_mctx, &ns_g_fallbackentropy);

619                         ns_main_earlyfatal("isc_entropy_create() failed: %s",

621 

626                                              "entropy source %s: %s",

629                         isc_entropy_detach(&ns_g_fallbackentropy);

630                 }

631         }

632 #endif

看cpu數目

635         /*

636          * Check for the number of cpu's before ns_os_chroot().

637          */

638         ns_g_cpus_detected = isc_os_ncpus();

639 #endif

以下說明了最小許可權執行機制,讀config檔案需要有root機制,通過unix的sid置位實現,即setsid()

/*

644          * For operating systems which have a capability mechanism, now

645          * is the time to switch to minimal privs and change our user id.

646          * On traditional UNIX systems, this call will be a no-op, and we

647          * will change the user ID after reading the config file the first

648          * time.  (We need to read the config file to know which possibly

649          * privileged ports to bind() to.)

650          */

652 日誌初始化

655                 ns_main_earlyfatal("ns_log_init() failed: %s",

pid = fork();產生新的子程序,如果是直接named而不是named –g的話,因此,需要派生子程序,並關閉父的一些輸入輸出控制代碼,參見fork例程

if (!ns_g_foreground)

/*

669          * We call isc_app_start() here as some versions of FreeBSD's fork()

670          * destroys all the signal handling it sets up.

671          */

Isc_app_start主要是處理fork的訊號機制的恢復

674                 ns_main_earlyfatal("isc_app_start() failed: %s",

676 寫日誌檔案,開始啟動

678                       ISC_LOG_NOTICE, "starting BIND %s%s", ns_g_version,

680 

682                       ISC_LOG_NOTICE, "built with %s", ns_g_configargs);

683 

接下來是資源限制部分,可用#ulimit –a來理解

  /*

729          * Record the server's startup time.

730          */

733                 ns_main_earlyfatal("isc_time_now() failed: %s",

735 

生成管理器,如任務、超時、entropy、hash,socket等管理器

738                 ns_main_earlyfatal("create_managers() failed: %s",

740 

742 

743         /*

744          * Add calls to register sdb drivers here.

745          */

746         /* xxdb_init(); */

747 

748 #ifdef DLZ

749         /*

750          * Registyer any DLZ drivers.

751          */

754                 ns_main_earlyfatal("dlz_drivers_init() failed: %s",

756 #endif

757 

生成服務,重要部分,見分析六

758         ns_server_create(ns_g_mctx, &ns_g_server);

759 }

760 

四、 執行主體程式

433         isc_event_t *event, *next_event;

436         sigset_t sset;

439         int sig;

440 #endif

441 #endif /* ISC_PLATFORM_USETHREADS */

442 

443 #ifdef HAVE_LINUXTHREADS 如果啟用了多執行緒編譯,目前我們編譯的是單執行緒,可用ps –em|grep named檢視執行緒數

445 #endif

446 加鎖,事件佇列是關鍵區,race condition

447         LOCK(&lock);

448 

451 事件結構有sender,type,action,arguments,而採用佇列ev_link實現,事件FIFO依序處理。

452                 /*

453                  * Post any on-run events (in FIFO order).

454                  */主迴圈

456                      event != NULL;

457                      event = next_event) {

458                         next_event = ISC_LIST_NEXT(event, ev_link);

460                        task = event->ev_sender;

461                         event->ev_sender = NULL;

事件任務機制,見分析五

463                 }

464 

465         }

466 

467         UNLOCK(&lock);

468 以下主要為訊號捕獲處理機制,特別注意shutdown退出時的處理。訊號catch處理機制能夠使應用更安全退出。

470         /*

471          * Catch SIGHUP.

472          *

473          * We do this here to ensure that the signal handler is installed

474          * (i.e. that it wasn't a "one-shot" handler).

475          */

479 #endif

480 

482         /*

483          * There is no danger if isc_app_shutdown() is called before we wait

484          * for signals.  Signals are blocked, so any such signal will simply

485          * be made pending and we will get it when we call sigwait().

486          */

487 

490                 /*

491                  * Wait for SIGHUP, SIGINT, or SIGTERM.

492                  */

493                 if (sigemptyset(&sset) != 0 ||

494                     sigaddset(&sset, SIGHUP) != 0 ||

495                     sigaddset(&sset, SIGINT) != 0 ||

496                     sigaddset(&sset, SIGTERM) != 0) {

497                         isc__strerror(errno, strbuf, sizeof(strbuf));

499                                          "isc_app_run() sigsetops: %s", strbuf);

501                 }

502 

505                 if (result == 0) {

506                         if (sig == SIGINT ||

507                             sig == SIGTERM)

509                         else if (sig == SIGHUP)

511                 }

512 

513 #else /* Using UnixWare sigwait semantics. */

514                 sig = sigwait(&sset);

515                 if (sig >= 0) {

516                         if (sig == SIGINT ||

517                             sig == SIGTERM)

519                         else if (sig == SIGHUP)

521                 }

522 

523 #endif /* HAVE_UNIXWARE_SIGWAIT */

524 #else  /* Don't have sigwait(). */

525                 /*

526                  * Listen for all signals.

527                  */

528                 if (sigemptyset(&sset) != 0) {

529                         isc__strerror(errno, strbuf, sizeof(strbuf));

531                                          "isc_app_run() sigsetops: %s", strbuf);

533                 }

534                 result = sigsuspend(&sset);

535 #endif /* HAVE_SIGWAIT */

536 

540                 }

541 

543                         exit(1);

544         }

545 

546 #else /* ISC_PLATFORM_USETHREADS */

547 

549 

552                 return (result);

553 

554 #endif /* ISC_PLATFORM_USETHREADS */

555 

557 }

正常關閉時,需要將相關執行緒也中止

558 

563 

564         LOCK(&lock);

565 

567 

569                 want_kill = ISC_FALSE;

570         else

572 

573         UNLOCK(&lock);

574 

575         if (want_kill) {

578 

579                 result = pthread_kill(main_thread, SIGTERM);

580                 if (result != 0) {

583                                          "isc_app_shutdown() pthread_kill: %s",

584                                          strbuf);

586                 }

587 #else

588                 if (kill(getpid(), SIGTERM) < 0) {

589                         isc__strerror(errno, strbuf, sizeof(strbuf));

591                                          "isc_app_shutdown() kill: %s", strbuf);

593                 }

594 #endif

595         }

596 

598 }

599 

五、 事件與任務處理

task = event->ev_sender;

event->ev_sender = NULL;

void

433 

434         /*

435          * Send '*event' to '*taskp' and then detach '*taskp' from its

436          * task.

437          */

438 

439         REQUIRE(taskp != NULL);