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

Subversion Repositories or1k

[/] [or1k/] [trunk/] [ecos-2.0/] [packages/] [net/] [tcpip/] [v2_0/] [src/] [ecos/] [timeout.c] - Blame information for rev 1773

Go to most recent revision | Details | Compare with Previous | View Log

Line No. Rev Author Line
1 1254 phoenix
//==========================================================================
2
//
3
//        lib/timeout.c
4
//
5
//        timeout support
6
//
7
//==========================================================================
8
//####BSDCOPYRIGHTBEGIN####
9
//
10
// -------------------------------------------
11
//
12
// Portions of this software may have been derived from OpenBSD or other sources,
13
// and are covered by the appropriate copyright disclaimers included herein.
14
//
15
// -------------------------------------------
16
//
17
//####BSDCOPYRIGHTEND####
18
//==========================================================================
19
//#####DESCRIPTIONBEGIN####
20
//
21
// Author(s):     gthomas, hmt
22
// Contributors:  gthomas, hmt
23
// Date:          1999-02-05
24
// Description:   Simple timeout functions
25
//####DESCRIPTIONEND####
26
 
27
#include <sys/param.h>
28
#include <pkgconf/net.h>
29
#include <cyg/kernel/kapi.h>
30
#include <cyg/infra/cyg_ass.h>
31
 
32
// Timeout support
33
 
34
void alarm_timeout_init(void);
35
 
36
#ifndef NTIMEOUTS
37
#define NTIMEOUTS 8
38
#endif
39
typedef struct {
40
    cyg_int32     delta;  // Number of "ticks" in the future for this timeout
41
    timeout_fun  *fun;    // Function to execute when it expires
42
    void         *arg;    // Argument to pass when it does
43
} timeout_entry;
44
static timeout_entry timeouts[NTIMEOUTS];
45
static cyg_handle_t timeout_alarm_handle;
46
static cyg_alarm timeout_alarm;
47
static cyg_int32 last_delta;
48
static cyg_tick_count_t last_set_time;
49
 
50
#define STACK_SIZE CYGNUM_HAL_STACK_SIZE_TYPICAL
51
static char alarm_stack[STACK_SIZE];
52
static cyg_thread alarm_thread_data;
53
static cyg_handle_t alarm_thread_handle;
54
 
55
static cyg_flag_t alarm_flag;
56
 
57
// ------------------------------------------------------------------------
58
// This routine exists so that this module can synchronize:
59
extern cyg_uint32 cyg_splinternal(void);
60
 
61
// ------------------------------------------------------------------------
62
// CALLBACK FUNCTION
63
// Called from the thread, this runs the alarm callbacks.
64
// Locking is already in place when this is called.
65
static void
66
do_timeout(void)
67
{
68
    int i;
69
    cyg_int32 min_delta;
70
    timeout_entry *e;
71
 
72
    CYG_ASSERT( 0 < last_delta, "last_delta underflow" );
73
 
74
    min_delta = last_delta; // local copy
75
    last_delta = -1; // flag recursive call underway
76
 
77
    for (e = timeouts, i = 0;  i < NTIMEOUTS;  i++, e++) {
78
        if (e->delta) {
79
            CYG_ASSERT( e->delta >= min_delta, "e->delta underflow" );
80
            e->delta -= min_delta;
81
            if (e->delta <= 0) { // Defensive
82
                // Time for this item to 'fire'
83
                timeout_fun *fun = e->fun;
84
                void *arg = e->arg;
85
                // Call it *after* cleansing the record
86
                e->fun = 0;
87
                e->delta = 0;
88
                (*fun)(arg);
89
            }
90
        }
91
    }
92
 
93
    // Now scan for a new timeout *after* running all the callbacks
94
    // (because they can add timeouts themselves)
95
    min_delta = 0x7FFFFFFF;  // Maxint
96
    for (e = timeouts, i = 0;  i < NTIMEOUTS;  i++, e++)
97
        if (e->delta)
98
            if (e->delta < min_delta)
99
                min_delta = e->delta;
100
 
101
    CYG_ASSERT( 0 < min_delta, "min_delta underflow" );
102
 
103
    if (min_delta != 0x7FFFFFFF) {
104
        // Still something to do, schedule it
105
        last_set_time = cyg_current_time();
106
        cyg_alarm_initialize(timeout_alarm_handle, last_set_time+min_delta, 0);
107
        last_delta = min_delta;
108
    } else {
109
        last_delta = 0; // flag no activity
110
    }
111
}
112
 
