Cron運行原理

目錄

目錄 1html

1. 前言 1工具

2. 示例 1ui

3. 工做過程 2url

4. 一個詭異的問題 3spa

5. cron&crontab 3.net

6. cron.allow&cron.deny 33d

7. cron.daily&cron.hourly&cron.weekly&cron.monthly 3unix

8. crontab編輯後cron異常 4htm

 

1. 前言

本文介紹的是由Paul Vixie開發的運行在SuSE Linux上的Cron。能夠經過「man cron」進行確認。blog

2. 示例

示例用來配合本文的說明

*/1 * * * * echo hello >> /tmp/hello.txt

3. 工做過程

 

Cron每分鐘作一次檢查,看看哪一個命令可執行。

從上圖能夠看到,有4fork,這4fork分別是:

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()調用)。

 

 

4. 一個詭異的問題

你有可能遇到這樣的狀況,假設在cron中有以下一條配置:

*/1 * * * * echo hello >> /tmp/hello.txt

 

觀察到它正常運行幾回後,就再也不運行了,或者一次也不能,但確認無其它問題,所以十分詭異。

 

這個問題的緣由,有多是由於有共享庫Hookcron,共享庫代碼觸發了SIGPIPE,致使了第二個fork出的進程退出,沒來得及執行vfork

 

fork出來的子進程,沒有對SIGPIPE進行任何處理,默認行爲是悄悄退出進程。經過修改/etc/ld.so.preload,能夠將共享庫注入到非關聯的進程中,可經過ldd觀察到這種依賴,使用LD_PRELOAD也能夠達到一樣的效果。

5. cron&crontab

cron是一個在後臺運行的守護進程,而crontab是一個設置cron的工具。cron調度的是/etc/crontab文件。

6. cron.allow&cron.deny

crontab使用的兩個文件,cron不會用到它們。

7. cron.daily&cron.hourly&cron.weekly&cron.monthly

cron.dailycron.hourlycron.weeklycron.monthly這四個目錄均位於/etc下,但croncrontab兩個並不處理。它們是由配置在/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

8. crontab編輯後cron異常

使用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

相關文章
相關標籤/搜索