2 * Copyright 2000, International Business Machines Corporation and others.
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
10 #include <afsconfig.h>
12 #include "afs/param.h"
14 #include <afs/param.h>
18 #include <sys/time_impl.h>
25 #include "afs/afs_osi.h"
27 #include "afs/sysincludes.h"
28 #include "afsincludes.h"
30 #include "rx/rx_clock.h"
31 #include "rx/rx_queue.h"
32 #include "rx/rx_event.h"
33 #include "rx/rx_kernel.h"
34 #include "rx_kmutex.h"
35 #ifdef RX_ENABLE_LOCKS
37 #endif /* RX_ENABLE_LOCKS */
38 #include "rx/rx_globals.h"
39 #if defined(AFS_SGI_ENV)
40 #include "sys/debug.h"
41 /* These are necessary to get curproc (used by GLOCK asserts) to work. */
43 #if !defined(AFS_SGI64_ENV) && !defined(UKERNEL)
46 extern void *osi_Alloc();
54 #ifdef AFS_PTHREAD_ENV
55 #include <rx/rx_pthread.h>
59 #ifdef RX_ENABLE_LOCKS
61 #endif /* RX_ENABLE_LOCKS */
62 #include "rx_globals.h"
69 /* All event processing is relative to the apparent current time given by clock_GetTime */
71 /* This should be static, but event_test wants to look at the free list... */
72 struct rx_queue rxevent_free; /* It's somewhat bogus to use a doubly-linked queue for the free list */
73 struct rx_queue rxepoch_free; /* It's somewhat bogus to use a doubly-linked queue for the free list */
74 static struct rx_queue rxepoch_queue; /* list of waiting epochs */
75 static int rxevent_allocUnit = 10; /* Allocation unit (number of event records to allocate at one time) */
76 static int rxepoch_allocUnit = 10; /* Allocation unit (number of epoch records to allocate at one time) */
77 int rxevent_nFree; /* Number of free event records */
78 int rxevent_nPosted; /* Current number of posted events */
79 int rxepoch_nFree; /* Number of free epoch records */
80 static int (*rxevent_ScheduledEarlierEvent)(void); /* Proc to call when an event is scheduled that is earlier than all other events */
84 struct xfreelist *next;
86 static struct xfreelist *xfreemallocs = 0, *xsp = 0;
88 struct clock rxevent_nextRaiseEvents; /* Time of next call to raise events */
89 int rxevent_raiseScheduled; /* true if raise events is scheduled */
91 #ifdef RX_ENABLE_LOCKS
93 /* rxdb_fileID is used to identify the lock location, along with line#. */
94 static int rxdb_fileID = RXDB_FILE_RX_EVENT;
95 #endif /* RX_LOCKS_DB */
96 #define RX_ENABLE_LOCKS 1
97 afs_kmutex_t rxevent_lock;
98 #endif /* RX_ENABLE_LOCKS */
100 #ifdef AFS_PTHREAD_ENV
102 * This mutex protects the following global variables:
103 * rxevent_initialized
107 pthread_mutex_t rx_event_mutex;
108 #define LOCK_EV_INIT assert(pthread_mutex_lock(&rx_event_mutex)==0);
109 #define UNLOCK_EV_INIT assert(pthread_mutex_unlock(&rx_event_mutex)==0);
112 #define UNLOCK_EV_INIT
113 #endif /* AFS_PTHREAD_ENV */
116 /* Pass in the number of events to allocate at a time */
117 int rxevent_initialized = 0;
118 void rxevent_Init(int nEvents, void (*scheduler)(void))
121 if (rxevent_initialized) {
125 MUTEX_INIT(&rxevent_lock, "rxevent_lock", MUTEX_DEFAULT, 0);
127 if (nEvents) rxevent_allocUnit = nEvents;
128 queue_Init(&rxevent_free);
129 queue_Init(&rxepoch_free);
130 queue_Init(&rxepoch_queue);
131 rxevent_nFree = rxevent_nPosted = 0;
133 rxevent_ScheduledEarlierEvent = scheduler;
134 rxevent_initialized = 1;
135 clock_Zero(&rxevent_nextRaiseEvents);
136 rxevent_raiseScheduled = 0;
140 /* Create and initialize new epoch structure */
141 struct rxepoch *rxepoch_Allocate(struct clock *when)
146 /* If we are short on free epoch entries, create a block of new oned
147 * and add them to the free queue */
148 if (queue_IsEmpty(&rxepoch_free)) {
149 #if defined(AFS_AIX32_ENV) && defined(KERNEL)
150 ep = (struct rxepoch *) rxi_Alloc(sizeof(struct rxepoch));
151 queue_Append(&rxepoch_free, &ep[0]), rxepoch_nFree++;
153 ep = (struct rxepoch *)
154 osi_Alloc(sizeof(struct rxepoch) * rxepoch_allocUnit);
156 xfreemallocs = (struct xfreelist *) osi_Alloc(sizeof(struct xfreelist));
157 xfreemallocs->mem = (void *)ep;
158 xfreemallocs->size = sizeof(struct rxepoch) * rxepoch_allocUnit;
159 xfreemallocs->next = xsp;
160 for (i = 0; i<rxepoch_allocUnit; i++)
161 queue_Append(&rxepoch_free, &ep[i]), rxepoch_nFree++;
164 ep = queue_First(&rxepoch_free, rxepoch);
167 ep->epochSec = when->sec;
168 queue_Init(&ep->events);
172 /* Add the indicated event (function, arg) at the specified clock time. The
173 * "when" argument specifies when "func" should be called, in clock (clock.h)
177 struct rxevent *rxevent_Post(struct clock *when,
178 void (*func)(struct rxevent *event,
179 struct rx_connection *conn, struct rx_call *acall),
180 void *arg, void *arg1)
182 struct rxevent *rxevent_Post(struct clock *when,
184 void *arg, void *arg1)
187 register struct rxevent *ev, *evqe, *evqpr;
188 register struct rxepoch *ep, *epqe, *epqpr;
191 MUTEX_ENTER(&rxevent_lock);
192 AFS_ASSERT_RXGLOCK();
197 fprintf(rx_Log_event, "%d.%d: rxevent_Post(%d.%d, %x, %x)\n",
198 (int) now.sec, (int) now.usec, (int) when->sec,
199 (int) when->usec, (unsigned int) func, (unsigned int) arg);
203 /* Get a pointer to the epoch for this event, if none is found then
204 * create a new epoch and insert it into the sorted list */
205 for (ep = NULL, queue_ScanBackwards(&rxepoch_queue, epqe, epqpr, rxepoch)) {
206 if (when->sec == epqe->epochSec) {
207 /* already have an structure for this epoch */
209 if (ep == queue_First(&rxepoch_queue, rxepoch))
212 } else if (when->sec > epqe->epochSec) {
213 /* Create a new epoch and insert after qe */
214 ep = rxepoch_Allocate(when);
215 queue_InsertAfter(epqe, ep);
220 /* Create a new epoch and place it at the head of the list */
221 ep = rxepoch_Allocate(when);
222 queue_Prepend(&rxepoch_queue, ep);
226 /* If we're short on free event entries, create a block of new ones and add
227 * them to the free queue */
228 if (queue_IsEmpty(&rxevent_free)) {
230 #if defined(AFS_AIX32_ENV) && defined(KERNEL)
231 ev = (struct rxevent *) rxi_Alloc(sizeof(struct rxevent));
232 queue_Append(&rxevent_free, &ev[0]), rxevent_nFree++;
234 ev = (struct rxevent *) osi_Alloc(sizeof(struct rxevent) * rxevent_allocUnit);
236 xfreemallocs = (struct xfreelist *) osi_Alloc(sizeof(struct xfreelist));
237 xfreemallocs->mem = (void *)ev;
238 xfreemallocs->size = sizeof(struct rxevent) * rxevent_allocUnit;
239 xfreemallocs->next = xsp;
240 for (i = 0; i<rxevent_allocUnit; i++)
241 queue_Append(&rxevent_free, &ev[i]), rxevent_nFree++;
245 /* Grab and initialize a new rxevent structure */
246 ev = queue_First(&rxevent_free, rxevent);
250 /* Record user defined event state */
251 ev->eventTime = *when;
255 rxevent_nPosted += 1; /* Rather than ++, to shut high-C up
256 * regarding never-set variables
259 /* Insert the event into the sorted list of events for this epoch */
260 for (queue_ScanBackwards(&ep->events, evqe, evqpr, rxevent)) {
261 if (when->usec >= evqe->eventTime.usec) {
262 /* Insert event after evqe */
263 queue_InsertAfter(evqe, ev);
264 MUTEX_EXIT(&rxevent_lock);
268 /* Insert event at head of current epoch */
269 queue_Prepend(&ep->events, ev);
270 if (isEarliest && rxevent_ScheduledEarlierEvent &&
271 (!rxevent_raiseScheduled ||
272 clock_Lt(&ev->eventTime, &rxevent_nextRaiseEvents))) {
273 rxevent_raiseScheduled = 1;
274 clock_Zero(&rxevent_nextRaiseEvents);
275 MUTEX_EXIT(&rxevent_lock);
276 /* Notify our external scheduler */
277 (*rxevent_ScheduledEarlierEvent)();
278 MUTEX_ENTER(&rxevent_lock);
280 MUTEX_EXIT(&rxevent_lock);
284 /* Cancel an event by moving it from the event queue to the free list.
285 * Warning, the event must be on the event queue! If not, this should core
286 * dump (reference through 0). This routine should be called using the macro
287 * event_Cancel, which checks for a null event and also nulls the caller's
288 * event pointer after cancelling the event.
290 #ifdef RX_ENABLE_LOCKS
291 #ifdef RX_REFCOUNT_CHECK
292 int rxevent_Cancel_type = 0;
296 void rxevent_Cancel_1(register struct rxevent *ev,
297 register struct rx_call *call, register int type)
303 fprintf(rx_Log_event, "%d.%d: rxevent_Cancel_1(%d.%d, %x, %x)\n",
304 (int) now.sec, (int) now.usec, (int) ev->eventTime.sec,
305 (int) ev->eventTime.usec, (unsigned int) ev->func,
306 (unsigned int) ev->arg);
309 /* Append it to the free list (rather than prepending) to keep the free
310 * list hot so nothing pages out
312 AFS_ASSERT_RXGLOCK();
313 MUTEX_ENTER(&rxevent_lock);
315 MUTEX_EXIT(&rxevent_lock);
318 #ifdef RX_ENABLE_LOCKS
319 /* It's possible we're currently processing this event. */
320 if (queue_IsOnQueue(ev)) {
321 queue_MoveAppend(&rxevent_free, ev);
326 #ifdef RX_REFCOUNT_CHECK
327 call->refCDebug[type]--;
328 if (call->refCDebug[type]<0) {
329 rxevent_Cancel_type = type;
330 osi_Panic("rxevent_Cancel: call refCount < 0");
332 #endif /* RX_REFCOUNT_CHECK */
335 #else /* RX_ENABLE_LOCKS */
336 queue_MoveAppend(&rxevent_free, ev);
339 #endif /* RX_ENABLE_LOCKS */
340 MUTEX_EXIT(&rxevent_lock);
343 /* Process all epochs that have expired relative to the current clock time
344 * (which is not re-evaluated unless clock_NewTime has been called). The
345 * relative time to the next epoch is returned in the output parameter next
346 * and the function returns 1. If there are is no next epoch, the function
349 int rxevent_RaiseEvents(struct clock *next)
351 register struct rxepoch *ep;
352 register struct rxevent *ev;
353 volatile struct clock now;
355 MUTEX_ENTER(&rxevent_lock);
357 AFS_ASSERT_RXGLOCK();
359 /* Events are sorted by time, so only scan until an event is found that has
360 * not yet timed out */
363 while (queue_IsNotEmpty(&rxepoch_queue)) {
364 ep = queue_First(&rxepoch_queue, rxepoch);
365 if (queue_IsEmpty(&ep->events)) {
367 queue_Append(&rxepoch_free, ep);
372 ev = queue_First(&ep->events, rxevent);
373 if (clock_Lt(&now, &ev->eventTime)) {
375 if (clock_Lt(&now, &ev->eventTime)) {
376 *next = rxevent_nextRaiseEvents = ev->eventTime;
377 rxevent_raiseScheduled = 1;
378 clock_Sub(next, &now);
379 MUTEX_EXIT(&rxevent_lock);
385 MUTEX_EXIT(&rxevent_lock);
386 ev->func(ev, ev->arg, ev->arg1);
387 MUTEX_ENTER(&rxevent_lock);
388 queue_Append(&rxevent_free, ev);
390 } while (queue_IsNotEmpty(&ep->events));
393 if (rx_Log_event) fprintf(rx_Log_event, "rxevent_RaiseEvents(%d.%d)\n",
394 (int) now.sec, (int) now.usec);
396 rxevent_raiseScheduled = 0;
397 MUTEX_EXIT(&rxevent_lock);
401 void shutdown_rxevent(void)
403 struct xfreelist *xp, *nxp;
406 if (!rxevent_initialized) {
410 rxevent_initialized = 0;
412 MUTEX_DESTROY(&rxevent_lock);
413 #if defined(AFS_AIX32_ENV) && defined(KERNEL)
414 /* Everything is freed in afs_osinet.c */
419 osi_Free((char *)xp->mem, xp->size);
420 osi_Free((char *)xp, sizeof(struct xfreelist));