113
// ------------------------------------------------------------------------
114
// ALARM EVENT FUNCTION
115
// This is the DSR for the alarm firing:
116
static void
117
do_alarm(cyg_handle_t alarm, cyg_addrword_t data)
118
{
119
    cyg_flag_setbits( &alarm_flag, 1 );
120
}
121
 
122
void ecos_synch_eth_drv_dsr(void)
123
{
124
    cyg_flag_setbits( &alarm_flag, 2 );
125
}
126
 
127
// ------------------------------------------------------------------------
128
// HANDLER THREAD ENTRY ROUTINE
129
// This waits on the DSR to tell it to run:
130
static void
131
alarm_thread(cyg_addrword_t param)
132
{
133
    // This is from the logical ethernet dev; it calls those delivery
134
    // functions who need attention.
135
    extern void eth_drv_run_deliveries( void );
136
 
137
    // This is from the logical ethernet dev; it tickles somehow
138
    // all ethernet devices in case one is wedged.
139
    extern void eth_drv_tickle_devices( void );
140
 
141
    while ( 1 ) {
142
        int spl;
143
        int x;
144
#ifdef CYGPKG_NET_FAST_THREAD_TICKLE_DEVS
145
        cyg_tick_count_t later = cyg_current_time();
146
        later += CYGNUM_NET_FAST_THREAD_TICKLE_DEVS_DELAY;
147
        x = cyg_flag_timed_wait(
148
            &alarm_flag,
149
            -1,
150
            CYG_FLAG_WAITMODE_OR | CYG_FLAG_WAITMODE_CLR,
151
            later );
152
#else
153
        x = cyg_flag_wait(
154
            &alarm_flag,
155
            -1,
156
            CYG_FLAG_WAITMODE_OR | CYG_FLAG_WAITMODE_CLR );
157
 
158
        CYG_ASSERT( 3 & x, "Lost my bits" );
159
#endif // CYGPKG_NET_FAST_THREAD_TICKLE_DEVS
160
        CYG_ASSERT( !((~3) & x), "Extra bits" );
161
 
162
        spl = cyg_splinternal();
163
 
164
        CYG_ASSERT( 0 == spl, "spl nonzero" );
165
 
166
        if ( 2 & x )
167
            eth_drv_run_deliveries();
168
#ifdef CYGPKG_NET_FAST_THREAD_TICKLE_DEVS
169
        // This is in the else clause for "do we deliver" because the
170
        // network stack might have continuous timing events anyway - so
171
        // the timeout would not occur, x would be 1 every time.
172
        else // Tickle the devices...
173
            eth_drv_tickle_devices();
174
#endif // CYGPKG_NET_FAST_THREAD_TICKLE_DEVS
175
 
176
        if ( 1 & x )
177
            do_timeout();
178
 
179
        cyg_splx(spl);
180
    }
181
}
182
 
183
// ------------------------------------------------------------------------
184
// INITIALIZATION FUNCTION
185
void
186
cyg_alarm_timeout_init( void )
187
{
188
    // Init the alarm object, attached to the real time clock
189
    cyg_handle_t h;
190
    cyg_clock_to_counter(cyg_real_time_clock(), &h);
191
    cyg_alarm_create(h, do_alarm, 0, &timeout_alarm_handle, &timeout_alarm);
192
    // Init the flag of waking up
193
    cyg_flag_init( &alarm_flag );
194
    // Create alarm background thread to run the callbacks
195
    cyg_thread_create(
196
        CYGPKG_NET_FAST_THREAD_PRIORITY, // Priority
197
        alarm_thread,                   // entry
198
        0,                              // entry parameter
199
        "Network alarm support",        // Name
200
        &alarm_stack[0],                // Stack
201
        STACK_SIZE,                     // Size
202
        &alarm_thread_handle,           // Handle
203
        &alarm_thread_data              // Thread data structure
204
        );
205
    cyg_thread_resume(alarm_thread_handle);    // Start it
206
}
207
 
