GCC Code Coverage Report
Directory: ./ Exec Total Coverage
File: usr.sbin/amd/amd/clock.c Lines: 0 47 0.0 %
Date: 2016-12-06 Branches: 0 34 0.0 %

Line Branch Exec Source
1
/*
2
 * Copyright (c) 1989 Jan-Simon Pendry
3
 * Copyright (c) 1989 Imperial College of Science, Technology & Medicine
4
 * Copyright (c) 1989, 1993
5
 *	The Regents of the University of California.  All rights reserved.
6
 *
7
 * This code is derived from software contributed to Berkeley by
8
 * Jan-Simon Pendry at Imperial College, London.
9
 *
10
 * Redistribution and use in source and binary forms, with or without
11
 * modification, are permitted provided that the following conditions
12
 * are met:
13
 * 1. Redistributions of source code must retain the above copyright
14
 *    notice, this list of conditions and the following disclaimer.
15
 * 2. Redistributions in binary form must reproduce the above copyright
16
 *    notice, this list of conditions and the following disclaimer in the
17
 *    documentation and/or other materials provided with the distribution.
18
 * 3. Neither the name of the University nor the names of its contributors
19
 *    may be used to endorse or promote products derived from this software
20
 *    without specific prior written permission.
21
 *
22
 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
23
 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
24
 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
25
 * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
26
 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
27
 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
28
 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
29
 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
30
 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
31
 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
32
 * SUCH DAMAGE.
33
 *
34
 *	from: @(#)clock.c	8.1 (Berkeley) 6/6/93
35
 *	$Id: clock.c,v 1.7 2014/10/26 03:08:21 guenther Exp $
36
 */
37
38
/*
39
 * Callouts.
40
 *
41
 * Modelled on kernel object of the same name.
42
 * See usual references.
43
 *
44
 * Use of a heap-based mechanism was rejected:
45
 * 1.  more complex implementation needed.
46
 * 2.  not obvious that a list is too slow for Amd.
47
 */
48
49
#include "am.h"
50
51
typedef struct callout callout;
52
struct callout {
53
	callout	*c_next;		/* List of callouts */
54
	void	(*c_fn)(void *);	/* Function to call */
55
	void	*c_closure;		/* Closure to pass to call */
56
	time_t	c_time;			/* Time of call */
57
	int	c_id;			/* Unique identifier */
58
};
59
60
static callout callouts;		/* List of pending callouts */
61
static callout *free_callouts;		/* Cache of free callouts */
62
static int nfree_callouts;		/* Number on free list */
63
static int callout_id;			/* Next free callout identifier */
64
time_t next_softclock;			/* Time of next call to softclock() */
65
66
/*
67
 * Number of callout slots we keep on the free list
68
 */
69
#define	CALLOUT_FREE_SLOP	10
70
71
/*
72
 * Global assumption: valid id's are non-zero.
73
 */
74
#define	CID_ALLOC()	(++callout_id)
75
#define	CID_UNDEF	(0)
76
77
static callout *
78
alloc_callout(void)
79
{
80
	callout *cp = free_callouts;
81
	if (cp) {
82
		--nfree_callouts;
83
		free_callouts = free_callouts->c_next;
84
		return cp;
85
	}
86
	return ALLOC(callout);
87
}
88
89
static void
90
free_callout(callout *cp)
91
{
92
	if (nfree_callouts > CALLOUT_FREE_SLOP) {
93
		free(cp);
94
	} else {
95
		cp->c_next = free_callouts;
96
		free_callouts = cp;
97
		nfree_callouts++;
98
	}
99
}
100
101
/*
102
 * Schedule a callout.
103
 *
104
 * (*fn)(closure) will be called at clocktime() + secs
105
 */
106
int
107
timeout(unsigned int secs, void (*fn)(void *), void *closure)
108
{
109
	callout *cp, *cp2;
110
	time_t t = clocktime() + secs;
111
112
	/*
113
	 * Allocate and fill in a new callout structure
114
	 */
115
	callout *cpnew = alloc_callout();
116
	cpnew->c_closure = closure;
117
	cpnew->c_fn = fn;
118
	cpnew->c_time = t;
119
	cpnew->c_id = CID_ALLOC();
120
121
	if (t < next_softclock)
122
		next_softclock = t;
123
124
	/*
125
	 * Find the correct place in the list
126
	 */
127
	for (cp = &callouts; (cp2 = cp->c_next); cp = cp2)
128
		if (cp2->c_time >= t)
129
			break;
130
131
	/*
132
	 * And link it in
133
	 */
134
	cp->c_next = cpnew;
135
	cpnew->c_next = cp2;
136
137
	/*
138
	 * Return callout identifier
139
	 */
140
	return cpnew->c_id;
141
}
142
143
/*
144
 * De-schedule a callout
145
 */
146
void
147
untimeout(int id)
148
{
149
	callout *cp, *cp2;
150
	for (cp = &callouts; (cp2 = cp->c_next); cp = cp2) {
151
		if (cp2->c_id == id) {
152
			cp->c_next = cp2->c_next;
153
			free_callout(cp2);
154
			break;
155
		}
156
	}
157
}
158
159
/*
160
 * Reschedule after clock changed
161
 */
162
void
163
reschedule_timeouts(time_t now, time_t then)
164
{
165
	callout *cp;
166
167
	for (cp = callouts.c_next; cp; cp = cp->c_next) {
168
		if (cp->c_time >= now && cp->c_time <= then) {
169
			plog(XLOG_WARNING, "job %d rescheduled to run immediately", cp->c_id);
170
#ifdef DEBUG
171
			dlog("rescheduling job %d back %d seconds",
172
				cp->c_id, cp->c_time - now);
173
#endif
174
			next_softclock = cp->c_time = now;
175
		}
176
	}
177
}
178
179
/*
180
 * Clock handler
181
 */
182
int
183
softclock(void)
184
{
185
	time_t now;
186
	callout *cp;
187
188
	do {
189
		if (task_notify_todo)
190
			do_task_notify();
191
192
		now = clocktime();
193
194
		/*
195
		 * While there are more callouts waiting...
196
		 */
197
		while ((cp = callouts.c_next) && cp->c_time <= now) {
198
			/*
199
			 * Extract first from list, save fn & closure and
200
			 * unlink callout from list and free.
201
			 * Finally call function.
202
			 *
203
			 * The free is done first because
204
			 * it is quite common that the
205
			 * function will call timeout()
206
			 * and try to allocate a callout
207
			 */
208
			void (*fn)(void *) = cp->c_fn;
209
			void *closure = cp->c_closure;
210
211
			callouts.c_next = cp->c_next;
212
			free_callout(cp);
213
#ifdef DEBUG
214
			/*dlog("Calling %#x(%#x)", fn, closure);*/
215
#endif /* DEBUG */
216
			(*fn)(closure);
217
		}
218
219
	} while (task_notify_todo);
220
221
	/*
222
	 * Return number of seconds to next event,
223
	 * or 0 if there is no event.
224
	 */
225
	if ((cp = callouts.c_next))
226
		return cp->c_time - now;
227
	return 0;
228
}