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>
26 #include "afs/afs_osi.h"
28 #include "afs/sysincludes.h"
29 #include "afsincludes.h"
31 #include "rx/rx_clock.h"
32 #include "rx/rx_queue.h"
33 #include "rx/rx_event.h"
34 #include "rx/rx_kernel.h"
35 #include "rx_kmutex.h"
36 #ifdef RX_ENABLE_LOCKS
38 #endif /* RX_ENABLE_LOCKS */
39 #include "rx/rx_globals.h"
40 #if defined(AFS_SGI_ENV)
41 #include "sys/debug.h"
42 /* These are necessary to get curproc (used by GLOCK asserts) to work. */
44 #if !defined(AFS_SGI64_ENV) && !defined(UKERNEL)
47 extern void *osi_Alloc();
49 #if defined(AFS_OBSD_ENV)
58 #ifdef AFS_PTHREAD_ENV
59 #include <rx/rx_pthread.h>
63 #ifdef RX_ENABLE_LOCKS
65 #endif /* RX_ENABLE_LOCKS */
66 #include "rx_globals.h"
73 /* All event processing is relative to the apparent current time given by clock_GetTime */
75 /* This should be static, but event_test wants to look at the free list... */
76 struct rx_queue rxevent_free; /* It's somewhat bogus to use a doubly-linked queue for the free list */
77 struct rx_queue rxepoch_free; /* It's somewhat bogus to use a doubly-linked queue for the free list */
78 static struct rx_queue rxepoch_queue; /* list of waiting epochs */
79 static int rxevent_allocUnit = 10; /* Allocation unit (number of event records to allocate at one time) */
80 static int rxepoch_allocUnit = 10; /* Allocation unit (number of epoch records to allocate at one time) */
81 int rxevent_nFree; /* Number of free event records */
82 int rxevent_nPosted; /* Current number of posted events */
83 int rxepoch_nFree; /* Number of free epoch records */
84 static void (*rxevent_ScheduledEarlierEvent) (void); /* Proc to call when an event is scheduled that is earlier than all other events */
88 struct xfreelist *next;
90 static struct xfreelist *xfreemallocs = 0, *xsp = 0;
92 struct clock rxevent_nextRaiseEvents; /* Time of next call to raise events */
93 int rxevent_raiseScheduled; /* true if raise events is scheduled */
95 #ifdef RX_ENABLE_LOCKS
97 /* rxdb_fileID is used to identify the lock location, along with line#. */
98 static int rxdb_fileID = RXDB_FILE_RX_EVENT;
99 #endif /* RX_LOCKS_DB */
100 #define RX_ENABLE_LOCKS 1
101 afs_kmutex_t rxevent_lock;
102 #endif /* RX_ENABLE_LOCKS */
104 #ifdef AFS_PTHREAD_ENV
106 * This mutex protects the following global variables:
107 * rxevent_initialized
111 pthread_mutex_t rx_event_mutex;
112 #define LOCK_EV_INIT assert(pthread_mutex_lock(&rx_event_mutex)==0)
113 #define UNLOCK_EV_INIT assert(pthread_mutex_unlock(&rx_event_mutex)==0)
116 #define UNLOCK_EV_INIT
117 #endif /* AFS_PTHREAD_ENV */
120 /* Pass in the number of events to allocate at a time */
121 int rxevent_initialized = 0;
123 rxevent_Init(int nEvents, void (*scheduler) (void))
126 if (rxevent_initialized) {
130 MUTEX_INIT(&rxevent_lock, "rxevent_lock", MUTEX_DEFAULT, 0);
133 rxevent_allocUnit = nEvents;
134 queue_Init(&rxevent_free);
135 queue_Init(&rxepoch_free);
136 queue_Init(&rxepoch_queue);
137 rxevent_nFree = rxevent_nPosted = 0;
139 rxevent_ScheduledEarlierEvent = scheduler;
140 rxevent_initialized = 1;
141 clock_Zero(&rxevent_nextRaiseEvents);
142 rxevent_raiseScheduled = 0;
146 /* Create and initialize new epoch structure */
148 rxepoch_Allocate(struct clock *when)
153 /* If we are short on free epoch entries, create a block of new oned
154 * and add them to the free queue */
155 if (queue_IsEmpty(&rxepoch_free)) {
156 #if defined(AFS_AIX32_ENV) && defined(KERNEL)
157 ep = (struct rxepoch *)rxi_Alloc(sizeof(struct rxepoch));
158 queue_Append(&rxepoch_free, &ep[0]), rxepoch_nFree++;
160 ep = (struct rxepoch *)
161 osi_Alloc(sizeof(struct rxepoch) * rxepoch_allocUnit);
164 (struct xfreelist *)osi_Alloc(sizeof(struct xfreelist));
165 xfreemallocs->mem = (void *)ep;
166 xfreemallocs->size = sizeof(struct rxepoch) * rxepoch_allocUnit;
167 xfreemallocs->next = xsp;
168 for (i = 0; i < rxepoch_allocUnit; i++)
169 queue_Append(&rxepoch_free, &ep[i]), rxepoch_nFree++;
172 ep = queue_First(&rxepoch_free, rxepoch);
175 ep->epochSec = when->sec;
176 queue_Init(&ep->events);
180 /* Add the indicated event (function, arg) at the specified clock time. The
181 * "when" argument specifies when "func" should be called, in clock (clock.h)
186 rxevent_Post(struct clock *when,
187 void (*func) (struct rxevent * event,
188 struct rx_connection * conn,
189 struct rx_call * acall), void *arg, void *arg1)
191 static struct rxevent *
192 _rxevent_Post(struct clock *when, void (*func) (), void *arg, void *arg1,
193 int arg2, int newargs)
196 register struct rxevent *ev, *evqe, *evqpr;
197 register struct rxepoch *ep, *epqe, *epqpr;
200 MUTEX_ENTER(&rxevent_lock);
201 AFS_ASSERT_RXGLOCK();
206 fprintf(rx_Log_event, "%d.%d: rxevent_Post(%d.%d, %lx, %lx, %lx, %d)\n",
207 (int)now.sec, (int)now.usec, (int)when->sec, (int)when->usec,
208 (unsigned long)func, (unsigned long)arg,
209 (unsigned long)arg1, arg2);
213 /* Get a pointer to the epoch for this event, if none is found then
214 * create a new epoch and insert it into the sorted list */
215 for (ep = NULL, queue_ScanBackwards(&rxepoch_queue, epqe, epqpr, rxepoch)) {
216 if (when->sec == epqe->epochSec) {
217 /* already have an structure for this epoch */
219 if (ep == queue_First(&rxepoch_queue, rxepoch))
222 } else if (when->sec > epqe->epochSec) {
223 /* Create a new epoch and insert after qe */
224 ep = rxepoch_Allocate(when);
225 queue_InsertAfter(epqe, ep);
230 /* Create a new epoch and place it at the head of the list */
231 ep = rxepoch_Allocate(when);
232 queue_Prepend(&rxepoch_queue, ep);
236 /* If we're short on free event entries, create a block of new ones and add
237 * them to the free queue */
238 if (queue_IsEmpty(&rxevent_free)) {
240 #if defined(AFS_AIX32_ENV) && defined(KERNEL)
241 ev = (struct rxevent *)rxi_Alloc(sizeof(struct rxevent));
242 queue_Append(&rxevent_free, &ev[0]), rxevent_nFree++;
244 ev = (struct rxevent *)osi_Alloc(sizeof(struct rxevent) *
248 (struct xfreelist *)osi_Alloc(sizeof(struct xfreelist));
249 xfreemallocs->mem = (void *)ev;
250 xfreemallocs->size = sizeof(struct rxevent) * rxevent_allocUnit;
251 xfreemallocs->next = xsp;
252 for (i = 0; i < rxevent_allocUnit; i++)
253 queue_Append(&rxevent_free, &ev[i]), rxevent_nFree++;
257 /* Grab and initialize a new rxevent structure */
258 ev = queue_First(&rxevent_free, rxevent);
262 /* Record user defined event state */
263 ev->eventTime = *when;
268 ev->newargs = newargs;
269 rxevent_nPosted += 1; /* Rather than ++, to shut high-C up
270 * regarding never-set variables
273 /* Insert the event into the sorted list of events for this epoch */
274 for (queue_ScanBackwards(&ep->events, evqe, evqpr, rxevent)) {
275 if (when->usec >= evqe->eventTime.usec) {
276 /* Insert event after evqe */
277 queue_InsertAfter(evqe, ev);
278 MUTEX_EXIT(&rxevent_lock);
282 /* Insert event at head of current epoch */
283 queue_Prepend(&ep->events, ev);
284 if (isEarliest && rxevent_ScheduledEarlierEvent
285 && (!rxevent_raiseScheduled
286 || clock_Lt(&ev->eventTime, &rxevent_nextRaiseEvents))) {
287 rxevent_raiseScheduled = 1;
288 clock_Zero(&rxevent_nextRaiseEvents);
289 MUTEX_EXIT(&rxevent_lock);
290 /* Notify our external scheduler */
291 (*rxevent_ScheduledEarlierEvent) ();
292 MUTEX_ENTER(&rxevent_lock);
294 MUTEX_EXIT(&rxevent_lock);
299 rxevent_Post(struct clock *when, void (*func) (), void *arg, void *arg1)
301 return _rxevent_Post(when, func, arg, arg1, 0, 0);
305 rxevent_Post2(struct clock *when, void (*func) (), void *arg, void *arg1,
308 return _rxevent_Post(when, func, arg, arg1, arg2, 1);
311 /* Cancel an event by moving it from the event queue to the free list.
312 * Warning, the event must be on the event queue! If not, this should core
313 * dump (reference through 0). This routine should be called using the macro
314 * event_Cancel, which checks for a null event and also nulls the caller's
315 * event pointer after cancelling the event.
317 #ifdef RX_ENABLE_LOCKS
318 #ifdef RX_REFCOUNT_CHECK
319 int rxevent_Cancel_type = 0;
324 rxevent_Cancel_1(register struct rxevent *ev, register struct rx_call *call,
331 fprintf(rx_Log_event, "%d.%d: rxevent_Cancel_1(%d.%d, %lx, %lx)\n",
332 (int)now.sec, (int)now.usec, (int)ev->eventTime.sec,
333 (int)ev->eventTime.usec, (unsigned long)ev->func,
334 (unsigned long)ev->arg);
337 /* Append it to the free list (rather than prepending) to keep the free
338 * list hot so nothing pages out
340 AFS_ASSERT_RXGLOCK();
341 MUTEX_ENTER(&rxevent_lock);
343 MUTEX_EXIT(&rxevent_lock);
346 #ifdef RX_ENABLE_LOCKS
347 /* It's possible we're currently processing this event. */
348 if (queue_IsOnQueue(ev)) {
349 queue_MoveAppend(&rxevent_free, ev);
354 #ifdef RX_REFCOUNT_CHECK
355 call->refCDebug[type]--;
356 if (call->refCDebug[type] < 0) {
357 rxevent_Cancel_type = type;
358 osi_Panic("rxevent_Cancel: call refCount < 0");
360 #endif /* RX_REFCOUNT_CHECK */
363 #else /* RX_ENABLE_LOCKS */
364 queue_MoveAppend(&rxevent_free, ev);
367 #endif /* RX_ENABLE_LOCKS */
368 MUTEX_EXIT(&rxevent_lock);
371 /* Process all epochs that have expired relative to the current clock time
372 * (which is not re-evaluated unless clock_NewTime has been called). The
373 * relative time to the next epoch is returned in the output parameter next
374 * and the function returns 1. If there are is no next epoch, the function
378 rxevent_RaiseEvents(struct clock *next)
380 register struct rxepoch *ep;
381 register struct rxevent *ev;
382 volatile struct clock now;
384 MUTEX_ENTER(&rxevent_lock);
386 AFS_ASSERT_RXGLOCK();
388 /* Events are sorted by time, so only scan until an event is found that has
389 * not yet timed out */
392 while (queue_IsNotEmpty(&rxepoch_queue)) {
393 ep = queue_First(&rxepoch_queue, rxepoch);
394 if (queue_IsEmpty(&ep->events)) {
396 queue_Append(&rxepoch_free, ep);
401 ev = queue_First(&ep->events, rxevent);
402 if (clock_Lt(&now, &ev->eventTime)) {
404 if (clock_Lt(&now, &ev->eventTime)) {
405 *next = rxevent_nextRaiseEvents = ev->eventTime;
406 rxevent_raiseScheduled = 1;
407 clock_Sub(next, &now);
408 MUTEX_EXIT(&rxevent_lock);
414 MUTEX_EXIT(&rxevent_lock);
416 ev->func(ev, ev->arg, ev->arg1, ev->arg2);
418 ev->func(ev, ev->arg, ev->arg1);
420 MUTEX_ENTER(&rxevent_lock);
421 queue_Append(&rxevent_free, ev);
423 } while (queue_IsNotEmpty(&ep->events));
427 fprintf(rx_Log_event, "rxevent_RaiseEvents(%d.%d)\n", (int)now.sec,
430 rxevent_raiseScheduled = 0;
431 MUTEX_EXIT(&rxevent_lock);
436 shutdown_rxevent(void)
438 struct xfreelist *xp, *nxp;
441 if (!rxevent_initialized) {
445 rxevent_initialized = 0;
447 MUTEX_DESTROY(&rxevent_lock);
448 #if defined(AFS_AIX32_ENV) && defined(KERNEL)
449 /* Everything is freed in afs_osinet.c */
454 osi_Free((char *)xp->mem, xp->size);
455 osi_Free((char *)xp, sizeof(struct xfreelist));