Whamcloud - gitweb
b=5498
[fs/lustre-release.git] / lnet / ulnds / socklnd / pqtimer.c
1 /* -*- mode: c; c-basic-offset: 8; indent-tabs-mode: nil; -*-
2  * vim:expandtab:shiftwidth=8:tabstop=8:
3  *
4  *  Copyright (c) 2002 Cray Inc.
5  *  Copyright (c) 2002 Eric Hoffman
6  *
7  *   This file is part of Lustre, http://www.lustre.org.
8  *
9  *   Lustre is free software; you can redistribute it and/or
10  *   modify it under the terms of version 2 of the GNU General Public
11  *   License as published by the Free Software Foundation.
12  *
13  *   Lustre is distributed in the hope that it will be useful,
14  *   but WITHOUT ANY WARRANTY; without even the implied warranty of
15  *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
16  *   GNU General Public License for more details.
17  *
18  *   You should have received a copy of the GNU General Public License
19  *   along with Lustre; if not, write to the Free Software
20  *   Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
21  */
22
23 /* timer.c:
24  *   this file implements a simple priority-queue based timer system. when
25  * combined with a file which implements now() and block(), it can
26  * be used to provide course-grained time-based callbacks.
27  */
28
29 #include <pqtimer.h>
30 #include <stdlib.h>
31 #include <string.h>
32
33 struct timer {
34   void (*function)(void *);
35   void *arg;
36   when w;
37   int interval;
38   int disable;
39 };
40
41 typedef struct thunk *thunk;
42 struct thunk {
43     void (*f)(void *);
44     void *a;
45     thunk next;
46 };
47
48 extern when now(void);
49
50 static thunk thunks;
51 static int internal;
52 static void (*block_function)(when);
53 static int number_of_timers;
54 static int size_of_pqueue;
55 static timer *timers;
56
57
58 static void heal(int where)
59 {
60     int left=(where<<1);
61     int right=(where<<1)+1;
62     int min=where;
63     timer temp;
64   
65     if (left <= number_of_timers)
66         if (timers[left]->w < timers[min]->w) min=left;
67     if (right <= number_of_timers)
68         if (timers[right]->w < timers[min]->w) min=right;
69     if (min != where){
70         temp=timers[where];
71         timers[where]=timers[min];
72         timers[min]=temp;
73         heal(min);
74     }
75 }
76
77 static void add_pqueue(int i)
78 {
79     timer temp;
80     int parent=(i>>1);
81     if ((i>1) && (timers[i]->w< timers[parent]->w)){
82         temp=timers[i];
83         timers[i]=timers[parent];
84         timers[parent]=temp;
85         add_pqueue(parent);
86     }
87 }
88
89 static void add_timer(timer t)
90 {
91     if (size_of_pqueue<(number_of_timers+2)){
92         int oldsize=size_of_pqueue;
93         timer *new=(void *)malloc(sizeof(struct timer)*(size_of_pqueue+=10));
94         memcpy(new,timers,sizeof(timer)*oldsize);
95         timers=new;
96     }
97     timers[++number_of_timers]=t;
98     add_pqueue(number_of_timers);
99 }
100
101 /* Function: register_timer
102  * Arguments: interval: the time interval from the current time when
103  *                      the timer function should be called
104  *            function: the function to call when the time has expired
105  *            argument: the argument to call it with.
106  * Returns: a pointer to a timer structure
107  */
108 timer register_timer(when interval,
109                      void (*function)(void *),
110                      void *argument)
111 {
112     timer t=(timer)malloc(sizeof(struct timer));
113
114     t->arg=argument;
115     t->function=function;
116     t->interval=interval;
117     t->disable=0;
118     t->w=now()+interval;
119     add_timer(t);
120     if (!internal && (number_of_timers==1))
121         block_function(t->w);
122     return(t);
123 }
124
125 /* Function: remove_timer
126  * Arguments: t: 
127  * Returns: nothing
128  *
129  * remove_timer removes a timer from the system, insuring
130  * that it will never be called. It does not actually
131  * free the timer due to reentrancy issues.
132  */
133
134 void remove_timer(timer t)
135 {
136     t->disable=1;
137 }
138
139
140
141 void timer_fire()
142 {
143     timer current;
144
145     current=timers[1];
146     timers[1]=timers[number_of_timers--];
147     heal(1);
148     if (!current->disable) {
149         (*current->function)(current->arg);
150     }
151     free(current);
152 }
153
154 when next_timer(void)
155 {
156     when here=now();
157
158     while (number_of_timers && (timers[1]->w <= here)) timer_fire();
159     if (number_of_timers) return(timers[1]->w);
160     return(0);
161 }
162
163 /* Function: timer_loop
164  * Arguments: none
165  * Returns: never
166  * 
167  * timer_loop() is the blocking dispatch function for the timer.
168  * Is calls the block() function registered with init_timer,
169  * and handles associated with timers that have been registered.
170  */
171 void timer_loop()
172 {
173     when here;
174
175     while (1){
176         thunk z;
177         here=now();
178
179         for (z=thunks;z;z=z->next) (*z->f)(z->a);
180
181         if (number_of_timers){
182             if (timers[1]->w > here){
183                 (*block_function)(timers[1]->w);
184             } else {
185                 timer_fire();
186             }
187         } else {
188             thunk z;
189             for (z=thunks;z;z=z->next) (*z->f)(z->a);
190             (*block_function)(0);
191         }
192     }
193 }
194
195
196 /* Function: register_thunk
197  * Arguments: f: the function to call
198  *            a: the single argument to call it with
199  *
200  * Thunk functions get called at irregular intervals, they
201  * should not assume when, or take a particularily long
202  * amount of time. Thunks are for background cleanup tasks.
203  */
204 void register_thunk(void (*f)(void *),void *a)
205 {
206     thunk t=(void *)malloc(sizeof(struct thunk));
207     t->f=f;
208     t->a=a;
209     t->next=thunks;
210     thunks=t;
211 }
212
213 /* Function: initialize_timer
214  * Arguments: block: the function to call to block for the specified interval 
215  *
216  * initialize_timer() must be called before any other timer function,
217  * including timer_loop.
218  */
219 void initialize_timer(void (*block)(when))
220 {
221     block_function=block;
222     number_of_timers=0;
223     size_of_pqueue=10;
224     timers=(timer *)malloc(sizeof(timer)*size_of_pqueue);
225     thunks=0;
226 }