kern_timeout.c revision 33392
11541Srgrimes/*-
21541Srgrimes * Copyright (c) 1982, 1986, 1991, 1993
31541Srgrimes *	The Regents of the University of California.  All rights reserved.
41541Srgrimes * (c) UNIX System Laboratories, Inc.
51541Srgrimes * All or some portions of this file are derived from material licensed
61541Srgrimes * to the University of California by American Telephone and Telegraph
71541Srgrimes * Co. or Unix System Laboratories, Inc. and are reproduced herein with
81541Srgrimes * the permission of UNIX System Laboratories, Inc.
91541Srgrimes *
101541Srgrimes * Redistribution and use in source and binary forms, with or without
111541Srgrimes * modification, are permitted provided that the following conditions
121541Srgrimes * are met:
131541Srgrimes * 1. Redistributions of source code must retain the above copyright
141541Srgrimes *    notice, this list of conditions and the following disclaimer.
151541Srgrimes * 2. Redistributions in binary form must reproduce the above copyright
161541Srgrimes *    notice, this list of conditions and the following disclaimer in the
171541Srgrimes *    documentation and/or other materials provided with the distribution.
181541Srgrimes * 3. All advertising materials mentioning features or use of this software
191541Srgrimes *    must display the following acknowledgement:
201541Srgrimes *	This product includes software developed by the University of
211541Srgrimes *	California, Berkeley and its contributors.
221541Srgrimes * 4. Neither the name of the University nor the names of its contributors
231541Srgrimes *    may be used to endorse or promote products derived from this software
241541Srgrimes *    without specific prior written permission.
251541Srgrimes *
261541Srgrimes * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
271541Srgrimes * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
281541Srgrimes * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
291541Srgrimes * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
301541Srgrimes * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
311541Srgrimes * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
321541Srgrimes * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
331541Srgrimes * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
341541Srgrimes * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
351541Srgrimes * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
361541Srgrimes * SUCH DAMAGE.
371541Srgrimes *
381541Srgrimes *	@(#)kern_clock.c	8.5 (Berkeley) 1/21/94
3933392Sphk * $Id: kern_timeout.c,v 1.52 1998/01/14 19:42:47 phk Exp $
401541Srgrimes */
411541Srgrimes
421541Srgrimes#include <sys/param.h>
431541Srgrimes#include <sys/systm.h>
4433392Sphk#include <sys/callout.h>
451541Srgrimes#include <sys/kernel.h>
461541Srgrimes
4733392Sphk/*
4833392Sphk * TODO:
4933392Sphk *	allocate more timeout table slots when table overflows.
5033392Sphk */
5133392Sphk
5233392Sphk/* Exported to machdep.c and/or kern_clock.c.  */
5329680Sgibbsstruct callout *callout;
5429680Sgibbsstruct callout_list callfree;
5529680Sgibbsint callwheelsize, callwheelbits, callwheelmask;
5629680Sgibbsstruct callout_tailq *callwheel;
5733392Sphkint softticks;			/* Like ticks, but for softclock(). */
582112Swollman
5929680Sgibbsstatic struct callout *nextsoftcheck;	/* Next callout to be checked. */
601541Srgrimes
611541Srgrimes/*
6229680Sgibbs * The callout mechanism is based on the work of Adam M. Costello and
6329680Sgibbs * George Varghese, published in a technical report entitled "Redesigning
6429680Sgibbs * the BSD Callout and Timer Facilities" and modified slightly for inclusion
6529680Sgibbs * in FreeBSD by Justin T. Gibbs.  The original work on the data structures
6629680Sgibbs * used in this implementation was published by G.Varghese and A. Lauck in
6729680Sgibbs * the paper "Hashed and Hierarchical Timing Wheels: Data Structures for
6829680Sgibbs * the Efficient Implementation of a Timer Facility" in the Proceedings of
6929680Sgibbs * the 11th ACM Annual Symposium on Operating Systems Principles,
7029680Sgibbs * Austin, Texas Nov 1987.
7129680Sgibbs */
7232388Sphk
7329680Sgibbs/*
741541Srgrimes * Software (low priority) clock interrupt.
751541Srgrimes * Run periodic events from timeout queue.
761541Srgrimes */
771541Srgrimesvoid
7832391Sphksoftclock()
791541Srgrimes{
801541Srgrimes	register struct callout *c;
8129805Sgibbs	register struct callout_tailq *bucket;
821541Srgrimes	register int s;
8329805Sgibbs	register int curticks;
8433392Sphk	register int steps;	/* #steps since we last allowed interrupts */
851541Srgrimes
8633392Sphk#ifndef MAX_SOFTCLOCK_STEPS
8733392Sphk#define MAX_SOFTCLOCK_STEPS 100 /* Maximum allowed value of steps. */
8833392Sphk#endif /* MAX_SOFTCLOCK_STEPS */
8929680Sgibbs
9029680Sgibbs	steps = 0;
911541Srgrimes	s = splhigh();
9229680Sgibbs	while (softticks != ticks) {
9329805Sgibbs		softticks++;
9429805Sgibbs		/*
9529805Sgibbs		 * softticks may be modified by hard clock, so cache
9629805Sgibbs		 * it while we work on a given bucket.
9729805Sgibbs		 */
9829805Sgibbs		curticks = softticks;
9929805Sgibbs		bucket = &callwheel[curticks & callwheelmask];
10029805Sgibbs		c = TAILQ_FIRST(bucket);
10129680Sgibbs		while (c) {
10229805Sgibbs			if (c->c_time != curticks) {
10329680Sgibbs				c = TAILQ_NEXT(c, c_links.tqe);
10429680Sgibbs				++steps;
10529680Sgibbs				if (steps >= MAX_SOFTCLOCK_STEPS) {
10629680Sgibbs					nextsoftcheck = c;
10729805Sgibbs					/* Give interrupts a chance. */
10829680Sgibbs					splx(s);
10929680Sgibbs					s = splhigh();
11029680Sgibbs					c = nextsoftcheck;
11129680Sgibbs					steps = 0;
11229680Sgibbs				}
11329680Sgibbs			} else {
11429680Sgibbs				void (*c_func)(void *);
11529680Sgibbs				void *c_arg;
11629680Sgibbs
11729680Sgibbs				nextsoftcheck = TAILQ_NEXT(c, c_links.tqe);
11829805Sgibbs				TAILQ_REMOVE(bucket, c, c_links.tqe);
11929680Sgibbs				c_func = c->c_func;
12029680Sgibbs				c_arg = c->c_arg;
12129680Sgibbs				c->c_func = NULL;
12229680Sgibbs				SLIST_INSERT_HEAD(&callfree, c, c_links.sle);
12329680Sgibbs				splx(s);
12429680Sgibbs				c_func(c_arg);
12529680Sgibbs				s = splhigh();
12629680Sgibbs				steps = 0;
12729680Sgibbs				c = nextsoftcheck;
12829680Sgibbs			}
12929680Sgibbs		}
1301541Srgrimes	}
13129680Sgibbs	nextsoftcheck = NULL;
1321541Srgrimes	splx(s);
1331541Srgrimes}
1341541Srgrimes
1351541Srgrimes/*
1361541Srgrimes * timeout --
1371541Srgrimes *	Execute a function after a specified length of time.
1381541Srgrimes *
1391541Srgrimes * untimeout --
1401541Srgrimes *	Cancel previous timeout function call.
1411541Srgrimes *
14229680Sgibbs * callout_handle_init --
14329680Sgibbs *	Initialize a handle so that using it with untimeout is benign.
14429680Sgibbs *
1451541Srgrimes *	See AT&T BCI Driver Reference Manual for specification.  This
14629680Sgibbs *	implementation differs from that one in that although an
14729680Sgibbs *	identification value is returned from timeout, the original
14829680Sgibbs *	arguments to timeout as well as the identifier are used to
14929680Sgibbs *	identify entries for untimeout.
1501541Srgrimes */
15129680Sgibbsstruct callout_handle
15229680Sgibbstimeout(ftn, arg, to_ticks)
1532112Swollman	timeout_t ftn;
1541541Srgrimes	void *arg;
15529680Sgibbs	register int to_ticks;
1561541Srgrimes{
15729680Sgibbs	int s;
15829680Sgibbs	struct callout *new;
15929680Sgibbs	struct callout_handle handle;
1601541Srgrimes
16129680Sgibbs	if (to_ticks <= 0)
16229680Sgibbs		to_ticks = 1;
1631541Srgrimes
1641541Srgrimes	/* Lock out the clock. */
1651541Srgrimes	s = splhigh();
1661541Srgrimes
1671541Srgrimes	/* Fill in the next free callout structure. */
16829680Sgibbs	new = SLIST_FIRST(&callfree);
16929680Sgibbs	if (new == NULL)
17029680Sgibbs		/* XXX Attempt to malloc first */
1711541Srgrimes		panic("timeout table full");
17229680Sgibbs
17329680Sgibbs	SLIST_REMOVE_HEAD(&callfree, c_links.sle);
1741541Srgrimes	new->c_arg = arg;
1751541Srgrimes	new->c_func = ftn;
17629805Sgibbs	new->c_time = ticks + to_ticks;
17729805Sgibbs	TAILQ_INSERT_TAIL(&callwheel[new->c_time & callwheelmask],
17829805Sgibbs			  new, c_links.tqe);
1791541Srgrimes
1801541Srgrimes	splx(s);
18129680Sgibbs	handle.callout = new;
18229680Sgibbs	return (handle);
1831541Srgrimes}
1841541Srgrimes
1851541Srgrimesvoid
18629680Sgibbsuntimeout(ftn, arg, handle)
1872112Swollman	timeout_t ftn;
1881541Srgrimes	void *arg;
18929680Sgibbs	struct callout_handle handle;
1901541Srgrimes{
1911541Srgrimes	register int s;
1921541Srgrimes
19329680Sgibbs	/*
19429680Sgibbs	 * Check for a handle that was initialized
19529680Sgibbs	 * by callout_handle_init, but never used
19629680Sgibbs	 * for a real timeout.
19729680Sgibbs	 */
19829680Sgibbs	if (handle.callout == NULL)
19929680Sgibbs		return;
20029680Sgibbs
2011541Srgrimes	s = splhigh();
20229680Sgibbs	if ((handle.callout->c_func == ftn)
20329680Sgibbs	 && (handle.callout->c_arg == arg)) {
20429680Sgibbs		if (nextsoftcheck == handle.callout) {
20529680Sgibbs			nextsoftcheck = TAILQ_NEXT(handle.callout, c_links.tqe);
2061541Srgrimes		}
20729805Sgibbs		TAILQ_REMOVE(&callwheel[handle.callout->c_time & callwheelmask],
20829680Sgibbs			     handle.callout, c_links.tqe);
20929680Sgibbs		handle.callout->c_func = NULL;
21029680Sgibbs		SLIST_INSERT_HEAD(&callfree, handle.callout, c_links.sle);
21129680Sgibbs	}
2121541Srgrimes	splx(s);
2131541Srgrimes}
2141541Srgrimes
21524101Sbdevoid
21629680Sgibbscallout_handle_init(struct callout_handle *handle)
21729680Sgibbs{
21829680Sgibbs	handle->callout = NULL;
21929680Sgibbs}
22029680Sgibbs
22131950Snate#ifdef APM_FIXUP_CALLTODO
22231950Snate/*
22331950Snate * Adjust the kernel calltodo timeout list.  This routine is used after
22431950Snate * an APM resume to recalculate the calltodo timer list values with the
22531950Snate * number of hz's we have been sleeping.  The next hardclock() will detect
22631950Snate * that there are fired timers and run softclock() to execute them.
22731950Snate *
22831950Snate * Please note, I have not done an exhaustive analysis of what code this
22931950Snate * might break.  I am motivated to have my select()'s and alarm()'s that
23031950Snate * have expired during suspend firing upon resume so that the applications
23131950Snate * which set the timer can do the maintanence the timer was for as close
23231950Snate * as possible to the originally intended time.  Testing this code for a
23331950Snate * week showed that resuming from a suspend resulted in 22 to 25 timers
23431950Snate * firing, which seemed independant on whether the suspend was 2 hours or
23531950Snate * 2 days.  Your milage may vary.   - Ken Key <key@cs.utk.edu>
23631950Snate */
23731950Snatevoid
23831950Snateadjust_timeout_calltodo(time_change)
23931950Snate    struct timeval *time_change;
24031950Snate{
24131950Snate	register struct callout *p;
24231950Snate	unsigned long delta_ticks;
24331950Snate	int s;
24431950Snate
24531950Snate	/*
24631950Snate	 * How many ticks were we asleep?
24731950Snate	 * (stolen from hzto()).
24831950Snate	 */
24931950Snate
25031950Snate	/* Don't do anything */
25131950Snate	if (time_change->tv_sec < 0)
25231950Snate		return;
25331950Snate	else if (time_change->tv_sec <= LONG_MAX / 1000000)
25431950Snate		delta_ticks = (time_change->tv_sec * 1000000 +
25531950Snate			       time_change->tv_usec + (tick - 1)) / tick + 1;
25631950Snate	else if (time_change->tv_sec <= LONG_MAX / hz)
25731950Snate		delta_ticks = time_change->tv_sec * hz +
25831950Snate			      (time_change->tv_usec + (tick - 1)) / tick + 1;
25931950Snate	else
26031950Snate		delta_ticks = LONG_MAX;
26131950Snate
26231950Snate	if (delta_ticks > INT_MAX)
26331950Snate		delta_ticks = INT_MAX;
26431950Snate
26531950Snate	/*
26631950Snate	 * Now rip through the timer calltodo list looking for timers
26731950Snate	 * to expire.
26831950Snate	 */
26931950Snate
27031950Snate	/* don't collide with softclock() */
27131950Snate	s = splhigh();
27231950Snate	for (p = calltodo.c_next; p != NULL; p = p->c_next) {
27331950Snate		p->c_time -= delta_ticks;
27431950Snate
27531950Snate		/* Break if the timer had more time on it than delta_ticks */
27631950Snate		if (p->c_time > 0)
27731950Snate			break;
27831950Snate
27931950Snate		/* take back the ticks the timer didn't use (p->c_time <= 0) */
28031950Snate		delta_ticks = -p->c_time;
28131950Snate	}
28231950Snate	splx(s);
28331950Snate
28431950Snate	return;
28531950Snate}
28631950Snate#endif /* APM_FIXUP_CALLTODO */
287