~ubuntu-branches/ubuntu/warty/openafs/warty

« back to all changes in this revision

Viewing changes to src/rx/rx_event.c

  • Committer: Bazaar Package Importer
  • Author(s): Sam Hartman
  • Date: 2004-01-10 16:37:33 UTC
  • Revision ID: james.westby@ubuntu.com-20040110163733-jvr0n1uahshlb1uu
Tags: upstream-1.2.11
ImportĀ upstreamĀ versionĀ 1.2.11

Show diffs side-by-side

added added

removed removed

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