home *** CD-ROM | disk | FTP | other *** search
/ Usenet 1994 October / usenetsourcesnewsgroupsinfomagicoctober1994disk2.iso / unix / volume21 / amd / part04 / clock.c < prev    next >
C/C++ Source or Header  |  1990-04-10  |  4KB  |  199 lines

  1. /*
  2.  * $Id: clock.c,v 5.1 89/11/17 18:19:50 jsp Exp Locker: jsp $
  3.  *
  4.  * Copyright (c) 1989 Jan-Simon Pendry
  5.  * Copyright (c) 1989 Imperial College of Science, Technology & Medicine
  6.  * Copyright (c) 1989 The Regents of the University of California.
  7.  * All rights reserved.
  8.  *
  9.  * This code is derived from software contributed to Berkeley by
  10.  * Jan-Simon Pendry at Imperial College, London.
  11.  *
  12.  * Redistribution and use in source and binary forms are permitted
  13.  * provided that the above copyright notice and this paragraph are
  14.  * duplicated in all such forms and that any documentation,
  15.  * advertising materials, and other materials related to such
  16.  * distribution and use acknowledge that the software was developed
  17.  * by Imperial College of Science, Technology and Medicine, London, UK.
  18.  * The names of the College and University may not be used to endorse
  19.  * or promote products derived from this software without specific
  20.  * prior written permission.
  21.  * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
  22.  * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
  23.  * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
  24.  *
  25.  *    %W% (Berkeley) %G%
  26.  */
  27.  
  28. /*
  29.  * Callouts.
  30.  *
  31.  * Modelled on kernel object of the same name.
  32.  * See usual references.
  33.  *
  34.  * Use of a heap-based mechanism was rejected:
  35.  * 1.  more complext implementation needed.
  36.  * 2.  not obvious that a list is too slow for amd.
  37.  */
  38.  
  39. #include "am.h"
  40.  
  41. typedef struct callout callout;
  42. struct callout {
  43.     callout    *c_next;        /* List of callouts */
  44.     void    (*c_fn)();        /* Function to call */
  45.     voidp    c_closure;        /* Closure to pass to call */
  46.     time_t    c_time;            /* Time of call */
  47.     int    c_id;            /* Unique identifier */
  48. };
  49.  
  50. static callout callouts;        /* List of pending callouts */
  51. static callout *free_callouts;        /* Cache of free callouts */
  52. static int nfree_callouts;        /* Number on free list */
  53. static int callout_id;            /* Next free callout identifier */
  54. time_t next_softclock;            /* Time of next call to softclock() */
  55.  
  56. /*
  57.  * Number of callout slots we keep on the free list
  58.  */
  59. #define    CALLOUT_FREE_SLOP    10
  60.  
  61. /*
  62.  * Assumption: valid id's are non-zero.
  63.  */
  64. #define    CID_ALLOC()    (++callout_id)
  65. #define    CID_UNDEF    (0)
  66.  
  67. static callout *alloc_callout()
  68. {
  69.     callout *cp = free_callouts;
  70.     if (cp) {
  71.         --nfree_callouts;
  72.         free_callouts = free_callouts->c_next;
  73.         return cp;
  74.     }
  75.     return ALLOC(callout);
  76. }
  77.  
  78. static void free_callout(cp)
  79. callout *cp;
  80. {
  81.     if (nfree_callouts > CALLOUT_FREE_SLOP) {
  82.         free((voidp) cp);
  83.     } else {
  84.         cp->c_next = free_callouts;
  85.         free_callouts = cp;
  86.         nfree_callouts++;
  87.     }
  88. }
  89.  
  90. /*
  91.  * Schedule a callout.
  92.  *
  93.  * (*fn)(closure) will be called at clocktime() + secs
  94.  */
  95. int timeout(secs, fn, closure)
  96. unsigned int secs;
  97. void (*fn)();
  98. voidp closure;
  99. {
  100.     callout *cp, *cp2;
  101.     time_t t = clocktime() + secs;
  102.  
  103.     /*
  104.      * Allocate and fill in a new callout structure
  105.      */
  106.     callout *cpnew = alloc_callout();
  107.     cpnew->c_closure = closure;
  108.     cpnew->c_fn = fn;
  109.     cpnew->c_time = t;
  110.     cpnew->c_id = CID_ALLOC();
  111.  
  112.     if (t < next_softclock)
  113.         next_softclock = t;
  114.  
  115.     /*
  116.      * Find the correct place in the list
  117.      */
  118.     for (cp = &callouts; cp2 = cp->c_next; cp = cp2)
  119.         if (cp2->c_time >= t)
  120.             break;
  121.  
  122.     /*
  123.      * And link it in
  124.      */
  125.     cp->c_next = cpnew;
  126.     cpnew->c_next = cp2;
  127.  
  128.     /*
  129.      * Return callout identifier
  130.      */
  131.     return cpnew->c_id;
  132. }
  133.  
  134. /*
  135.  * De-schedule a callout
  136.  */
  137. void untimeout(id)
  138. int id;
  139. {
  140.     callout *cp, *cp2;
  141.     for (cp = &callouts; cp2 = cp->c_next; cp = cp2) {
  142.         if (cp2->c_id == id) {
  143.             cp->c_next = cp2->c_next;
  144.             free_callout(cp2);
  145.             break;
  146.         }
  147.     }
  148. }
  149.  
  150. /*
  151.  * Clock handler
  152.  */
  153. int softclock()
  154. {
  155.     time_t now;
  156.     callout *cp;
  157.  
  158.     do {
  159.         if (task_notify_todo)
  160.             task_notify();
  161.  
  162.         now = clocktime();
  163.  
  164.         /*
  165.          * While there are more callouts waiting...
  166.          */
  167.         while ((cp = callouts.c_next) && cp->c_time <= now) {
  168.             /*
  169.              * Extract first from list, save fn & closure and
  170.              * unlink callout from list and free.
  171.              * Finally call function.
  172.              *
  173.              * The free is done first because
  174.              * it is quite common that the
  175.              * function will call timeout()
  176.              * and try to allocate a callout
  177.              */
  178.             void (*fn)() = cp->c_fn;
  179.             voidp closure = cp->c_closure;
  180.  
  181.             callouts.c_next = cp->c_next;
  182.             free_callout(cp);
  183. #ifdef DEBUG
  184.             /*dlog("Calling %#x(%#x)", fn, closure);*/
  185. #endif
  186.             (*fn)(closure);
  187.         }
  188.  
  189.     } while (task_notify_todo);
  190.  
  191.     /*
  192.      * Return number of seconds to next event,
  193.      * or 0 if there is no event.
  194.      */
  195.     if (cp = callouts.c_next)
  196.         return cp->c_time - now;
  197.     return 0;
  198. }
  199.