From ff0db1d39896f03ec4afb6a745981e41cd7d241e Mon Sep 17 00:00:00 2001 From: "Nicholas J. Kain" Date: Mon, 19 Feb 2024 00:22:17 -0500 Subject: [PATCH] Don't use C++-style classes. --- crontab.cpp | 4 +- crontab.rl | 4 +- ncron.cpp | 22 +++---- sched.cpp | 173 ++++++++++++++++++++++++++++------------------------ sched.hpp | 49 ++++++--------- 5 files changed, 125 insertions(+), 127 deletions(-) diff --git a/crontab.cpp b/crontab.cpp index 1632df7..f3759be 100644 --- a/crontab.cpp +++ b/crontab.cpp @@ -80,7 +80,7 @@ struct ParseCfgState log_line("job count mismatch"); exit(EXIT_FAILURE); } - new(ce) Job; + job_init(ce); seen_job = true; have_command = false; seen_cst_hhmm = false; @@ -401,7 +401,7 @@ static void parse_history(char const *path) j->lasttime_ = hst.h.lasttime; if (!j->runat_) { j->exectime_ = hst.h.exectime; - j->set_initial_exectime(); + job_set_initial_exectime(j); } else { if (j->interval_ > 0) { log_line("ERROR IN CRONTAB: interval is unused when runat is set: job %d", j->id_); diff --git a/crontab.rl b/crontab.rl index b8df1e3..417b73c 100644 --- a/crontab.rl +++ b/crontab.rl @@ -79,7 +79,7 @@ struct ParseCfgState log_line("job count mismatch"); exit(EXIT_FAILURE); } - new(ce) Job; + job_init(ce); seen_job = true; have_command = false; seen_cst_hhmm = false; @@ -230,7 +230,7 @@ static void parse_history(char const *path) j->lasttime_ = hst.h.lasttime; if (!j->runat_) { j->exectime_ = hst.h.exectime; - j->set_initial_exectime(); + job_set_initial_exectime(j); } else { if (j->interval_ > 0) { log_line("ERROR IN CRONTAB: interval is unused when runat is set: job %d", j->id_); diff --git a/ncron.cpp b/ncron.cpp index d6b9620..f0643f6 100644 --- a/ncron.cpp +++ b/ncron.cpp @@ -46,13 +46,13 @@ static unsigned g_initial_sleep = 0; static char const *g_ncron_conf = CONFIG_FILE_DEFAULT; static char const *g_ncron_execfile = EXEC_FILE_DEFAULT; static char const *g_ncron_execfile_tmp = EXEC_FILE_DEFAULT "~"; -enum class Execmode +enum Execmode { - normal = 0, - journal, - nosave, + Execmode_normal = 0, + Execmode_journal, + Execmode_nosave, }; -static Execmode g_ncron_execmode = Execmode::normal; +static Execmode g_ncron_execmode = Execmode_normal; size_t g_njobs; Job *g_jobs; @@ -96,7 +96,7 @@ static bool do_save_stack(FILE *f, Job *j) static void save_and_exit(void) { - if (g_ncron_execmode != Execmode::nosave) { + if (g_ncron_execmode != Execmode_nosave) { if (save_stack()) { log_line("Saved stack to %s.", g_ncron_execfile); } else { @@ -105,7 +105,7 @@ static void save_and_exit(void) } } // Get rid of leak sanitizer noise. - for (size_t i = 0; i < g_njobs; ++i) g_jobs[i].~Job(); + for (size_t i = 0; i < g_njobs; ++i) job_destroy(&g_jobs[i]); log_line("Exited."); exit(EXIT_SUCCESS); } @@ -214,8 +214,8 @@ static void do_work(unsigned initial_sleep) if (gflags_debug) log_line("DISPATCH %d (%lu <= %lu)", j->id_, j->exectime_, ts.tv_sec); - j->exec(ts); - if (j->journal_ || g_ncron_execmode == Execmode::journal) + job_exec(j, &ts); + if (j->journal_ || g_ncron_execmode == Execmode_journal) pending_save = true; if ((j->numruns_ < j->maxruns_ || j->maxruns_ == 0) && j->exectime_ != 0) { @@ -318,8 +318,8 @@ static void process_options(int ac, char *av[]) exit(EXIT_FAILURE); } break; - case '0': g_ncron_execmode = Execmode::nosave; break; - case 'j': g_ncron_execmode = Execmode::journal; break; + case '0': g_ncron_execmode = Execmode_nosave; break; + case 'j': g_ncron_execmode = Execmode_journal; break; case 't': g_ncron_conf = xstrdup(optarg); break; case 'H': { size_t l = strlen(optarg); diff --git a/sched.cpp b/sched.cpp index 0f4a19b..5c98868 100644 --- a/sched.cpp +++ b/sched.cpp @@ -24,44 +24,54 @@ extern char **environ; // it probably won't run in the uptime of the machine. #define MAX_YEARS 5 -Job::Job() +void job_init(struct Job *self) { + self->next_ = NULL; + self->command_ = NULL; + self->args_ = NULL; + self->exectime_ = 0; + self->lasttime_ = 0; + self->id_ = -1; + self->interval_ = 0; + self->numruns_ = 0; + self->journal_ = false; + self->runat_ = false; // Allowed by default. - memset(&cst_hhmm_, 1, sizeof cst_hhmm_); - memset(&cst_mday_, 1, sizeof cst_mday_); - memset(&cst_wday_, 1, sizeof cst_wday_); - memset(&cst_mon_, 1, sizeof cst_mon_); + memset(&self->cst_hhmm_, 1, sizeof self->cst_hhmm_); + memset(&self->cst_mday_, 1, sizeof self->cst_mday_); + memset(&self->cst_wday_, 1, sizeof self->cst_wday_); + memset(&self->cst_mon_, 1, sizeof self->cst_mon_); } -Job::~Job() +void job_destroy(struct Job *self) { - if (command_) free(command_); - if (args_) free(args_); + if (self->command_) { free(self->command_); self->command_ = NULL; } + if (self->args_) { free(self->args_); self->args_ = NULL; } } -bool Job::in_month(int v) const +static bool job_in_month(const struct Job *self, int v) { assert(v > 0 && v < 13); - return cst_mon_[v - 1]; + return self->cst_mon_[v - 1]; } -bool Job::in_mday(int v) const +static bool job_in_mday(const struct Job *self, int v) { assert(v > 0 && v < 32); - return cst_mday_[v - 1]; + return self->cst_mday_[v - 1]; } -bool Job::in_wday(int v) const +static bool job_in_wday(const struct Job *self, int v) { assert(v > 0 && v < 8); - return cst_wday_[v - 1]; + return self->cst_wday_[v - 1]; } -bool Job::in_hhmm(int h, int m) const +static bool job_in_hhmm(const struct Job *self, int h, int m) { assert(h >= 0 && h < 24); assert(m >= 0 && h < 60); - return cst_hhmm_[h * 60 + m]; + return self->cst_hhmm_[h * 60 + m]; } static bool is_leap_year(int year) @@ -96,58 +106,59 @@ struct day_sieve // bit2 = wday uint8_t filter[366]; - [[nodiscard]] bool day_ok(int i) const { return filter[i] == 7; } +}; - [[nodiscard]] bool build(Job const *entry, int year) - { - memset(filter, 0, sizeof filter); +static bool day_sieve_day_ok(struct day_sieve *self, int i) { return self->filter[i] == 7; } - struct tm t = {}; - t.tm_mday = 1; - t.tm_year = year; - t.tm_isdst = -1; - start_ts = mktime(&t); - if (start_ts == -1) return false; +static bool day_sieve_build(struct day_sieve *self, Job const *entry, int year) +{ + memset(self->filter, 0, sizeof self->filter); - size_t fi = 0; - for (size_t month = 1; month <= 12; ++month) { - bool include_month = entry->in_month(month); - for (int j = 0, jend = days_in_month(month, year); j < jend; ++j, ++fi) { - if (include_month) filter[fi] |= 1; - } - } - fi = 0; - for (size_t month = 1; month <= 12; ++month) { - for (int day = 1, dayend = days_in_month(month, year); day <= dayend; ++day, ++fi) { - if (entry->in_mday(day)) { - filter[fi] |= 2; - } - } + struct tm t = {}; + t.tm_mday = 1; + t.tm_year = year; + t.tm_isdst = -1; + self->start_ts = mktime(&t); + if (self->start_ts == -1) return false; + + size_t fi = 0; + for (size_t month = 1; month <= 12; ++month) { + bool include_month = job_in_month(entry, month); + for (int j = 0, jend = days_in_month(month, year); j < jend; ++j, ++fi) { + if (include_month) self->filter[fi] |= 1; } - int sdow = t.tm_wday + 1; // starting wday of year - int weekday = sdow; // day of the week we're checking - int sday = 0; // starting day of year - for (;;) { - if (entry->in_wday(weekday)) { - for (size_t i = static_cast(sday); i < sizeof filter; i += 7) filter[i] |= 4; + } + fi = 0; + for (size_t month = 1; month <= 12; ++month) { + for (int day = 1, dayend = days_in_month(month, year); day <= dayend; ++day, ++fi) { + if (job_in_mday(entry, day)) { + self->filter[fi] |= 2; } - weekday = weekday % 7 + 1; - if (weekday == sdow) break; - ++sday; - assert(sday < 7); } - // At least one day should be allowed, otherwise - // the job will never run. - for (size_t i = 0; i < sizeof filter; ++i) { - if (filter[i] == 7) return true; + } + int sdow = t.tm_wday + 1; // starting wday of year + int weekday = sdow; // day of the week we're checking + int sday = 0; // starting day of year + for (;;) { + if (job_in_wday(entry, weekday)) { + for (size_t i = static_cast(sday); i < sizeof self->filter; i += 7) self->filter[i] |= 4; } - return false; + weekday = weekday % 7 + 1; + if (weekday == sdow) break; + ++sday; + assert(sday < 7); } -}; + // At least one day should be allowed, otherwise + // the job will never run. + for (size_t i = 0; i < sizeof self->filter; ++i) { + if (self->filter[i] == 7) return true; + } + return false; +} /* stime is the time we're constraining * returns a time value that has been appropriately constrained */ -time_t Job::constrain_time(time_t stime) const +static time_t job_constrain_time(struct Job *self, time_t stime) { struct tm *rtime; time_t t; @@ -156,8 +167,8 @@ time_t Job::constrain_time(time_t stime) const int cyear = rtime->tm_year; int syear = cyear; - day_sieve ds; - if (!ds.build(this, rtime->tm_year)) return 0; + struct day_sieve ds; + if (!day_sieve_build(&ds, self, rtime->tm_year)) return 0; for (;;) { if (cyear - syear >= MAX_YEARS) @@ -165,11 +176,11 @@ time_t Job::constrain_time(time_t stime) const t = mktime(rtime); rtime = localtime(&t); if (rtime->tm_year != cyear) { - if (!ds.build(this, rtime->tm_year)) return 0; + if (!day_sieve_build(&ds, self, rtime->tm_year)) return 0; cyear = rtime->tm_year; } - if (!ds.day_ok(rtime->tm_yday)) { + if (!day_sieve_day_ok(&ds, rtime->tm_yday)) { // Day isn't allowed. Advance to the start of // the next allowed day. rtime->tm_min = 0; @@ -177,7 +188,7 @@ time_t Job::constrain_time(time_t stime) const rtime->tm_mday++; int ndays = is_leap_year(rtime->tm_year) ? 365 : 364; for (int i = rtime->tm_yday + 1; i < ndays; ++i) { - if (ds.day_ok(i)) + if (day_sieve_day_ok(&ds, i)) goto day_ok; rtime->tm_mday++; } @@ -189,7 +200,7 @@ time_t Job::constrain_time(time_t stime) const } day_ok: for (;;) { - if (in_hhmm(rtime->tm_hour, rtime->tm_min)) + if (job_in_hhmm(self, rtime->tm_hour, rtime->tm_min)) return mktime(rtime); ++rtime->tm_min; if (rtime->tm_min == 60) { @@ -214,41 +225,41 @@ time_t Job::constrain_time(time_t stime) const } /* Used when jobs without exectimes are first loaded. */ -void Job::set_initial_exectime() +void job_set_initial_exectime(struct Job *self) { struct timespec ts; clock_or_die(&ts); - time_t ttm = constrain_time(ts.tv_sec); - time_t ttd = ttm - lasttime_; - if (ttd < interval_) { - ttm += interval_ - ttd; - ttm = constrain_time(ttm); + time_t ttm = job_constrain_time(self, ts.tv_sec); + time_t ttd = ttm - self->lasttime_; + if (ttd < self->interval_) { + ttm += self->interval_ - ttd; + ttm = job_constrain_time(self, ttm); } - exectime_ = ttm; + self->exectime_ = ttm; } -/* stupidly advances to next time of execution; performs constraint. */ -void Job::set_next_time() +// Advances to next time of execution; performs constraint +static void job_set_next_time(struct Job *self) { struct timespec ts; clock_or_die(&ts); - time_t etime = constrain_time(ts.tv_sec + interval_); - exectime_ = etime > ts.tv_sec ? etime : 0; + time_t etime = job_constrain_time(self, ts.tv_sec + self->interval_); + self->exectime_ = etime > ts.tv_sec ? etime : 0; } -void Job::exec(const struct timespec &ts) +void job_exec(struct Job *self, const struct timespec *ts) { pid_t pid; - if (int ret = nk_pspawn(&pid, command_, nullptr, nullptr, args_, environ)) { - log_line("posix_spawn failed for '%s': %s", command_, strerror(ret)); + if (int ret = nk_pspawn(&pid, self->command_, nullptr, nullptr, self->args_, environ)) { + log_line("posix_spawn failed for '%s': %s", self->command_, strerror(ret)); return; } - ++numruns_; - lasttime_ = ts.tv_sec; - set_next_time(); + ++self->numruns_; + self->lasttime_ = ts->tv_sec; + job_set_next_time(self); } -void job_insert(Job **head, Job *elt) +void job_insert(struct Job **head, struct Job *elt) { elt->next_ = nullptr; for (;;) { diff --git a/sched.hpp b/sched.hpp index 96eaaf9..6178fe5 100644 --- a/sched.hpp +++ b/sched.hpp @@ -8,44 +8,31 @@ struct Job { - Job(); - Job(Job &) = delete; - Job(Job &&o) = delete; - Job &operator=(Job &) = delete; - Job &operator=(Job &&o) noexcept = delete; - ~Job(); - - Job *next_ = nullptr; - char *command_ = nullptr; - char *args_ = nullptr; - time_t exectime_ = 0; /* time at which we will execute in the future */ - time_t lasttime_ = 0; /* time that the job last ran */ - int id_ = -1; - unsigned int interval_ = 0; /* min interval between executions in seconds */ - unsigned int numruns_ = 0; /* number of times a job has run */ - unsigned int maxruns_ = 0; /* max # of times a job will run, 0 = nolim */ - bool journal_ = false; - bool runat_ = false; + struct Job *next_; + char *command_; + char *args_; + time_t exectime_; /* time at which we will execute in the future */ + time_t lasttime_; /* time that the job last ran */ + int id_; + unsigned int interval_; /* min interval between executions in seconds */ + unsigned int numruns_; /* number of times a job has run */ + unsigned int maxruns_; /* max # of times a job will run, 0 = nolim */ + bool journal_; + bool runat_; bool cst_hhmm_[1440]; // If corresponding bit is set, time is allowed. bool cst_mday_[31]; bool cst_wday_[7]; bool cst_mon_[12]; - - void set_initial_exectime(); - void exec(const struct timespec &ts); - - bool in_month(int v) const; - bool in_mday(int v) const; - bool in_wday(int v) const; - bool in_hhmm(int h, int m) const; -private: - void set_next_time(); - time_t constrain_time(time_t stime) const; }; -void job_insert(Job **head, Job *elt); +void job_init(struct Job *); +void job_destroy(struct Job *); +void job_insert(struct Job **head, struct Job *elt); + +void job_set_initial_exectime(struct Job *); +void job_exec(struct Job *, const struct timespec *ts); void parse_config(char const *path, char const *execfile, - Job **stack, Job **deadstack); + struct Job **stack, struct Job **deadstack); #endif