Add per-second scheduling into the cron(8). Right now it's

only available via the new @every_second shortcut. ENOTIME to
implement crontab(5) format extensions to allow more flexible
scheduling.

In order to address some concerns expressed by Terry Lambert
while discussing the topic few years ago, about per-second cron
possibly causing some bad effects on /etc/crontab by stat()ing
it every second instead of every minute now (i.e. atime update),
only check that database needs to be reloaded on every 60-th
loop run. This should be close enough to the current behaviour.

Add "@every_minute" shortcut while I am here.

MFC after:	1 month
This commit is contained in:
Maxim Sobolev 2012-10-15 08:21:49 +00:00
parent e76163a539
commit 2543786a37
Notes: svn2git 2020-12-20 02:59:44 +00:00
svn path=/head/; revision=241576
4 changed files with 45 additions and 9 deletions

View File

@ -98,6 +98,7 @@ main(argc, argv)
char *argv[];
{
cron_db database;
int runnum;
ProgramName = argv[0];
@ -149,21 +150,24 @@ main(argc, argv)
load_database(&database);
run_reboot_jobs(&database);
cron_sync();
runnum = 0;
while (TRUE) {
# if DEBUGGING
/* if (!(DebugFlags & DTEST)) */
# endif /*DEBUGGING*/
cron_sleep(&database);
load_database(&database);
if (runnum % 60 == 0)
load_database(&database);
/* do this iteration
*/
cron_tick(&database);
/* sleep 1 minute
/* sleep 1 second
*/
TargetTime += 60;
TargetTime += 1;
runnum += 1;
}
}
@ -194,22 +198,23 @@ cron_tick(db)
static time_t diff = 0, /* time difference in seconds from the last offset change */
difflimit = 0; /* end point for the time zone correction */
struct tm otztm; /* time in the old time zone */
int otzminute, otzhour, otzdom, otzmonth, otzdow;
int otzsecond, otzminute, otzhour, otzdom, otzmonth, otzdow;
register struct tm *tm = localtime(&TargetTime);
register int minute, hour, dom, month, dow;
register int second, minute, hour, dom, month, dow;
register user *u;
register entry *e;
/* make 0-based values out of these so we can use them as indicies
*/
second = tm->tm_sec -FIRST_SECOND;
minute = tm->tm_min -FIRST_MINUTE;
hour = tm->tm_hour -FIRST_HOUR;
dom = tm->tm_mday -FIRST_DOM;
month = tm->tm_mon +1 /* 0..11 -> 1..12 */ -FIRST_MONTH;
dow = tm->tm_wday -FIRST_DOW;
Debug(DSCH, ("[%d] tick(%d,%d,%d,%d,%d)\n",
getpid(), minute, hour, dom, month, dow))
Debug(DSCH, ("[%d] tick(%d,%d,%d,%d,%d,%d)\n",
getpid(), second, minute, hour, dom, month, dow))
if (dst_enabled && last_time != 0
&& TargetTime > last_time /* exclude stepping back */
@ -262,6 +267,7 @@ cron_tick(db)
/* make 0-based values out of these so we can use them as indicies
*/
otzsecond = otztm.tm_sec -FIRST_SECOND;
otzminute = otztm.tm_min -FIRST_MINUTE;
otzhour = otztm.tm_hour -FIRST_HOUR;
otzdom = otztm.tm_mday -FIRST_DOM;
@ -283,7 +289,8 @@ cron_tick(db)
e->uid, e->gid, e->cmd))
if ( diff != 0 && (e->flags & (RUN_AT|NOT_UNTIL)) ) {
if (bit_test(e->minute, otzminute)
if (bit_test(e->second, otzsecond)
&& bit_test(e->minute, otzminute)
&& bit_test(e->hour, otzhour)
&& bit_test(e->month, otzmonth)
&& ( ((e->flags & DOM_STAR) || (e->flags & DOW_STAR))
@ -302,7 +309,8 @@ cron_tick(db)
continue;
}
if (bit_test(e->minute, minute)
if (bit_test(e->second, second)
&& bit_test(e->minute, minute)
&& bit_test(e->hour, hour)
&& bit_test(e->month, month)
&& ( ((e->flags & DOM_STAR) || (e->flags & DOW_STAR))

View File

@ -124,6 +124,10 @@
LineNumber = ln; \
}
#define FIRST_SECOND 0
#define LAST_SECOND 59
#define SECOND_COUNT (LAST_SECOND - FIRST_SECOND + 1)
#define FIRST_MINUTE 0
#define LAST_MINUTE 59
#define MINUTE_COUNT (LAST_MINUTE - FIRST_MINUTE + 1)
@ -165,6 +169,7 @@ typedef struct _entry {
#endif
char **envp;
char *cmd;
bitstr_t bit_decl(second, SECOND_COUNT);
bitstr_t bit_decl(minute, MINUTE_COUNT);
bitstr_t bit_decl(hour, HOUR_COUNT);
bitstr_t bit_decl(dom, DOM_COUNT);

View File

@ -232,6 +232,8 @@ string meaning
@daily Run once a day, "0 0 * * *".
@midnight (same as @daily)
@hourly Run once an hour, "0 * * * *".
@every_minute Run once a minute, "*/1 * * * *".
@every_second Run once a second.
.Ed
.Sh EXAMPLE CRON FILE
.Bd -literal

View File

@ -151,6 +151,7 @@ load_entry(file, error_func, pw, envp)
e->flags |= WHEN_REBOOT;
} else if (!strcmp("yearly", cmd) || !strcmp("annually", cmd)){
Debug(DPARS, ("load_entry()...yearly shortcut\n"))
bit_set(e->second, 0);
bit_set(e->minute, 0);
bit_set(e->hour, 0);
bit_set(e->dom, 0);
@ -159,6 +160,7 @@ load_entry(file, error_func, pw, envp)
e->flags |= DOW_STAR;
} else if (!strcmp("monthly", cmd)) {
Debug(DPARS, ("load_entry()...monthly shortcut\n"))
bit_set(e->second, 0);
bit_set(e->minute, 0);
bit_set(e->hour, 0);
bit_set(e->dom, 0);
@ -167,6 +169,7 @@ load_entry(file, error_func, pw, envp)
e->flags |= DOW_STAR;
} else if (!strcmp("weekly", cmd)) {
Debug(DPARS, ("load_entry()...weekly shortcut\n"))
bit_set(e->second, 0);
bit_set(e->minute, 0);
bit_set(e->hour, 0);
bit_nset(e->dom, 0, (LAST_DOM-FIRST_DOM+1));
@ -175,6 +178,7 @@ load_entry(file, error_func, pw, envp)
bit_set(e->dow, 0);
} else if (!strcmp("daily", cmd) || !strcmp("midnight", cmd)) {
Debug(DPARS, ("load_entry()...daily shortcut\n"))
bit_set(e->second, 0);
bit_set(e->minute, 0);
bit_set(e->hour, 0);
bit_nset(e->dom, 0, (LAST_DOM-FIRST_DOM+1));
@ -182,11 +186,28 @@ load_entry(file, error_func, pw, envp)
bit_nset(e->dow, 0, (LAST_DOW-FIRST_DOW+1));
} else if (!strcmp("hourly", cmd)) {
Debug(DPARS, ("load_entry()...hourly shortcut\n"))
bit_set(e->second, 0);
bit_set(e->minute, 0);
bit_nset(e->hour, 0, (LAST_HOUR-FIRST_HOUR+1));
bit_nset(e->dom, 0, (LAST_DOM-FIRST_DOM+1));
bit_nset(e->month, 0, (LAST_MONTH-FIRST_MONTH+1));
bit_nset(e->dow, 0, (LAST_DOW-FIRST_DOW+1));
} else if (!strcmp("every_minute", cmd)) {
Debug(DPARS, ("load_entry()...every_minute shortcut\n"))
bit_set(e->second, 0);
bit_nset(e->minute, 0, (LAST_MINUTE-FIRST_MINUTE+1));
bit_nset(e->hour, 0, (LAST_HOUR-FIRST_HOUR+1));
bit_nset(e->dom, 0, (LAST_DOM-FIRST_DOM+1));
bit_nset(e->month, 0, (LAST_MONTH-FIRST_MONTH+1));
bit_nset(e->dow, 0, (LAST_DOW-FIRST_DOW+1));
} else if (!strcmp("every_second", cmd)) {
Debug(DPARS, ("load_entry()...every_second shortcut\n"))
bit_nset(e->second, 0, (LAST_SECOND-FIRST_SECOND+1));
bit_nset(e->minute, 0, (LAST_MINUTE-FIRST_MINUTE+1));
bit_nset(e->hour, 0, (LAST_HOUR-FIRST_HOUR+1));
bit_nset(e->dom, 0, (LAST_DOM-FIRST_DOM+1));
bit_nset(e->month, 0, (LAST_MONTH-FIRST_MONTH+1));
bit_nset(e->dow, 0, (LAST_DOW-FIRST_DOW+1));
} else {
ecode = e_timespec;
goto eof;