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

Subversion Repositories openrisc

[/] [openrisc/] [trunk/] [rtos/] [ecos-3.0/] [packages/] [net/] [tcpip/] [current/] [src/] [ecos/] [timeout.c] - Blame information for rev 786

Details | Compare with Previous | View Log

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

powered by: WebSVN 2.1.0

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