1. 程式人生 > >squid的main函式原始碼分析

squid的main函式原始碼分析

        要分析一款開源的軟體除了要弄清楚一些基本的使用和配置之外,其次最重要的就是對原始碼進行分析。對原始碼進行分析首先應從其main函式分析入手,瞭解他在啟動時的涉及的哪方面的功能,並勾勒出他的執行流程圖,現在squid已經支援windows平臺了,並且支援以服務的方式啟動。其程式碼如下:

#if USE_WIN32_SERVICE
/* When USE_WIN32_SERVICE is defined, the main function is placed in win32.c */
void WINAPI
SquidWinSvcMain(int argc, char **argv)
{
    SquidMain(argc, argv);
}

int
SquidMain(int argc, char **argv)
#else
int
main(int argc, char **argv)
#endif
{
    int errcount = 0;
    int loop_delay;
#ifdef _SQUID_WIN32_
    int WIN32_init_err;
#endif

#if HAVE_SBRK
    /*
    * HAVE_SBRK	- 這個巨集的產生我說明一下,這個是用configure產生的,在autoconf.h中能看到,這個是configure做系統
    * 函式fun功能性檢查的時候,如果該作業系統支援其系統呼叫,則在autoconf.h中定義巨集HAVE_FUN,FUN是其函式名字的大寫
    * sbrk	- 是從堆中分配空間,本質是移動一個位置,向後移就是分配空間,向前移就是釋放空間,返回以頁為單位
    * 的虛擬記憶體使用情況,squid用它來計算整個程序的記憶體使用情況。
    */
    sbrk_start = sbrk(0);
#endif

    debug_log = stderr;

#ifdef _SQUID_WIN32_
    if ((WIN32_init_err = WIN32_Subsystem_Init(&argc, &argv)))
	return WIN32_init_err;
#endif

    /* call mallopt() before anything else */
#if HAVE_MALLOPT
#ifdef M_GRAIN
    /* Round up all sizes to a multiple of this */
    mallopt(M_GRAIN, 16);
#endif
#ifdef M_MXFAST
    /* biggest size that is considered a small block */
    mallopt(M_MXFAST, 256);
#endif
#ifdef M_NBLKS
    /* allocate this many small blocks at once */
    mallopt(M_NLBLKS, 32);
#endif
#endif /* HAVE_MALLOPT */

    /* 初始化本地地址local_addr,預設地址any_addr和廣播地址no_addr */
    memset(&local_addr, '\0', sizeof(struct in_addr));
    safe_inet_addr(localhost, &local_addr);
    memset(&any_addr, '\0', sizeof(struct in_addr));
    safe_inet_addr("0.0.0.0", &any_addr);
    memset(&no_addr, '\0', sizeof(struct in_addr));
    safe_inet_addr("255.255.255.255", &no_addr);

    /* 用當前時間生成隨機種子 */
    squid_srandom(time(NULL));

    /* 初始化當前時間 */
    getCurrentTime();
    squid_start = current_time;
    failure_notify = fatal_dump;	/* 設定失敗或者出現重大錯誤時候退出的回撥函式指標 */

#if defined(USE_WIN32_SERVICE) && defined(_SQUID_WIN32_)
    WIN32_svcstatusupdate(SERVICE_START_PENDING, 10000);
#endif

    /* 解析命令列引數,如./squid -D -N -d3 之類的 */
    mainParseOptions(argc, argv);

#if HAVE_SYSLOG && defined(LOG_LOCAL4)
    /* 開啟系統日誌,將日誌寫入系統日誌吧 */
    openlog(appname, LOG_PID | LOG_NDELAY | LOG_CONS, syslog_facility);
#endif

#if defined(USE_WIN32_SERVICE) && defined(_SQUID_WIN32_)
    if (opt_install_service) {
	WIN32_InstallService();
	return 0;
    }
    if (opt_remove_service) {
	WIN32_RemoveService();
	return 0;
    }
    if (opt_command_line) {
	WIN32_SetServiceCommandLine();
	return 0;
    }
#endif

    /* parse configuration file
     * note: in "normal" case this used to be called from mainInitialize() */
    {
	/* 配置檔名稱初始化,這個可也通過命令列的方式指定,預設是squid.conf */ 
	int parse_err;
	if (!ConfigFile)
	    ConfigFile = xstrdup(DefaultConfigFile);
	assert(!configured_once);
#if USE_LEAKFINDER
	/* 
	* 記憶體洩漏檢測功能初始化,通過--enable-leakfinder開啟。建立一個雜湊表htable,快取動態記憶體分配
	* 情況,cachemgrRegister註冊獲取記憶體洩漏跟蹤統計資料的action 。
	* 但是奇怪的事,我就沒看到哪些地方在呼叫leakAdd leakTouch leakFree之類的介面。
	*/ 
	leakInit();
#endif
	/* 
	* squid提供的記憶體池功能,這裡主要是對預定義的物件記憶體分配器初始化,以後這些物件就用這些定義好了的記憶體分配器來
	* 分配記憶體了!cachemgrRegister註冊獲取記憶體使用跟蹤統計資料的action 。squid實現的記憶體池功能比apache簡單多了!
	*/
	memInit();

	/* 
	* squid提供的專用於回撥函式引數物件記憶體分配器初始化,用這個種分配器分配的記憶體儲存了一些其他的資訊用於識別和驗證。
	* cachemgrRegister註冊獲取回撥引數物件跟蹤統計資料的action 。
	*/
	cbdataInit();

	/* 
	* Squid的事件機制的作用是,提供一種觸發機制,可以定時地執行某些操作. Squid任何一個功能模組中的程式碼可以靈活地指定
	* “在x秒鐘之後,我要做某操作”,而到了x秒鐘之後,該操作就可以自動地執行。
	* 這裡主要是對event的物件記憶體分配器初始化, cachemgrRegister註冊獲取event物件跟蹤統計資料的action 。
	*/
	eventInit();		/* eventInit() is required for config parsing */

	/*
	* storeReplSetup()和storeFsSetup(),替換策略模組和儲存策略模組選擇的初始化,這些模組的選擇是通過
	* ./configure --enable-storeio=afus,diskd,ufs和 ./configure --enable-removal-policies=heap,lru來確定的!
	* 替換和儲存模組都提供了一個相容層,這些相容層只是一個管理功能介面的函式指標物件,初始化就是用使用者
	* configure配置的介面來初始化函式指標管理物件。
	*/
	storeFsInit();		/* required for config parsing */

	/*
	* authSchemeSetup(),squid配置的驗證機制初始化,這個是squid提供給使用者的代理認證,可以通過
	* ./configure --enable-auth=basic,digest,ntlm來配置,預設支援basic認證方式。並且需要配置一種
	* 對應的外部認證程式,通過--enable-basic-auth-helpers=ncsa完成,這裡只是配置了認證機制basic
	* 使用ncsa外部程式來完成認證,這些外部程式都是通過pipe方式來進行通訊完成認證的!
	*/
	authenticateSchemeInit();	/* required for config parsing */

	/*
	* 這個沒什麼的,看起來就像是解析配置檔案,預設的配置檔案是squid.conf,cachemgrRegister註冊獲取配置資料的action 
	* 處理過程先設定部分預設值,然後解析配置檔案覆蓋或者初始化一些配置值,然後看哪些沒值的就設定預設值,最後配置資訊
	* 合法化檢查,如果配置資訊不合理就退出吧!!
	*/
	parse_err = parseConfigFile(ConfigFile);

	if (opt_parse_cfg_only)
	    return parse_err;
    }
    setUmask(Config.umask);

    /*
    * 重複啟動執行監測,如果不是像squid傳送程序訊號的話,就提示不能重複啟動執行的錯誤。squid程序啟動的時候會向squid.pid
    * 寫入當前執行程序的pid,checkRunningPid()就是檢查的這個檔案來確認squid是不是已經啟動了!當squid退出的時候會刪除
    * squid.pid的這個檔案。
    */
    if (-1 == opt_send_signal)
	if (checkRunningPid())
	    exit(1);

    /* Make sure the OS allows core dumps if enabled in squid.conf */
    /*
    * 這個只是設定os系統引數,允許squid在crash的時候生成coredump檔案。
    */
    enableCoredumps();

/*
* 這個看樣子是測試access方面巨集,如果定義了該巨集,會#include "test_access.c"這個檔案,
* 不過哥哥沒找到這個檔案。我想其他版本有吧,先跳過這個不管算了!
*/
#if TEST_ACCESS
    comm_init();
    comm_select_init();
    mainInitialize();
    test_access();
    return 0;
#endif
    /*
    * squid程序除了可以作為啟動程序外,還可以通過一些命令引數作為管理程序,來完成一些基本的管理工作,
    * 如opt_send_signal選項,如果該選項設定了就可以向正在執行的squid程序傳送訊號,我看了就傳送了kill訊號!
    * 如opt_create_swap_dirs選項,如果該選項設定了就可以建立cache目錄,根據cache_dir配置指令來完成建立。
    */
    /* send signal to running copy and exit */
    if (opt_send_signal != -1) {
	/* chroot if configured to run inside chroot */
	if (Config.chroot_dir) {
	    if (chroot(Config.chroot_dir))
		fatal("failed to chroot");
	    no_suid();
	} else {
	    leave_suid();
	}
	sendSignal();
	/* NOTREACHED */
    }
    if (opt_create_swap_dirs) {
	/* chroot if configured to run inside chroot */
	if (Config.chroot_dir && chroot(Config.chroot_dir)) {
	    fatal("failed to chroot");
	}
	setEffectiveUser();
	debug(0, 0) ("Creating Swap Directories\n");
	storeCreateSwapDirectories();
	return 0;
    }

    /*
    * 這裡squid以後臺服務的方式來啟動執行。
    */
    if (!opt_no_daemon)
	watch_child(argv);
    setMaxFD();

    /* init comm module */
    /*
    * 現在squid網路模組支援devpoll,poll,epoll,kqueue,select和select_win32模式。
    * 網路初始化,這裡包括client-side和server-side套接字fd,pipe,以及檔案fd的管理結構fde,記憶體分配器和套接字狀態管理結構初始化。
    */
    comm_init();
    comm_select_init();

    if (opt_no_daemon) {
	/* we have to init fdstat here. */
	if (!opt_stdin_overrides_http_port)
	    fd_open(0, FD_LOG, "stdin");
	fd_open(1, FD_LOG, "stdout");
	fd_open(2, FD_LOG, "stderr");
    }
#if defined(USE_WIN32_SERVICE) && defined(_SQUID_WIN32_)
    WIN32_svcstatusupdate(SERVICE_START_PENDING, 10000);
#endif
    /*
    * squid主要資訊初始化,這個會將在mainInitialize()功能做詳細的分析。
    */
    mainInitialize();

#if defined(USE_WIN32_SERVICE) && defined(_SQUID_WIN32_)
    WIN32_svcstatusupdate(SERVICE_RUNNING, 0);
#endif

    /* main loop */
    /*
    * 這個應該就是squid的心跳系統,這裡除了處理squid管理髮過來的訊號之類外,就只處理event事件和讀寫處理。
    * 這裡應該就只包括套接字和檔案的讀寫吧,整個框架就3點功能:
    *	- 處理squid管理髮過來的訊號,do_reconfigure表示是重新載入配置資訊,這個處理起來還不簡單啊,要關閉所
    * 有埠,所有連線,所有檔案讀寫等,然後切換到root使用者,解析配置檔案,在然後切換回來執行使用者,然後啟動
    * 之前關閉的埠,連線等等資訊,太多了!
    *	- eventRun(),執行event,遍歷event管理列表tasks,如果event->when中滿足當前執行條件,就執行event->func
    * 中的函式功能,執行完後從tasks中刪除之,並釋放資源吧。靈活地指定“在x秒鐘之後,我要做某操作”,這個可以做
    * 任何事情,不錯。。。
    *	- 接下來就是網路套接字和檔案io的讀寫!loop_delay = eventNextTime()這個是取得下一個最快將要執行的event
    * 時間,loop_delay不能超過1000就是1秒,通過這個時間來在一些埠上設定等待超時時間,comm_select(loop_delay)
    * 就是在網路套接字和檔案FD上等待預先設定好了的操作,等成功返回後就用預先設定好了的函式作回撥執行處理得到
    * 的資料。比如listen FD監聽到來的請求,receive FD接收到來的request和response data,預先設定好了資料發出去
    * 去的FD,寫入disk的FD,等等!!!
    */
    for (;;) {
	if (do_reconfigure) {
	    mainReconfigure();
	    do_reconfigure = 0;
	} else if (do_rotate) {
	    mainRotate();
	    do_rotate = 0;
	} else if (do_shutdown) {
	    time_t wait = do_shutdown > 0 ? (int) Config.shutdownLifetime : 0;
	    debug(1, 1) ("Preparing for shutdown after %d requests\n",
		statCounter.client_http.requests);
	    debug(1, 1) ("Waiting %d seconds for active connections to finish\n",
		(int) wait);
	    do_shutdown = 0;
	    shutting_down = 1;
#if defined(USE_WIN32_SERVICE) && defined(_SQUID_WIN32_)
	    WIN32_svcstatusupdate(SERVICE_STOP_PENDING, (wait + 1) * 1000);
#endif
	    serverConnectionsClose();
	    eventAdd("SquidShutdown", SquidShutdown, NULL, (double) (wait + 1), 1);
	}
	eventRun();
	if ((loop_delay = eventNextTime()) < 0)
	    loop_delay = 0;
	if (debug_log_flush() && loop_delay > 1000)
	    loop_delay = 1000;
	switch (comm_select(loop_delay)) {
	case COMM_OK:
	    errcount = 0;	/* reset if successful */
	    break;
	case COMM_ERROR:
	    errcount++;
	    debug(1, 0) ("Select loop Error. Retry %d\n", errcount);
	    if (errcount == 10)
		fatal_dump("Select Loop failed!");
	    break;
	case COMM_TIMEOUT:
	    break;
	case COMM_SHUTDOWN:
	    SquidShutdown(NULL);
	    break;
	default:
	    fatal_dump("MAIN: Internal error -- this should never happen.");
	    break;
	}
    }
    /* NOTREACHED */
    return 0;
}




