OpenCores
URL https://opencores.org/ocsvn/openrisc_me/openrisc_me/trunk

Subversion Repositories openrisc_me

[/] [openrisc/] [trunk/] [rtos/] [ecos-2.0/] [packages/] [net/] [bsd_tcpip/] [v2_0/] [src/] [ecos/] [timeout.c] - Blame information for rev 174

Details | Compare with Previous | View Log

Line No. Rev Author Line
1 27 unneback
//==========================================================================
2
//
3
//      src/ecos/timeout.c
4
//
5
//==========================================================================
6
//####BSDCOPYRIGHTBEGIN####
7
//
8
// -------------------------------------------
9
//
10
// Portions of this software may have been derived from OpenBSD, 
11
// FreeBSD or other sources, and are covered by the appropriate
12
// copyright disclaimers included herein.
13
//
14
// Portions created by Red Hat are
15
// Copyright (C) 2002 Red Hat, Inc. All Rights Reserved.
16
//
17
// -------------------------------------------
18
//
19
//####BSDCOPYRIGHTEND####
20
//==========================================================================
21
 
22
//==========================================================================
23
//
24
//        lib/timeout.c
25
//
26
//        timeout support
27
//
28
//==========================================================================
29
//####BSDCOPYRIGHTBEGIN####
30
//
31
// -------------------------------------------
32
//
33
// Portions of this software may have been derived from OpenBSD or other sources,
34
// and are covered by the appropriate copyright disclaimers included herein.
35
//
36
// -------------------------------------------
37
//
38
//####BSDCOPYRIGHTEND####
39
//==========================================================================
40
//#####DESCRIPTIONBEGIN####
41
//
42
// Author(s):     gthomas, hmt
43
// Contributors:  gthomas, hmt
44
// Date:          1999-02-05
45
// Description:   Simple timeout functions
46
//####DESCRIPTIONEND####
47
 
48
#include <sys/param.h>
49
#include <pkgconf/net.h>
50
#include <cyg/kernel/kapi.h>
51
#include <cyg/infra/cyg_ass.h>
52
 
53
// Timeout support
54
 
55
void alarm_timeout_init(void);
56
 
57
#ifndef NTIMEOUTS
58
#define NTIMEOUTS 8
59
#endif
60
static timeout_entry _timeouts[NTIMEOUTS];
61
static timeout_entry *timeouts = (timeout_entry *)NULL;
62
static cyg_handle_t timeout_alarm_handle;
63
static cyg_alarm timeout_alarm;
64
static cyg_int32 last_delta;
65
static cyg_tick_count_t last_set_time;
66
 
67
#define STACK_SIZE CYGNUM_HAL_STACK_SIZE_TYPICAL
68
static char alarm_stack[STACK_SIZE];
69
static cyg_thread alarm_thread_data;
70
static cyg_handle_t alarm_thread_handle;
71
 
72
static cyg_flag_t alarm_flag;
73
 
74
// ------------------------------------------------------------------------
75
// This routine exists so that this module can synchronize:
76
extern cyg_uint32 cyg_splinternal(void);
77
 
78
#ifdef TIMEOUT_DEBUG
79
static void
80
_show_timeouts(void)
81
{
82
    timeout_entry *f;
83
    for (f = timeouts;  f;  f = f->next) {
84
        diag_printf("%p: delta: %d, fun: %p, param: %p\n", f, f->delta, f->fun, f->arg);
85
    }
86
}
87
#endif // TIMEOUT_DEBUG
88
 
