rx-warning-cleanup-and-afsconfig-20010605
[openafs.git] / src / rx / rx_event.c
1 /*
2  * Copyright 2000, International Business Machines Corporation and others.
3  * All Rights Reserved.
4  * 
5  * This software has been released under the terms of the IBM Public
6  * License.  For details, see the LICENSE file in the top-level source
7  * directory or online at http://www.openafs.org/dl/license10.html
8  */
9
10 #ifdef  KERNEL
11 #include "../afs/param.h"
12 #ifndef UKERNEL
13 #include "../afs/afs_osi.h"
14 #else /* !UKERNEL */
15 #include "../afs/sysincludes.h"
16 #include "../afs/afsincludes.h"
17 #endif /* !UKERNEL */
18 #include "../rx/rx_clock.h"
19 #include "../rx/rx_queue.h"
20 #include "../rx/rx_event.h"
21 #include "../rx/rx_kernel.h"
22 #include "../rx/rx_kmutex.h"
23 #ifdef RX_ENABLE_LOCKS
24 #include "../rx/rx.h"
25 #endif /* RX_ENABLE_LOCKS */
26 #include "../rx/rx_globals.h"
27 #if defined(AFS_SGI_ENV)
28 #include "../sys/debug.h"
29 /* These are necessary to get curproc (used by GLOCK asserts) to work. */
30 #include "../h/proc.h"
31 #if !defined(AFS_SGI64_ENV) && !defined(UKERNEL)
32 #include "../h/user.h"
33 #endif
34 extern void *osi_Alloc();
35 #endif
36 #else /* KERNEL */
37 #include "afs/param.h"
38 #include <stdio.h>
39 #include "rx_clock.h"
40 #include "rx_queue.h"
41 #include "rx_event.h"
42 #include "rx_user.h"
43 #ifdef AFS_PTHREAD_ENV
44 #include <rx/rx_pthread.h>
45 #else
46 #include "rx_lwp.h"
47 #endif
48 #ifdef RX_ENABLE_LOCKS
49 #include "rx.h"
50 #endif /* RX_ENABLE_LOCKS */
51 #include "rx_globals.h"
52 #ifdef AFS_NT40_ENV
53 #include <malloc.h>
54 #endif
55 #endif /* KERNEL */
56
57
58 /* All event processing is relative to the apparent current time given by clock_GetTime */
59
60 /* This should be static, but event_test wants to look at the free list... */
61 struct rx_queue rxevent_free;      /* It's somewhat bogus to use a doubly-linked queue for the free list */
62 struct rx_queue rxepoch_free;      /* It's somewhat bogus to use a doubly-linked queue for the free list */
63 static struct rx_queue rxepoch_queue; /* list of waiting epochs */
64 static int rxevent_allocUnit = 10;   /* Allocation unit (number of event records to allocate at one time) */
65 static int rxepoch_allocUnit = 10;   /* Allocation unit (number of epoch records to allocate at one time) */
66 int rxevent_nFree;                 /* Number of free event records */
67 int rxevent_nPosted;       /* Current number of posted events */
68 int rxepoch_nFree;                 /* Number of free epoch records */
69 static int (*rxevent_ScheduledEarlierEvent)(); /* Proc to call when an event is scheduled that is earlier than all other events */
70 struct xfreelist { 
71     void *mem;
72     int size;
73     struct xfreelist *next; 
74 };
75 static struct xfreelist *xfreemallocs = 0, *xsp = 0;
76
77 struct clock rxevent_nextRaiseEvents;   /* Time of next call to raise events */
78 int rxevent_raiseScheduled;             /* true if raise events is scheduled */
79
80 #ifdef RX_ENABLE_LOCKS
81 #ifdef RX_LOCKS_DB
82 /* rxdb_fileID is used to identify the lock location, along with line#. */
83 static int rxdb_fileID = RXDB_FILE_RX_EVENT;
84 #endif /* RX_LOCKS_DB */
85 #define RX_ENABLE_LOCKS  1
86 afs_kmutex_t rxevent_lock;
87 #endif /* RX_ENABLE_LOCKS */
88
89 #ifdef AFS_PTHREAD_ENV
90 /*
91  * This mutex protects the following global variables:
92  * rxevent_initialized
93  */
94
95 #include <assert.h>
96 pthread_mutex_t rx_event_mutex;
97 #define LOCK_EV_INIT assert(pthread_mutex_lock(&rx_event_mutex)==0);
98 #define UNLOCK_EV_INIT assert(pthread_mutex_unlock(&rx_event_mutex)==0);
99 #else
100 #define LOCK_EV_INIT
101 #define UNLOCK_EV_INIT
102 #endif /* AFS_PTHREAD_ENV */
103
104
105 /* Pass in the number of events to allocate at a time */
106 int rxevent_initialized = 0;
107 void
108 rxevent_Init(nEvents, scheduler)
109     int nEvents;
110     int (*scheduler)();
111 {
112     LOCK_EV_INIT
113     if (rxevent_initialized) {
114         UNLOCK_EV_INIT
115         return;
116     }
117     MUTEX_INIT(&rxevent_lock, "rxevent_lock", MUTEX_DEFAULT, 0);
118     clock_Init();
119     if (nEvents) rxevent_allocUnit = nEvents;
120     queue_Init(&rxevent_free);
121     queue_Init(&rxepoch_free);
122     queue_Init(&rxepoch_queue);
123     rxevent_nFree = rxevent_nPosted = 0;
124     rxepoch_nFree = 0;
125     rxevent_ScheduledEarlierEvent = scheduler;
126     rxevent_initialized = 1;
127     clock_Zero(&rxevent_nextRaiseEvents);
128     rxevent_raiseScheduled = 0;
129     UNLOCK_EV_INIT
130 }
131
132 /* Create and initialize new epoch structure */
133 struct rxepoch *rxepoch_Allocate(struct clock *when)
134 {
135     struct rxepoch *ep;
136     int i;
137
138     /* If we are short on free epoch entries, create a block of new oned
139      * and add them to the free queue */
140     if (queue_IsEmpty(&rxepoch_free)) {
141 #if    defined(AFS_AIX32_ENV) && defined(KERNEL)
142         ep = (struct rxepoch *) rxi_Alloc(sizeof(struct rxepoch));
143         queue_Append(&rxepoch_free, &ep[0]), rxepoch_nFree++;
144 #else
145         ep = (struct rxepoch *)
146              osi_Alloc(sizeof(struct rxepoch) * rxepoch_allocUnit);
147         xsp = xfreemallocs;
148         xfreemallocs = (struct xfreelist *) osi_Alloc(sizeof(struct xfreelist));
149         xfreemallocs->mem = (void *)ep;
150         xfreemallocs->size = sizeof(struct rxepoch) * rxepoch_allocUnit;
151         xfreemallocs->next = xsp;
152         for (i = 0; i<rxepoch_allocUnit; i++)
153             queue_Append(&rxepoch_free, &ep[i]), rxepoch_nFree++;
154 #endif
155     }
156     ep = queue_First(&rxepoch_free, rxepoch);
157     queue_Remove(ep);
158     rxepoch_nFree--;
159     ep->epochSec = when->sec;
160     queue_Init(&ep->events);
161     return ep;
162 }
163
164 /* Add the indicated event (function, arg) at the specified clock time.  The
165  * "when" argument specifies when "func" should be called, in clock (clock.h)
166  * units. */
167
168 struct rxevent *rxevent_Post(struct clock *when, void (*func)(),
169                              void *arg, void *arg1)
170 {
171     register struct rxevent *ev, *evqe, *evqpr;
172     register struct rxepoch *ep, *epqe, *epqpr;
173     struct clock ept;
174     int isEarliest = 0;
175
176     MUTEX_ENTER(&rxevent_lock);
177     AFS_ASSERT_RXGLOCK();
178 #ifdef RXDEBUG
179     if (rx_Log_event) {
180         struct clock now;
181         clock_GetTime(&now);
182         fprintf(rx_Log_event, "%d.%d: rxevent_Post(%d.%d, %x, %x)\n", now.sec, now.usec, when->sec, when->usec, func, arg);
183     }
184 #endif
185
186     /* Get a pointer to the epoch for this event, if none is found then
187      * create a new epoch and insert it into the sorted list */
188     for (ep = NULL, queue_ScanBackwards(&rxepoch_queue, epqe, epqpr, rxepoch)) {
189         if (when->sec == epqe->epochSec) {
190             /* already have an structure for this epoch */
191             ep = epqe;
192             if (ep == queue_First(&rxepoch_queue, rxepoch))
193                 isEarliest = 1;
194             break;
195         } else if (when->sec > epqe->epochSec) {
196             /* Create a new epoch and insert after qe */
197             ep = rxepoch_Allocate(when);
198             queue_InsertAfter(epqe, ep);
199             break;
200         }
201     }
202     if (ep == NULL) {
203         /* Create a new epoch and place it at the head of the list */
204         ep = rxepoch_Allocate(when);
205         queue_Prepend(&rxepoch_queue, ep);
206         isEarliest = 1;
207     }
208
209     /* If we're short on free event entries, create a block of new ones and add
210      * them to the free queue */
211     if (queue_IsEmpty(&rxevent_free)) {
212         register int i;
213 #if     defined(AFS_AIX32_ENV) && defined(KERNEL)
214         ev = (struct rxevent *) rxi_Alloc(sizeof(struct rxevent));
215         queue_Append(&rxevent_free, &ev[0]), rxevent_nFree++;
216 #else
217         ev = (struct rxevent *) osi_Alloc(sizeof(struct rxevent) * rxevent_allocUnit);
218         xsp = xfreemallocs;
219         xfreemallocs = (struct xfreelist *) osi_Alloc(sizeof(struct xfreelist));
220         xfreemallocs->mem = (void *)ev;
221         xfreemallocs->size = sizeof(struct rxevent) * rxevent_allocUnit;
222         xfreemallocs->next = xsp;
223         for (i = 0; i<rxevent_allocUnit; i++)
224             queue_Append(&rxevent_free, &ev[i]), rxevent_nFree++;
225 #endif
226     }
227
228     /* Grab and initialize a new rxevent structure */
229     ev = queue_First(&rxevent_free, rxevent);
230     queue_Remove(ev);
231     rxevent_nFree--;
232
233     /* Record user defined event state */
234     ev->eventTime = *when;
235     ev->func = func;
236     ev->arg = arg;
237     ev->arg1 = arg1;
238     rxevent_nPosted += 1; /* Rather than ++, to shut high-C up
239                            *  regarding never-set variables
240                            */
241
242     /* Insert the event into the sorted list of events for this epoch */
243     for (queue_ScanBackwards(&ep->events, evqe, evqpr, rxevent)) {
244         if (when->usec >= evqe->eventTime.usec) {
245             /* Insert event after evqe */
246             queue_InsertAfter(evqe, ev);
247             MUTEX_EXIT(&rxevent_lock);
248             return ev;
249         }
250     }
251     /* Insert event at head of current epoch */
252     queue_Prepend(&ep->events, ev);
253     if (isEarliest && rxevent_ScheduledEarlierEvent &&
254         (!rxevent_raiseScheduled ||
255          clock_Lt(&ev->eventTime, &rxevent_nextRaiseEvents))) {
256         rxevent_raiseScheduled = 1;
257         clock_Zero(&rxevent_nextRaiseEvents);
258         MUTEX_EXIT(&rxevent_lock);
259         /* Notify our external scheduler */
260         (*rxevent_ScheduledEarlierEvent)();
261         MUTEX_ENTER(&rxevent_lock);
262     }
263     MUTEX_EXIT(&rxevent_lock);
264     return ev;
265 }
266
267 /* Cancel an event by moving it from the event queue to the free list.
268  * Warning, the event must be on the event queue!  If not, this should core
269  * dump (reference through 0).  This routine should be called using the macro
270  * event_Cancel, which checks for a null event and also nulls the caller's
271  * event pointer after cancelling the event.
272  */
273 #ifdef RX_ENABLE_LOCKS
274 #ifdef RX_REFCOUNT_CHECK
275 int rxevent_Cancel_type = 0;
276 void rxevent_Cancel_1(ev, call, type)
277     register struct rxevent *ev;
278     register struct rx_call *call;
279     register int type;
280 #else /* RX_REFCOUNT_CHECK */
281 void rxevent_Cancel_1(ev, call)
282     register struct rxevent *ev;
283     register struct rx_call *call;
284 #endif /* RX_REFCOUNT_CHECK */
285 #else  /* RX_ENABLE_LOCKS */
286 void rxevent_Cancel_1(ev)
287     register struct rxevent *ev;
288 #endif /* RX_ENABLE_LOCKS */
289 {
290 #ifdef RXDEBUG
291     if (rx_Log_event) {
292         struct clock now;
293         clock_GetTime(&now);
294         fprintf(rx_Log_event, "%d.%d: rxevent_Cancel_1(%d.%d, %x, %x)\n", now.sec,
295                 now.usec, ev->eventTime.sec, ev->eventTime.usec, ev->func,
296                 ev->arg);
297     }
298 #endif
299     /* Append it to the free list (rather than prepending) to keep the free
300      * list hot so nothing pages out
301      */
302     AFS_ASSERT_RXGLOCK();
303     MUTEX_ENTER(&rxevent_lock);
304     if (!ev) {
305         MUTEX_EXIT(&rxevent_lock);
306         return;
307     }
308 #ifdef RX_ENABLE_LOCKS
309     /* It's possible we're currently processing this event. */
310     if (queue_IsOnQueue(ev)) {
311         queue_MoveAppend(&rxevent_free, ev);
312         rxevent_nPosted--;
313         rxevent_nFree++;
314         if (call) {
315             call->refCount--;
316 #ifdef RX_REFCOUNT_CHECK
317             call->refCDebug[type]--;
318             if (call->refCDebug[type]<0) {
319                 rxevent_Cancel_type = type;
320                 osi_Panic("rxevent_Cancel: call refCount < 0");
321             }
322 #endif /* RX_REFCOUNT_CHECK */
323         }
324     }
325 #else /* RX_ENABLE_LOCKS */
326     queue_MoveAppend(&rxevent_free, ev);
327     rxevent_nPosted--;
328     rxevent_nFree++;
329 #endif /* RX_ENABLE_LOCKS */
330     MUTEX_EXIT(&rxevent_lock);
331 }
332
333 /* Process all epochs that have expired relative to the current clock time
334  * (which is not re-evaluated unless clock_NewTime has been called).  The
335  * relative time to the next epoch is returned in the output parameter next
336  * and the function returns 1.  If there are is no next epoch, the function
337  * returns 0.
338  */
339 int rxevent_RaiseEvents(next)
340     struct clock *next;
341 {
342     register struct rxepoch *ep;
343     register struct rxevent *ev;
344     struct clock now;
345
346     MUTEX_ENTER(&rxevent_lock);
347
348     AFS_ASSERT_RXGLOCK();
349
350     /* Events are sorted by time, so only scan until an event is found that has
351      * not yet timed out */
352
353     clock_Zero(&now);
354     while (queue_IsNotEmpty(&rxepoch_queue)) {
355         ep = queue_First(&rxepoch_queue, rxepoch);
356         if (queue_IsEmpty(&ep->events)) {
357             queue_Remove(ep);
358             queue_Append(&rxepoch_free, ep);
359             rxepoch_nFree++;
360             continue;
361         }
362         do {
363             ev = queue_First(&ep->events, rxevent);
364             if (clock_Lt(&now, &ev->eventTime)) {
365                 clock_GetTime(&now);
366                 if (clock_Lt(&now, &ev->eventTime)) {
367                     *next = rxevent_nextRaiseEvents = ev->eventTime;
368                     rxevent_raiseScheduled = 1;
369                     clock_Sub(next, &now);
370                     MUTEX_EXIT(&rxevent_lock);
371                     return 1;
372                 }
373             }
374             queue_Remove(ev);
375             rxevent_nPosted--;
376             MUTEX_EXIT(&rxevent_lock);
377             ev->func(ev, ev->arg, ev->arg1);
378             MUTEX_ENTER(&rxevent_lock);
379             queue_Append(&rxevent_free, ev);
380             rxevent_nFree++;
381         } while (queue_IsNotEmpty(&ep->events));
382     }
383 #ifdef RXDEBUG
384     if (rx_Log_event) fprintf(rx_Log_event, "rxevent_RaiseEvents(%d.%d)\n", now.sec, now.usec);
385 #endif
386     rxevent_raiseScheduled = 0;
387     MUTEX_EXIT(&rxevent_lock);
388     return 0;
389 }
390
391 void shutdown_rxevent(void) 
392 {
393     struct xfreelist *xp, *nxp;
394
395     LOCK_EV_INIT
396     if (!rxevent_initialized) {
397         UNLOCK_EV_INIT
398         return;
399     }
400     rxevent_initialized = 0;
401     UNLOCK_EV_INIT
402     MUTEX_DESTROY(&rxevent_lock);
403 #if     defined(AFS_AIX32_ENV) && defined(KERNEL)
404     /* Everything is freed in afs_osinet.c */
405 #else
406     xp = xfreemallocs;
407     while (xp) {
408         nxp = xp->next;
409         osi_Free((char *)xp->mem, xp->size);
410         osi_Free((char *)xp, sizeof(struct xfreelist));
411         xp = nxp;
412     }
413 #endif
414
415 }