208
// ------------------------------------------------------------------------
209
// EXPORTED API: SET A TIMEOUT
210
// This can be called from anywhere, including recursively from the timeout
211
// functions themselves.
212
cyg_uint32
213
timeout(timeout_fun *fun, void *arg, cyg_int32 delta)
214
{
215
    int i;
216
    timeout_entry *e;
217
    cyg_uint32 stamp;
218
 
219
    // this needs to be atomic - recursive calls from the alarm
220
    // handler thread itself are allowed:
221
    int spl = cyg_splinternal();
222
 
223
    CYG_ASSERT( 0 < delta, "delta is right now, or even sooner!" );
224
 
225
    // Renormalize delta wrt the existing set alarm, if there is one
226
    if ( last_delta > 0 )
227
        delta += (cyg_int32)(cyg_current_time() - last_set_time);
228
    // So recorded_delta is set to either:
229
    // alarm is active:   delta + NOW - THEN
230
    // alarm is inactive: delta
231
 
232
    stamp = 0;  // Assume no slots available
233
    for (e = timeouts, i = 0;  i < NTIMEOUTS;  i++, e++) {
234
        if ((e->delta == 0) && (e->fun == 0)) {
235
            // Free entry
236
            e->delta = delta;
237
            e->fun = fun;
238
            e->arg = arg;
239
            stamp = (cyg_uint32)e;
240
            break;
241
        }
242
    }
243
 
244
    if ( stamp &&                 // we did add a record AND
245
         (0 == last_delta ||      // alarm was inactive  OR
246
          delta < last_delta) ) { // alarm was active but later than we need
247
 
248
        // (if last_delta is -1, this call is recursive from the handler so
249
        //  also do nothing in that case)
250
 
251
        // Here, we know the new item added is sooner than that which was
252
        // most recently set, if any, so we can just go and set it up.
253
        if ( 0 == last_delta )
254
            last_set_time = cyg_current_time();
255
 
256
        // So we use, to set the alarm either:
257
        // alarm is active:   (delta + NOW - THEN) + THEN
258
        // alarm is inactive:  delta + NOW
259
        // and in either case it is true that
260
        //  (recorded_delta + last_set_time) == (delta + NOW)
261
        cyg_alarm_initialize(timeout_alarm_handle, last_set_time+delta, 0);
262
        last_delta = delta;
263
    }
264
    // Otherwise, the alarm is active, AND it is set to fire sooner than we
265
    // require, so when it does, that will sort out calling the item we
266
    // just added.  Or we didn't actually add a record, so nothing has
267
    // changed.
268
 
269
#ifdef CYGPKG_INFRA_DEBUG
270
    // Do some more checking akin to that in the alarm handler:
271
    if ( last_delta != -1 ) { // not a recursive call
272
        cyg_tick_count_t now = cyg_current_time();
273
        CYG_ASSERT( last_delta >= 0, "Bad last delta" );
274
        delta = 0x7fffffff;
275
        for (e = timeouts, i = 0;  i < NTIMEOUTS;  i++, e++) {
276
            if (e->delta) {
277
                CYG_ASSERT( e->delta >= last_delta, "e->delta underflow" );
278
                CYG_ASSERT( last_set_time + e->delta + 1000 > now,
279
                            "Recorded alarm not in the future!" );
280
                if ( e->delta < delta )
281
                    delta = e->delta;
282
            } else {
283
                CYG_ASSERT( 0 == e->fun, "Function recorded for 0 delta" );
284
            }
285
        }
286
        CYG_ASSERT( delta == last_delta, "We didn't pick the smallest delta!" );
287
    }
288
#endif
289
 
290
    cyg_splx(spl);
291
    return stamp;
292
}
293
 
294
// ------------------------------------------------------------------------
295
// EXPORTED API: CANCEL A TIMEOUT
296
// This can be called from anywhere, including recursively from the timeout
297
// functions themselves.
298
void
299
untimeout(timeout_fun *fun, void * arg)
300
{
301
    int i;
302
    timeout_entry *e;
303
    int spl = cyg_splinternal();
304
 
305
    for (e = timeouts, i = 0; i < NTIMEOUTS; i++, e++) {
306
        if (e->delta && (e->fun == fun) && (e->arg == arg)) {
307
            e->delta = 0;
308
            e->fun = 0;
309
            break;
310
        }
311
    }
312
    cyg_splx(spl);
313
}
314
 
315
// ------------------------------------------------------------------------
316
 
317
// EOF timeout.c

powered by: WebSVN 2.1.0

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