Bind-9.6.0-P1原始碼分析之一:整體架構(初稿)
轉載至:不知轉載源
一、 說明
這是bind解析程式的入口
事件bind程式也事件驅動型,以任務作為主要的執行。
當一個解析請求到來時,就會通過事件的產生來觸發任務dispatch處理。這樣的處理有相應
if (event->ev_action != NULL) {
862 (event->ev_action)(
這裡 action就是執行函式
本文主要關注整體的執行結構,主要參考檔案是main.c
二、 啟動入口
870 int
871 main(int argc, char *argv[]) { 命令列引數傳入
以上為設定錯誤訊息
898初始化系統日誌,許可權等
900初始化工作
904 命令列引數分析,如-g將日誌輸出到front-end
注意以
用到了鎖機制
記憶體生成採用標準的系統呼叫 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
924 //setup是重要的一部分,見分析三
接下來就是解析主體程式了,是通過迴圈來做的,直到錯誤或者接收到退出訊號。遞
/*
928 * Start things running and then wait for a shutdown request
929 * or reload.
930 */
931 do {
934 if (result == ISC_R_RELOAD) { //通過我們會做這種操作,當配置了一個新的zone檔案時
938 "isc_app_run(): %s",
940 /*
941 * Force exit.
942 */
944 }
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 */
966 isc_mem_stats(ns_g_mctx, stdout);
968 }
970 if (ns_g_memstatistics && memstats != NULL) {
977 }
978 }
990 return (0);
991 }
三、 初始設定setup
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",
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,
682 ISC_LOG_NOTICE, "built with %s", ns_g_configargs);
接下來是資源限制部分,可用#ulimit –a來理解
/*
729 * Record the server's startup time.
730 */
733 ns_main_earlyfatal("isc_time_now() failed: %s",
生成管理器,如任務、超時、entropy、hash,socket等管理器
738 ns_main_earlyfatal("create_managers() failed: %s",
743 /*
744 * Add calls to register sdb drivers here.
745 */
746 /* xxdb_init(); */
748 #ifdef DLZ
749 /*
750 * Registyer any DLZ drivers.
751 */
754 ns_main_earlyfatal("dlz_drivers_init() failed: %s",
756 #endif
生成服務,重要部分,見分析六
758 ns_server_create(ns_g_mctx, &ns_g_server);
759 }
四、 執行主體程式
433 isc_event_t *event, *next_event;
436 sigset_t sset;
439 int sig;
440 #endif
441 #endif /* ISC_PLATFORM_USETHREADS */
443 #ifdef HAVE_LINUXTHREADS 如果啟用了多執行緒編譯,目前我們編譯的是單執行緒,可用ps –em|grep named檢視執行緒數
445 #endif
446 加鎖,事件佇列是關鍵區,race condition
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);
461 event->ev_sender = NULL;
事件任務機制,見分析五
463 }
465 }
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
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 */
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 }
506 if (sig == SIGINT ||
507 sig == SIGTERM)
509 else if (sig == SIGHUP)
511 }
513 #else /* Using UnixWare sigwait semantics. */
515 if (sig >= 0) {
516 if (sig == SIGINT ||
517 sig == SIGTERM)
519 else if (sig == SIGHUP)
521 }
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 */
540 }
543 exit(1);
544 }
546 #else /* ISC_PLATFORM_USETHREADS */
554 #endif /* ISC_PLATFORM_USETHREADS */
557 }
正常關閉時,需要將相關執行緒也中止
570 else
575 if (want_kill) {
579 result = pthread_kill(main_thread, SIGTERM);
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 }
598 }
五、 事件與任務處理
task = event->ev_sender;
event->ev_sender = NULL;
void
434 /*
435 * Send '*event' to '*taskp' and then detach '*taskp' from its
436 * task.
437 */