相關推薦

YOLO v2 損失函式原始碼分析

損失函式的定義是在region_layer.c檔案中,關於region層使用的引數在cfg檔案的最後一個section中定義。 首先來看一看region_layer 都定義了那些屬性值: layer make_region_layer(int batch, int w, int h, int n,

Opencv2.4.9多尺度檢測detectMultiScale函式原始碼分析

一、簡介     在Opencv2.4.9的原始碼中,對modules模組opencv_objdetect子專案中CascadeClasssifier類中的detectMultiScale函式進行了分析,涉及程式碼在cascadedetect.hpp和cascadede

squid的main函式原始碼分析

        要分析一款開源的軟體除了要弄清楚一些基本的使用和配置之外,其次最重要的就是對原始碼進行分析。對原始碼進行分析首先應從其main函式分析入手,瞭解他在啟動時的涉及的哪方面的功能,並勾勒出他的執行流程圖,現在squid已經支援windows平臺了,並且支援以服務

django.contrib.auth之authenticate函式原始碼分析

引言 django提供了一個預設的auth系統用於使用者的登入和授權,並提供了一定的擴充套件性,允許開發者自行定義多個驗證後臺,每個驗證後臺必須實現authenticate函式,並返回None或者User物件。 預設的後臺是django.contrib.au

系統呼叫入口函式原始碼分析system_call——X86_64

在實驗中用到這一塊,就去看原始碼分析整理了一下,全部為個人理解。有錯誤的地方,希望和大牛交流。 首先解釋一下,我實驗的目的是獲得系統呼叫入口函式system_call的起始地址和函式大小。 在linux-3.10.1, x86 64位的系統下,系統呼叫的入口地址儲存在MSR暫存器中,通過rdmsrl(MSR

lwIP(V1.3.0) RAW API函式原始碼分析4----tcp_accept()函式

位於: 位於:lwip-x.x.x/src/core/tcp.c 原型: void tcp_accept(struct tcp_pcb *pcb, err_t (* accept)(void *arg,

x265原始碼分析:main函式及CLIOptions結構體解釋

/** * 返回碼資訊: * 0 – 編碼成功; * 1 – 命令列解釋失敗; * 2 – 編碼器開啟失敗; * 3 – 生成流頭部失敗; * 4 – 編碼出錯; * 5 – 開啟csv檔案失敗. */ int main(int argc, char **argv) {

Vue 原始碼分析——建構函式原型

在執行 npm run dev 的時候 根據script/config.js 檔案中的配置 'web-full-dev': {       entry: resolve('web/entry-runtime-with-compiler.js'),   &n

最新版ffmpeg原始碼分析二:transcode()函式

還是先看一下主函式吧:(省略了很多無關大雅的程式碼) int main(int argc, char **argv) { OptionsContext o = { 0 }; int64_t ti; //與命令列分析有關

Mosquitto-1.5.4原始碼分析,PUBLISH的實現及函式跳轉關係

客戶端向伺服器傳送資料包(packet)時,首先將資料包放到改傳送佇列中,並不真實發送資料,而是傳送資料就緒訊號,等待loop事件迴圈呼叫的函式db__message_write根據網路連線情況來處理髮送請求;該佇列為單鏈表儲存結構,每次有新資料包需要傳送時,將新資料包插入到連結串列尾部;真正傳

Libevent原始碼分析-----與event相關的一些函式和操作

        Libevent提供了一些與event相關的操作函式和操作。本文就重點講一下這方面的原始碼。         在Libevent中,無論是event還是event_base,都是使用指標而不會使用變數。實際上,如果檢視Libevent不同的版本,就可

Libevent原始碼分析-----通用型別和函式

        Libevent定義了一系列的可移植的相容型別和函式。這使得在各個系統上都有一致的效果,Libevent一般都會在相容通用型別和函式的前面加上ev或evutil字首。         在實現上,Libevent都是使用條件編譯+巨集定義的方式。使用這

Libevent原始碼分析-----更多evbuffer操作函式

鎖操作:         在前一篇博文可以看到很多函式在操作前都需要對這個evbuffer進行加鎖。同event_base不同,如果evbuffer支援鎖的話,要顯式地呼叫函式evbuffer_enable_locking。 //buffer.c檔案 int//

Keras 中 list_pictures 函式原始碼分析及改進

1. list_pictures 的原始碼分析及改進 1.1 list_pictures 的原始碼分析   首先來看一下 list_pictures 的原始碼,具體如下 def list_pictures(directory, ext='jpg|jpeg|bmp

Python 原始碼分析函式機制

在 python 中函式也是一個物件 typedef struct { PyObject_HEAD PyObject *func_code; /* 函式編譯之後的 PyCodeObject, the __code__ attribute */ PyOb

ipset原始碼分析之kadt和uadt回撥函式

一定要清楚自己在幹什麼,每行程式碼在幹什麼,這樣寫的程式碼才能做到心中有數。 之前看到ip_set_hash_ip.chash_ip4_uadt和hash_ip4_kadt函式,就一直很好奇這兩個函式是幹什麼呢? 下面我來帶你一步步剖析這兩個函式 一、kadt和uadt回撥函式的註冊

STL原始碼分析之vector(二)—核心函式 push_back及insert_aux

說明: STL原始碼分析系列部落格的使用的是https://www.sgi.com/tech/stl/download.html 裡面的STL v2.03版.不同的STL或許會有所不同。 其它vector內容請參照本系列其它部落格。 主要函式分析

jdk1.8 HashMap原始碼分析(resize函式

final Node<K,V>[] resize() { Node<K,V>[] oldTab = table; int oldCap = (oldTab == null) ? 0 : oldTab.len

Android Wi-Fi原始碼分析之WifiService操作Wi-Fi(一):分析Wifi.c中的wifi_load_driver()函式

Wi-Fi原始碼分析之WifiService操作Wi-Fi(一) 分析Wifi.c中的wifi_load_driver()函式 int wifi_load_driver() { AL

openCV中的findHomography函式分析以及RANSAC演算法的詳解(原始碼分析

本文將openCV中的RANSAC程式碼全部挑選出來,進行分析和講解,以便大家更好的理解RANSAC演算法。程式碼我都試過,可以直接執行。 在計算機視覺和影象處理等很多領域,都需要用到RANSAC演算法。openCV中也有封裝好的RANSAC演算法,以便於人們使用。關於RA