目录 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