File: [local] / src / usr.sbin / smtpd / runq.c (download)
Revision 1.5, Wed May 31 16:51:46 2023 UTC (12 months, 1 week ago) by op
Branch: MAIN
CVS Tags: OPENBSD_7_5_BASE, OPENBSD_7_5, OPENBSD_7_4_BASE, OPENBSD_7_4, HEAD Changes since 1.4: +2 -1 lines
add missing include of time.h
spotted after a report on OpenSMTPD-portable. While here include
sys/time.h in smtpd.h, as noted in event_init(3), since it includes
event.h.
ok millert@
|
/* $OpenBSD: runq.c,v 1.5 2023/05/31 16:51:46 op Exp $ */
/*
* Copyright (c) 2013,2019 Eric Faurot <eric@openbsd.org>
*
* Permission to use, copy, modify, and distribute this software for any
* purpose with or without fee is hereby granted, provided that the above
* copyright notice and this permission notice appear in all copies.
*
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
* ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
#include <stdlib.h>
#include <time.h>
#include "smtpd.h"
struct job {
TAILQ_ENTRY(job) entry;
time_t when;
void *arg;
};
struct runq {
TAILQ_HEAD(, job) jobs;
void (*cb)(struct runq *, void *);
struct event ev;
};
static void runq_timeout(int, short, void *);
static struct runq *active;
static void
runq_reset(struct runq *runq)
{
struct timeval tv;
struct job *job;
time_t now;
job = TAILQ_FIRST(&runq->jobs);
if (job == NULL)
return;
now = time(NULL);
if (job->when <= now)
tv.tv_sec = 0;
else
tv.tv_sec = job->when - now;
tv.tv_usec = 0;
evtimer_add(&runq->ev, &tv);
}
static void
runq_timeout(int fd, short ev, void *arg)
{
struct runq *runq = arg;
struct job *job;
time_t now;
active = runq;
now = time(NULL);
while((job = TAILQ_FIRST(&runq->jobs))) {
if (job->when > now)
break;
TAILQ_REMOVE(&runq->jobs, job, entry);
runq->cb(runq, job->arg);
free(job);
}
active = NULL;
runq_reset(runq);
}
int
runq_init(struct runq **runqp, void (*cb)(struct runq *, void *))
{
struct runq *runq;
runq = malloc(sizeof(*runq));
if (runq == NULL)
return (0);
runq->cb = cb;
TAILQ_INIT(&runq->jobs);
evtimer_set(&runq->ev, runq_timeout, runq);
*runqp = runq;
return (1);
}
int
runq_schedule(struct runq *runq, time_t delay, void *arg)
{
time_t t;
time(&t);
return runq_schedule_at(runq, t + delay, arg);
}
int
runq_schedule_at(struct runq *runq, time_t when, void *arg)
{
struct job *job, *tmpjob;
job = malloc(sizeof(*job));
if (job == NULL)
return (0);
job->arg = arg;
job->when = when;
TAILQ_FOREACH(tmpjob, &runq->jobs, entry) {
if (tmpjob->when > job->when) {
TAILQ_INSERT_BEFORE(tmpjob, job, entry);
goto done;
}
}
TAILQ_INSERT_TAIL(&runq->jobs, job, entry);
done:
if (runq != active && job == TAILQ_FIRST(&runq->jobs)) {
evtimer_del(&runq->ev);
runq_reset(runq);
}
return (1);
}
int
runq_cancel(struct runq *runq, void *arg)
{
struct job *job, *first;
first = TAILQ_FIRST(&runq->jobs);
TAILQ_FOREACH(job, &runq->jobs, entry) {
if (job->arg == arg) {
TAILQ_REMOVE(&runq->jobs, job, entry);
free(job);
if (runq != active && job == first) {
evtimer_del(&runq->ev);
runq_reset(runq);
}
return (1);
}
}
return (0);
}
int
runq_pending(struct runq *runq, void *arg, time_t *when)
{
struct job *job;
TAILQ_FOREACH(job, &runq->jobs, entry) {
if (job->arg == arg) {
if (when)
*when = job->when;
return (1);
}
}
return (0);
}