forked from bruceg/bcron
-
Notifications
You must be signed in to change notification settings - Fork 0
/
bcron-sched.c
151 lines (130 loc) · 2.97 KB
/
bcron-sched.c
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
#include <sysdeps.h>
#include <systime.h>
#include <errno.h>
#include <signal.h>
#include <unistd.h>
#include <iobuf/iobuf.h>
#include <misc/misc.h>
#include <msg/msg.h>
#include <msg/wrap.h>
#include <str/iter.h>
#include <str/str.h>
#include <unix/nonblock.h>
#include <unix/sig.h>
#include <unix/trigger.h>
#include "bcron.h"
const char program[] = "bcron-sched";
const int msg_show_pid = 0;
int msg_debug_bits = 0;
static iopoll_fd ios[3];
/* Fill in tm and calculate the top of the next minute. */
static time_t next_minute(time_t t, struct tm* tm)
{
t += 60;
*tm = *(localtime(&t));
t -= tm->tm_sec;
tm->tm_sec = 0;
return t;
}
static time_t nexttime;
static struct tm nexttm;
static struct timeval reftime;
static void calctimes(void)
{
struct ghashiter i;
struct job* job;
nexttime = next_minute(reftime.tv_sec, &nexttm);
/* Make sure all jobs have a time scheduled */
ghashiter_loop(&i, &crontabs) {
for (job = ((struct crontabs_entry*)i.entry)->data.jobs;
job != 0; job = job->next) {
if (job->nexttime == 0)
job->nexttime = timespec_next(&job->times, nexttime, &nexttm);
}
}
}
static void loadall(void)
{
gettimeofday(&reftime, 0);
crontabs_load();
calctimes();
}
static long calcinterval(void)
{
long interval;
gettimeofday(&reftime, 0);
interval = (nexttime - reftime.tv_sec) * 1000 - reftime.tv_usec / 1000;
debug2(DEBUG_SCHED, "Interval: ", utoa(interval));
/* Add a little "fudge" to the interval, as the select frequently
returns a jiffy before the interval would actually expire. */
return interval + 100;
}
static void run_jobs(void)
{
struct ghashiter i;
gettimeofday(&reftime, 0);
if (reftime.tv_sec < nexttime) {
debug1(DEBUG_SCHED, "Not enough time has elapsed, sleeping again");
return;
}
debug2(DEBUG_SCHED, "Running jobs at: ", fmttime(reftime.tv_sec));
ghashiter_loop(&i, &crontabs) {
struct job* job;
for (job = ((struct crontabs_entry*)i.entry)->data.jobs;
job != 0; job = job->next)
if (job->nexttime <= reftime.tv_sec) {
job_exec(job);
job->nexttime = 0;
}
}
loadall();
}
#ifndef IGNORE_EXEC
static void handle_stdin(void)
{
char buf[256];
read(0, buf, sizeof buf);
}
#endif
static void catch_usr1(int sig)
{
crontabs_dump();
(void)sig;
}
int main(void)
{
msg_debug_init();
if (chdir_bcron() != 0)
die1sys(111, "Could not change directory");
nonblock_on(0);
timespec_next_init();
trigger_set(ios, TRIGGER);
sig_catch(SIGUSR1, catch_usr1);
#ifndef IGNORE_EXEC
ios[2].fd = 0;
ios[2].events = IOPOLL_READ;
#endif
msg1("Starting");
crontabs_init(&crontabs);
loadall();
for (;;) {
switch (iopoll(ios, 3, calcinterval())) {
case -1:
if (errno == EAGAIN || errno == EINTR)
continue;
die1sys(111, "poll failed");
case 0:
run_jobs();
continue;
default:
if (trigger_pulled(ios)) {
trigger_set(ios, TRIGGER);
loadall();
}
#ifndef IGNORE_EXEC
if (ios[2].revents)
handle_stdin();
#endif
}
}
}