rx-warning-cleanup-and-afsconfig-20010612
[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     int isEarliest = 0;
174
175     MUTEX_ENTER(&rxevent_lock);
176     AFS_ASSERT_RXGLOCK();
177 #ifdef RXDEBUG
178     if (rx_Log_event) {
179         struct clock now;
180         clock_GetTime(&now);
181         fprintf(rx_Log_event, "%d.%d: rxevent_Post(%d.%d, %x, %x)\n", now.sec, now.usec, when->sec, when->usec, func, arg);
182     }
183 #endif
184
185     /* Get a pointer to the epoch for this event, if none is found then
186      * create a new epoch and insert it into the sorted list */
187     for (ep = NULL, queue_ScanBackwards(&rxepoch_queue, epqe, epqpr, rxepoch)) {
188         if (when->sec == epqe->epochSec) {
189             /* already have an structure for this epoch */
190             ep = epqe;
191             if (ep == queue_First(&rxepoch_queue, rxepoch))
192                 isEarliest = 1;
193             break;
194         } else if (when->sec > epqe->epochSec) {
195             /* Create a new epoch and insert after qe */
196             ep = rxepoch_Allocate(when);
197             queue_InsertAfter(epqe, ep);
198             break;
199         }
200     }
201     if (ep == NULL) {
202         /* Create a new epoch and place it at the head of the list */
203         ep = rxepoch_Allocate(when);
204         queue_Prepend(&rxepoch_queue, ep);
205         isEarliest = 1;
206     }
207
208     /* If we're short on free event entries, create a block of new ones and add
209      * them to the free queue */
210     if (queue_IsEmpty(&rxevent_free)) {
211         register int i;
212 #if     defined(AFS_AIX32_ENV) && defined(KERNEL)
213         ev = (struct rxevent *) rxi_Alloc(sizeof(struct rxevent));
214         queue_Append(&rxevent_free, &ev[0]), rxevent_nFree++;
215 #else
216         ev = (struct rxevent *) osi_Alloc(sizeof(struct rxevent) * rxevent_allocUnit);
217         xsp = xfreemallocs;
218         xfreemallocs = (struct xfreelist *) osi_Alloc(sizeof(struct xfreelist));
219         xfreemallocs->mem = (void *)ev;
220         xfreemallocs->size = sizeof(struct rxevent) * rxevent_allocUnit;
221         xfreemallocs->next = xsp;
222         for (i = 0; i<rxevent_allocUnit; i++)
223             queue_Append(&rxevent_free, &ev[i]), rxevent_nFree++;
224 #endif
225     }
226
227     /* Grab and initialize a new rxevent structure */
228     ev = queue_First(&rxevent_free, rxevent);
229     queue_Remove(ev);
230     rxevent_nFree--;
231
232     /* Record user defined event state */
233     ev->eventTime = *when;
234     ev->func = func;
235     ev->arg = arg;
236     ev->arg1 = arg1;
237     rxevent_nPosted += 1; /* Rather than ++, to shut high-C up
238                            *  regarding never-set variables
239                            */
240
241     /* Insert the event into the sorted list of events for this epoch */
242     for (queue_ScanBackwards(&ep->events, evqe, evqpr, rxevent)) {
243         if (when->usec >= evqe->eventTime.usec) {
244             /* Insert event after evqe */
245             queue_InsertAfter(evqe, ev);
246             MUTEX_EXIT(&rxevent_lock);
247             return ev;
248         }
249     }
250     /* Insert event at head of current epoch */
251     queue_Prepend(&ep->events, ev);
252     if (isEarliest && rxevent_ScheduledEarlierEvent &&
253         (!rxevent_raiseScheduled ||
254          clock_Lt(&ev->eventTime, &rxevent_nextRaiseEvents))) {
255         rxevent_raiseScheduled = 1;
256         clock_Zero(&rxevent_nextRaiseEvents);
257         MUTEX_EXIT(&rxevent_lock);
258         /* Notify our external scheduler */
259         (*rxevent_ScheduledEarlierEvent)();
260         MUTEX_ENTER(&rxevent_lock);
261     }
262     MUTEX_EXIT(&rxevent_lock);
263     return ev;
264 }
265
266 /* Cancel an event by moving it from the event queue to the free list.
267  * Warning, the event must be on the event queue!  If not, this should core
268  * dump (reference through 0).  This routine should be called using the macro
269  * event_Cancel, which checks for a null event and also nulls the caller's
270  * event pointer after cancelling the event.
271  */
272 #ifdef RX_ENABLE_LOCKS
273 #ifdef RX_REFCOUNT_CHECK
274 int rxevent_Cancel_type = 0;
275 void rxevent_Cancel_1(ev, call, type)
276     register struct rxevent *ev;
277     register struct rx_call *call;
278     register int type;
279 #else /* RX_REFCOUNT_CHECK */
280 void rxevent_Cancel_1(ev, call)
281     register struct rxevent *ev;
282     register struct rx_call *call;
283 #endif /* RX_REFCOUNT_CHECK */
284 #else  /* RX_ENABLE_LOCKS */
285 void rxevent_Cancel_1(ev)
286     register struct rxevent *ev;
287 #endif /* RX_ENABLE_LOCKS */
288 {
289 #ifdef RXDEBUG
290     if (rx_Log_event) {
291         struct clock now;
292         clock_GetTime(&now);
293         fprintf(rx_Log_event, "%d.%d: rxevent_Cancel_1(%d.%d, %x, %x)\n", now.sec,
294                 now.usec, ev->eventTime.sec, ev->eventTime.usec, ev->func,
295                 ev->arg);
296     }
297 #endif
298     /* Append it to the free list (rather than prepending) to keep the free
299      * list hot so nothing pages out
300      */
301     AFS_ASSERT_RXGLOCK();
302     MUTEX_ENTER(&rxevent_lock);
303     if (!ev) {
304         MUTEX_EXIT(&rxevent_lock);
305         return;
306     }
307 #ifdef RX_ENABLE_LOCKS
308     /* It's possible we're currently processing this event. */
309     if (queue_IsOnQueue(ev)) {
310         queue_MoveAppend(&rxevent_free, ev);
311         rxevent_nPosted--;
312         rxevent_nFree++;
313         if (call) {
314             call->refCount--;
315 #ifdef RX_REFCOUNT_CHECK
316             call->refCDebug[type]--;
317             if (call->refCDebug[type]<0) {
318                 rxevent_Cancel_type = type;
319                 osi_Panic("rxevent_Cancel: call refCount < 0");
320             }
321 #endif /* RX_REFCOUNT_CHECK */
322         }
323     }
324 #else /* RX_ENABLE_LOCKS */
325     queue_MoveAppend(&rxevent_free, ev);
326     rxevent_nPosted--;
327     rxevent_nFree++;
328 #endif /* RX_ENABLE_LOCKS */
329     MUTEX_EXIT(&rxevent_lock);
330 }
331
332 /* Process all epochs that have expired relative to the current clock time
333  * (which is not re-evaluated unless clock_NewTime has been called).  The
334  * relative time to the next epoch is returned in the output parameter next
335  * and the function returns 1.  If there are is no next epoch, the function
336  * returns 0.
337  */
338 int rxevent_RaiseEvents(next)
339     struct clock *next;
340 {
341     register struct rxepoch *ep;
342     register struct rxevent *ev;
343     struct clock now;
344
345     MUTEX_ENTER(&rxevent_lock);
346
347     AFS_ASSERT_RXGLOCK();
348
349     /* Events are sorted by time, so only scan until an event is found that has
350      * not yet timed out */
351
352     clock_Zero(&now);
353     while (queue_IsNotEmpty(&rxepoch_queue)) {
354         ep = queue_First(&rxepoch_queue, rxepoch);
355         if (queue_IsEmpty(&ep->events)) {
356             queue_Remove(ep);
357             queue_Append(&rxepoch_free, ep);
358             rxepoch_nFree++;
359             continue;
360         }
361         do {
362             ev = queue_First(&ep->events, rxevent);
363             if (clock_Lt(&now, &ev->eventTime)) {
364                 clock_GetTime(&now);
365                 if (clock_Lt(&now, &ev->eventTime)) {
366                     *next = rxevent_nextRaiseEvents = ev->eventTime;
367                     rxevent_raiseScheduled = 1;
368                     clock_Sub(next, &now);
369                     MUTEX_EXIT(&rxevent_lock);
370                     return 1;
371                 }
372             }
373             queue_Remove(ev);
374             rxevent_nPosted--;
375             MUTEX_EXIT(&rxevent_lock);
376             ev->func(ev, ev->arg, ev->arg1);
377             MUTEX_ENTER(&rxevent_lock);
378             queue_Append(&rxevent_free, ev);
379             rxevent_nFree++;
380         } while (queue_IsNotEmpty(&ep->events));
381     }
382 #ifdef RXDEBUG
383     if (rx_Log_event) fprintf(rx_Log_event, "rxevent_RaiseEvents(%d.%d)\n", now.sec, now.usec);
384 #endif
385     rxevent_raiseScheduled = 0;
386     MUTEX_EXIT(&rxevent_lock);
387     return 0;
388 }
389
390 void shutdown_rxevent(void) 
391 {
392     struct xfreelist *xp, *nxp;
393
394     LOCK_EV_INIT
395     if (!rxevent_initialized) {
396         UNLOCK_EV_INIT
397         return;
398     }
399     rxevent_initialized = 0;
400     UNLOCK_EV_INIT
401     MUTEX_DESTROY(&rxevent_lock);
402 #if     defined(AFS_AIX32_ENV) && defined(KERNEL)
403     /* Everything is freed in afs_osinet.c */
404 #else
405     xp = xfreemallocs;
406     while (xp) {
407         nxp = xp->next;
408         osi_Free((char *)xp->mem, xp->size);
409         osi_Free((char *)xp, sizeof(struct xfreelist));
410         xp = nxp;
411     }
412 #endif
413
414 }