89
// ------------------------------------------------------------------------
90
// CALLBACK FUNCTION
91
// Called from the thread, this runs the alarm callbacks.
92
// Locking is already in place when this is called.
93
static void
94
do_timeout(void)
95
{
96
    cyg_int32 min_delta;
97
    timeout_entry *e, *e_next;
98
 
99
    CYG_ASSERT( 0 < last_delta, "last_delta underflow" );
100
 
101
    min_delta = last_delta; // local copy
102
    last_delta = -1; // flag recursive call underway
103
 
104
    e = _timeouts;
105
    while (e) {
106
        e_next = e->next;  // Because this can change during processing
107
        if (e->delta) {
108
#ifdef TIMEOUT_DEBUG
109
                if ( !(e->delta >= min_delta)) {
110
                    diag_printf("Bad delta in timeout: %p, delta: %d, min: %d, last: %ld\n", e, e->delta, min_delta, last_set_time);
111
                    _show_timeouts();
112
                }
113
#endif
114
// Note: this _can_ happen if timeouts are scheduled before the clock starts!
115
//            CYG_ASSERT( e->delta >= min_delta, "e->delta underflow" );
116
            e->delta -= min_delta;
117
            if (e->delta <= 0) { // Defensive
118
                // Time for this item to 'fire'
119
                timeout_fun *fun = e->fun;
120
                void *arg = e->arg;
121
                // Call it *after* cleansing the record
122
//                diag_printf("%s(%p, %p, %p)\n", __FUNCTION__, e, e->fun, e->arg);
123
                e->flags &= ~CALLOUT_PENDING;
124
                e->delta = 0;
125
                if (e->next) {
126
                    e->next->prev = e->prev;
127
                }
128
                if (e->prev) {
129
                    e->prev->next = e->next;
130
                } else {
131
                    timeouts = e->next;
132
                }
133
                (*fun)(arg);
134
            }
135
        }
136
        e = e_next;
137
    }
138
 
139
    // Now scan for a new timeout *after* running all the callbacks
140
    // (because they can add timeouts themselves)
141
    min_delta = 0x7FFFFFFF;  // Maxint
142
    for (e = timeouts;  e;  e = e->next )
143
        if (e->delta)
144
            if (e->delta < min_delta)
145
                min_delta = e->delta;
146
 
147
    CYG_ASSERT( 0 < min_delta, "min_delta underflow" );
148
 
149
    if (min_delta != 0x7FFFFFFF) {
150
        // Still something to do, schedule it
151
        last_set_time = cyg_current_time();
152
        cyg_alarm_initialize(timeout_alarm_handle, last_set_time+min_delta, 0);
153
        last_delta = min_delta;
154
    } else {
155
        last_delta = 0; // flag no activity
156
    }
157
#ifdef TIMEOUT_DEBUG
158
    diag_printf("Timeout list after %s\n", __FUNCTION__);
159
    _show_timeouts();
160
#endif
161
}
162
 
163
// ------------------------------------------------------------------------
164
// ALARM EVENT FUNCTION
165
// This is the DSR for the alarm firing:
166
static void
167
do_alarm(cyg_handle_t alarm, cyg_addrword_t data)
168
{
169
    cyg_flag_setbits( &alarm_flag, 1 );
170
}
171
 
172
void ecos_synch_eth_drv_dsr(void)
173
{
174
    cyg_flag_setbits( &alarm_flag, 2 );
175
}
176
 
177
// ------------------------------------------------------------------------
178
// HANDLER THREAD ENTRY ROUTINE
179
// This waits on the DSR to tell it to run:
180
static void
181
alarm_thread(cyg_addrword_t param)
182
{
183
    // This is from the logical ethernet dev; it calls those delivery
184
    // functions who need attention.
185
    extern void eth_drv_run_deliveries( void );
186
 
187
    // This is from the logical ethernet dev; it tickles somehow
188
    // all ethernet devices in case one is wedged.
189
    extern void eth_drv_tickle_devices( void );
190
 
191
    while ( 1 ) {
192
        int spl;
193
        int x;
194
#ifdef CYGPKG_NET_FAST_THREAD_TICKLE_DEVS
195
        cyg_tick_count_t later = cyg_current_time();
196
        later += CYGNUM_NET_FAST_THREAD_TICKLE_DEVS_DELAY;
197
        x = cyg_flag_timed_wait(
198
            &alarm_flag,
199
            -1,
200
            CYG_FLAG_WAITMODE_OR | CYG_FLAG_WAITMODE_CLR,
201
            later );
202
#else
203
        x = cyg_flag_wait(
204
            &alarm_flag,
205
            -1,
206
            CYG_FLAG_WAITMODE_OR | CYG_FLAG_WAITMODE_CLR );
207
 
208
        CYG_ASSERT( 3 & x, "Lost my bits" );
209
#endif // CYGPKG_NET_FAST_THREAD_TICKLE_DEVS
210
        CYG_ASSERT( !((~3) & x), "Extra bits" );
211
 
212
        spl = cyg_splinternal();
213
 
214
        CYG_ASSERT( 0 == spl, "spl nonzero" );
215
 
216
        if ( 2 & x )
217
            eth_drv_run_deliveries();
218
#ifdef CYGPKG_NET_FAST_THREAD_TICKLE_DEVS
219
        // This is in the else clause for "do we deliver" because the
220
        // network stack might have continuous timing events anyway - so
221
        // the timeout would not occur, x would be 1 every time.
222
        else // Tickle the devices...
223
            eth_drv_tickle_devices();
224
#endif // CYGPKG_NET_FAST_THREAD_TICKLE_DEVS
225
 
226
        if ( 1 & x )
227
            do_timeout();
228
 
229
        cyg_splx(spl);
230
    }
231
}
232
 
