GCC Code Coverage Report
Directory: ./ Exec Total Coverage
File: usr.sbin/smtpd/smtpd/../runq.c Lines: 0 71 0.0 %
Date: 2017-11-13 Branches: 0 52 0.0 %

Line Branch Exec Source
1
/*	$OpenBSD: runq.c,v 1.2 2015/01/20 17:37:54 deraadt Exp $	*/
2
3
/*
4
 * Copyright (c) 2013 Eric Faurot <eric@openbsd.org>
5
 *
6
 * Permission to use, copy, modify, and distribute this software for any
7
 * purpose with or without fee is hereby granted, provided that the above
8
 * copyright notice and this permission notice appear in all copies.
9
 *
10
 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
11
 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
12
 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
13
 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
14
 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
15
 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
16
 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
17
 */
18
19
#include <sys/types.h>
20
#include <sys/socket.h>
21
#include <sys/queue.h>
22
#include <sys/tree.h>
23
#include <sys/uio.h>
24
25
#include <imsg.h>
26
#include <stdio.h>
27
#include <stdlib.h>
28
#include <limits.h>
29
#include <time.h>
30
31
#include "smtpd.h"
32
33
struct job {
34
	TAILQ_ENTRY(job)	 entry;
35
	time_t			 when;
36
	void			(*cb)(struct runq *, void *);
37
	void			*arg;
38
};
39
40
struct runq {
41
	TAILQ_HEAD(, job)	 jobs;
42
	void			(*cb)(struct runq *, void *);
43
	struct event		 ev;
44
};
45
46
static void runq_timeout(int, short, void *);
47
48
static struct runq *active;
49
50
static void
51
runq_reset(struct runq *runq)
52
{
53
	struct timeval	 tv;
54
	struct job	*job;
55
	time_t		 now;
56
57
	job = TAILQ_FIRST(&runq->jobs);
58
	if (job == NULL)
59
		return;
60
61
	now = time(NULL);
62
	if (job->when <= now)
63
		tv.tv_sec = 0;
64
	else
65
		tv.tv_sec = job->when - now;
66
	tv.tv_usec = 0;
67
	evtimer_add(&runq->ev, &tv);
68
}
69
70
static void
71
runq_timeout(int fd, short ev, void *arg)
72
{
73
	struct runq	*runq = arg;
74
	struct job	*job;
75
	time_t		 now;
76
77
	active = runq;
78
	now = time(NULL);
79
80
	while((job = TAILQ_FIRST(&runq->jobs))) {
81
		if (job->when > now)
82
			break;
83
		TAILQ_REMOVE(&runq->jobs, job, entry);
84
		if (job->cb)
85
			job->cb(runq, job->arg);
86
		else
87
			runq->cb(runq, job->arg);
88
		free(job);
89
	}
90
91
	active = NULL;
92
	runq_reset(runq);
93
}
94
95
int
96
runq_init(struct runq **runqp, void (*cb)(struct runq *, void *))
97
{
98
	struct runq	*runq;
99
100
	runq = malloc(sizeof(*runq));
101
	if (runq == NULL)
102
		return (0);
103
104
	runq->cb = cb;
105
	TAILQ_INIT(&runq->jobs);
106
	evtimer_set(&runq->ev, runq_timeout, runq);
107
108
	*runqp = runq;
109
110
	return (1);
111
}
112
113
int
114
runq_schedule(struct runq *runq, time_t when, void (*cb)(struct runq *, void *),
115
    void *arg)
116
{
117
	struct job	*job, *tmpjob;
118
119
	job = malloc(sizeof(*job));
120
	if (job == NULL)
121
		return (0);
122
123
	job->arg = arg;
124
	job->cb = cb;
125
	job->when = when;
126
127
	TAILQ_FOREACH(tmpjob, &runq->jobs, entry) {
128
		if (tmpjob->when > job->when) {
129
			TAILQ_INSERT_BEFORE(tmpjob, job, entry);
130
			goto done;
131
		}
132
	}
133
	TAILQ_INSERT_TAIL(&runq->jobs, job, entry);
134
135
    done:
136
	if (runq != active && job == TAILQ_FIRST(&runq->jobs)) {
137
		evtimer_del(&runq->ev);
138
		runq_reset(runq);
139
	}
140
	return (1);
141
}
142
143
int
144
runq_delay(struct runq *runq, unsigned int delay,
145
    void (*cb)(struct runq *, void *), void *arg)
146
{
147
	return runq_schedule(runq, time(NULL) + delay, cb, arg);
148
}
149
150
int
151
runq_cancel(struct runq *runq, void (*cb)(struct runq *, void *), void *arg)
152
{
153
	struct job	*job, *first;
154
155
	first = TAILQ_FIRST(&runq->jobs);
156
	TAILQ_FOREACH(job, &runq->jobs, entry) {
157
		if (job->cb == cb && job->arg == arg) {
158
			TAILQ_REMOVE(&runq->jobs, job, entry);
159
			free(job);
160
			if (runq != active && job == first) {
161
				evtimer_del(&runq->ev);
162
				runq_reset(runq);
163
			}
164
			return (1);
165
		}
166
	}
167
168
	return (0);
169
}
170
171
int
172
runq_pending(struct runq *runq, void (*cb)(struct runq *, void *), void *arg,
173
    time_t *when)
174
{
175
	struct job	*job;
176
177
	TAILQ_FOREACH(job, &runq->jobs, entry) {
178
		if (job->cb == cb && job->arg == arg) {
179
			if (when)
180
				*when = job->when;
181
			return (1);
182
		}
183
	}
184
185
	return (0);
186
}
187
188
int
189
runq_next(struct runq *runq, void (**cb)(struct runq *, void *), void **arg,
190
    time_t *when)
191
{
192
	struct job	*job;
193
194
	job = TAILQ_FIRST(&runq->jobs);
195
	if (job == NULL)
196
		return (0);
197
	if (cb)
198
		*cb = job->cb;
199
	if (arg)
200
		*arg = job->arg;
201
	if (when)
202
		*when = job->when;
203
204
	return (1);
205
}