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