233
// ------------------------------------------------------------------------
234
// INITIALIZATION FUNCTION
235
void
236
cyg_alarm_timeout_init( void )
237
{
238
    // Init the alarm object, attached to the real time clock
239
    cyg_handle_t h;
240
    cyg_clock_to_counter(cyg_real_time_clock(), &h);
241
    cyg_alarm_create(h, do_alarm, 0, &timeout_alarm_handle, &timeout_alarm);
242
    // Init the flag of waking up
243
    cyg_flag_init( &alarm_flag );
244
    // Create alarm background thread to run the callbacks
245
    cyg_thread_create(
246
        CYGPKG_NET_FAST_THREAD_PRIORITY, // Priority
247
        alarm_thread,                   // entry
248
        0,                              // entry parameter
249
        "Network alarm support",        // Name
250
        &alarm_stack[0],                // Stack
251
        STACK_SIZE,                     // Size
252
        &alarm_thread_handle,           // Handle
253
        &alarm_thread_data              // Thread data structure
254
        );
255
    cyg_thread_resume(alarm_thread_handle);    // Start it
256
}
257
 
258
// ------------------------------------------------------------------------
259
// EXPORTED API: SET A TIMEOUT
260
// This can be called from anywhere, including recursively from the timeout
261
// functions themselves.
262
cyg_uint32
263
timeout(timeout_fun *fun, void *arg, cyg_int32 delta)
264
{
265
    timeout_entry *e;
266
    cyg_uint32 stamp;
267
 
268
    // this needs to be atomic - recursive calls from the alarm
269
    // handler thread itself are allowed:
270
    int spl = cyg_splinternal();
271
 
272
    stamp = 0;  // Assume no slots available
273
    for (e = _timeouts;  e;  e = e->next) {
274
        if ((e->flags & CALLOUT_PENDING) == 0) {
275
            // Free entry
276
            callout_init(e);
277
            e->flags = CALLOUT_LOCAL;
278
            callout_reset(e, delta, fun, arg);
279
            stamp = (cyg_uint32)e;
280
            break;
281
        }
282
    }
283
    cyg_splx(spl);
284
    return stamp;
285
}
286
 
287
// ------------------------------------------------------------------------
288
// EXPORTED API: CANCEL A TIMEOUT
289
// This can be called from anywhere, including recursively from the timeout
290
// functions themselves.
291
void
292
untimeout(timeout_fun *fun, void * arg)
293
{
294
    timeout_entry *e;
295
    int spl = cyg_splinternal();
296
 
297
    for (e = _timeouts;  e; e = e->next) {
298
        if (e->delta && (e->fun == fun) && (e->arg == arg)) {
299
            callout_stop(e);
300
            break;
301
        }
302
    }
303
    cyg_splx(spl);
304
}
305
 
306
void
307
callout_init(struct callout *c)
308
{
309
    bzero(c, sizeof(*c));
310
}
311
 
