thttpd源碼解析 定時器模塊
- thttpd是非常輕量級的http服務器,可執行文件僅50kB。名稱中的第一個
t
表示tiny, turbo, 或throttling - 與lighttpd、memcached、redis相比非常小巧,僅有不到8k行,而後三者大小分別爲:60k,13k,86k
- 支持HTTP/1.1和CGI;採用IO複用實現,單線程,可移植;實現了基於URL的文件流量限制功能
- 特別適用於大量靜態數據訪問的場景,如圖片存儲
- 2004年已經停止維護,有一個關於X-Forwarded-For HTTP header的bug。後來出現stthhpd基於此項目
- 性能比較參考對比
- 本文針對timer模塊進行分析
timer模塊
- 包括timer.h,timer.c兩個文件
- 使用全局開放式散列表,默認大小67,每個hash節點上的值按照時間順序排列
- ClientData定義如下:
typedef union { void* p; int i; long l; } ClientData;
- TimerProc類型聲明如下:
void TimerProc( ClientData client_data, struct timeval* nowP )
。函數將在定時器超時時調用 - Timer結構定義如下:
typedef struct TimerStruct { TimerProc* timer_proc; ClientData client_data; long msecs; int periodic; struct timeval time; struct TimerStruct* prev; struct TimerStruct* next; int hash; } Timer;
void tmr_init( void )
- 初始化定時器包,即定時器hash表
Timer* tmr_create( struct timeval* nowP, TimerProc* timer_proc, ClientData client_data, long msecs, int periodic )
- 創建一個定時器,指定是一次性/週期性,加入散列表
- 定時器的時間設置爲nowP的時刻加上msecs毫秒之後,若nowP爲0,設置爲當前時刻加上msecs毫秒
timeval* tmr_timeout( struct timeval* nowP )
- 返回到下次觸發的時間間隔
- 調用tmr_mstimeout得到
tmr_mstimeout( struct timeval* nowP )
- 返回到下次觸發時間間隔的毫秒數,即從nowP開始,經過多少毫秒hash表中會有一個定時器觸發
- 因爲hash表中的每個鏈表都是有序的,遍歷一次hash表即可
void tmr_run( struct timeval* nowP )
- 遍歷hash表,如果定時器沒有超時,調用timer_proc
- 如果定時器是週期性的,則調用後時間後延msecs,如果是非週期性的,則調用tmr_cancel去除
void tmr_reset( struct timeval* nowP, Timer* timer )
- 重新開始運行定時器,時鐘設置爲當前時間nowP加上定時時長
void tmr_cancel( Timer* timer )
- 釋放定時器,由於tmr_run中對所有非週期性定時器都已經調用tmr_cancel,用戶無需再自己對非週期定時器調用
- 將timers加入free_timers鏈表,節省free和malloc的開銷,相當於一個緩衝池
void tmr_cleanup( void )
- 清空定時器包,釋放所有無用的內存:free_timers鏈表
void tmr_destroy( void )
- 調用tmr_cancel釋放所有定時器,爲退出做準備,
void tmr_logstats( long secs )
- 生成調試log信息,記錄當前已分配、使用中、free的定時器個數
- 操作hash表的靜態函數
- hash:由
(time.tv_sec ^ time.tv_usec) % 67
得到hash值 - l_add:插入一個定時器
- l_remove:移除一個定時器
- re_sort:定時器結構體含有之前的hash值,如果定時器的值改變,移除後重新計算hash,插入到正確的位置
- hash:由
timer模塊的使用
- 在main函數中使用類timer模塊
- 調用tmr_init初始化
- 創建週期爲OCCASIONAL_TIME的週期定時器,回調函數爲occasional
- 創建週期爲5s的週期定時器,回調函數爲idle
- 創建週期爲THROTTLE_TIME的週期定時器,回調update_throttles
- 創建週期爲STATS_TIME的週期定時器,回調show_stats
- 在主要事件處理循環中:
- 如果沒有socket發生事件,調用一次tmr_run,continue
- 如果有新連接,continue,以保證新連接優先得到處理
- 如果有事件發生,則處理事件
- 運行一次tmr_run
- occasional
- 調用mmc_cleanup
- 調用tmr_cleanup,清除無用的定時器內存池
- 設置watchdog_flag = 1,使watchdog知道程序仍在運行
- idle
- update_throttles 更新流量控制
- show_stats
- 調用函數logstats,記錄信息