目錄 1html
1. 前言 1工具
2. 示例 1ui
3. 工做過程 2url
4. 一個詭異的問題 3spa
7. cron.daily&cron.hourly&cron.weekly&cron.monthly 3unix
本文介紹的是由Paul Vixie開發的運行在SuSE Linux上的Cron。能夠經過「man cron」進行確認。blog
# 示例用來配合本文的說明
*/1 * * * * echo hello >> /tmp/hello.txt
Cron每分鐘作一次檢查,看看哪一個命令可執行。
從上圖能夠看到,有4次fork,這4次fork分別是:
1) 第一個fork,讓Cron本身成爲Daemon進程,即成爲守護進程;
2) 第二個fork,當Cron檢查到有命令須要執行時被建立,但注意它並不執行命令,執行命令由它的子進程來作;
3) 第三個fork,有些版本調用的是vfork,但有些版本倒是fork,它是負責執行Cron命令的進程,即會調用execle()的進程;
4) 第四個fork不是必須的,只有爲Cron命令配置了標準輸入纔會用:
*/1 * * * * /tmp/X/x%1234567890
像上面有個百分符「%」,後面跟一串,則會有第四個fork,它的做用是將「%」後面的內容做爲標準輸入傳遞給第三個fork出來的進程。
注意fork出來的進程沒有忽略(ignore)管道信號(SIGPIPE),因此若是遇到SIGPIPE,則會致使進程無聲無息的退出,好比標準輸主輸出重定向管道的讀端被關閉了,寫時就會觸發SIGPIPE。
實踐中,可能會遇到child_process()在作上述所說的第三個fork前因SIGPIPE信號退出,致使難以理解的問題。其中一個現象是:Cron命令被執行了若干次,但以後不再執行了,緣由在於第二個fork出來的進程因SIGPIPE退出了,致使沒有進行第三個fork,所以Cron命令沒有被調用(老是由execle()調用)。
你有可能遇到這樣的狀況,假設在cron中有以下一條配置:
*/1 * * * * echo hello >> /tmp/hello.txt
觀察到它正常運行幾回後,就再也不運行了,或者一次也不能,但確認無其它問題,所以十分詭異。
這個問題的緣由,有多是由於有共享庫Hook了cron,共享庫代碼觸發了SIGPIPE,致使了第二個fork出的進程退出,沒來得及執行vfork。
fork出來的子進程,沒有對SIGPIPE進行任何處理,默認行爲是悄悄退出進程。經過修改/etc/ld.so.preload,能夠將共享庫注入到非關聯的進程中,可經過ldd觀察到這種依賴,使用LD_PRELOAD也能夠達到一樣的效果。
cron是一個在後臺運行的守護進程,而crontab是一個設置cron的工具。cron調度的是/etc/crontab文件。
crontab使用的兩個文件,cron不會用到它們。
cron.daily、cron.hourly、cron.weekly和cron.monthly這四個目錄均位於/etc下,但cron和crontab兩個並不處理。它們是由配置在/etc/crontab中的run-crons處理,run-crons是位於目錄/usr/lib/cron下的一個Shell腳本文件:
# cat /etc/crontab
SHELL=/bin/sh
PATH=/usr/bin:/usr/sbin:/sbin:/bin:/usr/lib/news/bin
MAILTO=root
#
# check scripts in cron.hourly, cron.daily, cron.weekly, and cron.monthly
#
-*/15 * * * * root test -x /usr/lib/cron/run-crons && /usr/lib/cron/run-crons >/dev/null 2>&1
使用crontab編輯後,cron卡住不動(不是指進程卡住了,而是指命令沒有被調用),緣由多是由於「tcb table full」,最簡單的辦法是重啓cron。
建議避免寫下面這樣的嵌套命令語句,它有可能致使cron不能正常工做:
*/1 * * * * echo "`date +%H:%M:%S` hello" >> /tmp/hello.txt
「echo」中嵌套了「date」,能夠改爲腳本調用,或者不嵌套命令,如:
*/1 * * * * echo "hello" >> /tmp/hello.txt
一個現象是有一個cron子進程(以下述的14786)不退出了:
# ps -ef|grep cron
root 10325 1 0 15:08 ? 00:00:00 /usr/sbin/cron
root 14786 10325 0 15:13 ? 00:00:00 /usr/sbin/cron
gdb看到的調用棧爲:
#0 0xffffe410 in __kernel_vsyscall ()
#1 0xb7e88a63 in __read_nocancel () from /lib/libc.so.6
#2 0xb7e38e38 in _IO_file_read_internal () from /lib/libc.so.6
#3 0xb7e3a0bb in _IO_new_file_underflow () from /lib/libc.so.6
#4 0xb7e3a7fb in _IO_default_uflow_internal () from /lib/libc.so.6
#5 0xb7e3bb2d in __uflow () from /lib/libc.so.6
#6 0xb7e35b7b in getc () from /lib/libc.so.6
#7 0x80005d73 in ?? () from /usr/sbin/cron
strace看到以下:
# strace -f -p 14786
Process 14786 attached
read(7,
藉助lsof能夠看到:
cron 14786 root 7r FIFO 0,6 117960708 pipe
爲一個管道,read()掛住的緣由多是由於管道另外一端所在進程調用_exit()退出而不是調用exit()退出。
這個時候只有人工kill這個掛起的cron子進程。
Crontab專題:http://blog.chinaunix.net/uid/20682147/cid-224920-list-1.html