312
void
313
callout_reset(struct callout *c, int delta, timeout_fun *f, void *p)
314
{
315
    int spl = cyg_splinternal();
316
 
317
    CYG_ASSERT( 0 < delta, "delta is right now, or even sooner!" );
318
 
319
    // Renormalize delta wrt the existing set alarm, if there is one
320
    if (last_delta > 0) {
321
#ifdef TIMEOUT_DEBUG
322
        int _delta = delta;
323
        int _time = cyg_current_time();
324
#endif // TIMEOUT_DEBUG
325
        // There is an active alarm
326
        if (last_set_time != 0) {
327
            // Adjust the delta to be absolute, relative to the alarm
328
            delta += (cyg_int32)(cyg_current_time() - last_set_time);
329
        } else {
330
            // We don't know exactly when the alarm will fire, so just
331
            // schedule this event for the first time, or sometime after
332
            ;  // Leaving the value alone won't be "too wrong"
333
        }
334
#ifdef TIMEOUT_DEBUG
335
        diag_printf("delta changed from %d to %d, now: %d, then: %d, last_delta: %d\n",
336
                    _delta, delta, _time, (int)last_set_time, last_delta);
337
        _show_timeouts();
338
#endif
339
    }
340
    // So recorded_delta is set to either:
341
    // alarm is active:   delta + NOW - THEN
342
    // alarm is inactive: delta
343
 
344
    // Add this callout/timeout to the list of things to do
345
    if (c->flags & CALLOUT_PENDING) {
346
        callout_stop(c);
347
    }
348
    c->prev = (timeout_entry *)NULL;
349
    c->next = timeouts;
350
    if (c->next != (timeout_entry *)NULL) {
351
        c->next->prev = c;
352
    }
353
    timeouts = c;
354
    c->flags |= CALLOUT_PENDING | CALLOUT_ACTIVE;
355
    c->fun = f;
356
    c->arg = p;
357
    c->delta = delta;
358
 
359
#ifdef TIMEOUT_DEBUG
360
    diag_printf("%s(%p, %d, %p, %p)\n", __FUNCTION__, c, delta, f, p);
361
    _show_timeouts();
362
#endif
363
 
364
    if ((0 == last_delta ||      // alarm was inactive  OR
365
         delta < last_delta) ) { // alarm was active but later than we need
366
 
367
        // (if last_delta is -1, this call is recursive from the handler so
368
        //  also do nothing in that case)
369
 
370
        // Here, we know the new item added is sooner than that which was
371
        // most recently set, if any, so we can just go and set it up.
372
        if ( 0 == last_delta )
373
            last_set_time = cyg_current_time();
374
 
375
        // So we use, to set the alarm either:
376
        // alarm is active:   (delta + NOW - THEN) + THEN
377
        // alarm is inactive:  delta + NOW
378
        // and in either case it is true that
379
        //  (recorded_delta + last_set_time) == (delta + NOW)
380
        cyg_alarm_initialize(timeout_alarm_handle, last_set_time+delta, 0);
381
#ifdef TIMEOUT_DEBUG
382
        if ((int)last_set_time == 0) {
383
            diag_printf("delta: %d, time: %ld, last_delta: %d\n", delta, last_set_time, last_delta);
384
        }
385
#endif
386
        last_delta = delta;
387
    }
388
    // Otherwise, the alarm is active, AND it is set to fire sooner than we
389
    // require, so when it does, that will sort out calling the item we
390
    // just added.
391
 
392
#ifdef CYGPKG_INFRA_DEBUG
393
    // Do some more checking akin to that in the alarm handler:
394
    if ( last_delta != -1 ) { // not a recursive call
395
        cyg_tick_count_t now = cyg_current_time();
396
        timeout_entry *e;
397
 
398
        CYG_ASSERT( last_delta >= 0, "Bad last delta" );
399
        delta = 0x7fffffff;
400
        for (e = timeouts;  e;  e = e->next) {
401
            if (e->delta) {
402
                CYG_ASSERT( e->delta >= last_delta, "e->delta underflow" );
403
                CYG_ASSERT( last_set_time + e->delta + 1000 > now,
404
                            "Recorded alarm not in the future!" );
405
                if ( e->delta < delta )
406
                    delta = e->delta;
407
            } else {
408
                CYG_ASSERT( 0 == e->fun, "Function recorded for 0 delta" );
409
            }
410
        }
411
        if (delta < last_delta) {
412
            diag_printf("Failed to pick smallest delta - picked: %d, last: %d\n", delta, last_delta);
413
            for (e = timeouts;  e;  e = e->next) {
414
                diag_printf("  timeout: %p at %d\n", e->fun, e->delta);
415
            }
416
        }
417
        CYG_ASSERT( delta >= last_delta, "We didn't pick the smallest delta!" );
418
    }
419
#endif
420
    cyg_splx(spl);
421
}
422
 
423
void
424
callout_stop(struct callout *c)
425
{
426
    int spl = cyg_splinternal();
427
 
428
#ifdef TIMEOUT_DEBUG
429
    diag_printf("%s(%p) = %x\n", __FUNCTION__, c, c->flags);
430
#endif
431
    if ((c->flags & CALLOUT_PENDING) == 0) {
432
        c->flags &= ~CALLOUT_ACTIVE;
433
        cyg_splx(spl);
434
        return;
435
    }
436
    c->flags &= ~(CALLOUT_PENDING | CALLOUT_ACTIVE);
437
    if (c->next) {
438
        c->next->prev = c->prev;
439
    }
440
    if (c->prev) {
441
        c->prev->next = c->next;
442
    } else {
443
        timeouts = c->next;
444
    }
445
    cyg_splx(spl);
446
}
447
 
448
int
449
callout_active(struct callout *c)
450
{
451
    return ((c->flags & CALLOUT_ACTIVE) != 0);
452
}
453
 
454
void
455
callout_deactivate(struct callout *c)
456
{
457
    c->flags &= ~CALLOUT_ACTIVE;
458
}
459
 
460
int
461
callout_pending(struct callout *c)
462
{
463
    return ((c->flags & CALLOUT_PENDING) != 0);
464
}
465
 
466
 
467
// ------------------------------------------------------------------------
468
 
469
// EOF timeout.c

powered by: WebSVN 2.1.0

© copyright 1999-2024 OpenCores.org, equivalent to Oliscience, all rights reserved. OpenCores®, registered trademark.