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

Subversion Repositories openrisc

[/] [openrisc/] [trunk/] [rtos/] [ecos-2.0/] [packages/] [kernel/] [v2_0/] [src/] [sync/] [flag.cxx] - Blame information for rev 174

Details | Compare with Previous | View Log

Line No. Rev Author Line
1 27 unneback
//==========================================================================
2
//
3
//      flag.cxx
4
//
5
//      Flag class implementation
6
//
7
//==========================================================================
8
//####ECOSGPLCOPYRIGHTBEGIN####
9
// -------------------------------------------
10
// This file is part of eCos, the Embedded Configurable Operating System.
11
// Copyright (C) 1998, 1999, 2000, 2001, 2002 Red Hat, Inc.
12
//
13
// eCos is free software; you can redistribute it and/or modify it under
14
// the terms of the GNU General Public License as published by the Free
15
// Software Foundation; either version 2 or (at your option) any later version.
16
//
17
// eCos is distributed in the hope that it will be useful, but WITHOUT ANY
18
// WARRANTY; without even the implied warranty of MERCHANTABILITY or
19
// FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
20
// for more details.
21
//
22
// You should have received a copy of the GNU General Public License along
23
// with eCos; if not, write to the Free Software Foundation, Inc.,
24
// 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
25
//
26
// As a special exception, if other files instantiate templates or use macros
27
// or inline functions from this file, or you compile this file and link it
28
// with other works to produce a work based on this file, this file does not
29
// by itself cause the resulting work to be covered by the GNU General Public
30
// License. However the source code for this file must still be made available
31
// in accordance with section (3) of the GNU General Public License.
32
//
33
// This exception does not invalidate any other reasons why a work based on
34
// this file might be covered by the GNU General Public License.
35
//
36
// Alternative licenses for eCos may be arranged by contacting Red Hat, Inc.
37
// at http://sources.redhat.com/ecos/ecos-license/
38
// -------------------------------------------
39
//####ECOSGPLCOPYRIGHTEND####
40
//==========================================================================
41
//#####DESCRIPTIONBEGIN####
42
//
43
// Author(s):   hmt
44
// Contributors:        hmt
45
// Date:        1998-02-11
46
// Purpose:     Flag implementation
47
// Description: This file contains the implementations of the flag class
48
//
49
//####DESCRIPTIONEND####
50
//
51
//==========================================================================
52
 
53
#include <pkgconf/kernel.h>
54
 
55
#include <cyg/kernel/ktypes.h>         // base kernel types
56
#include <cyg/infra/cyg_trac.h>        // tracing macros
57
#include <cyg/infra/cyg_ass.h>         // assertion macros
58
#include <cyg/kernel/instrmnt.h>       // instrumentation
59
 
60
#include <cyg/kernel/thread.inl>       // thread inlines
61
 
62
#include <cyg/kernel/flag.hxx>         // our own header
63
 
64
#include <cyg/kernel/sched.inl>        // scheduler inlines
65
#include <cyg/kernel/clock.inl>        // clock inlines
66
 
67
// -------------------------------------------------------------------------
68
// Constructor
69
 
70
Cyg_Flag::Cyg_Flag( Cyg_FlagValue init )
71
{
72
    CYG_REPORT_FUNCTION();
73
    value = init;
74
    CYG_REPORT_RETURN();
75
}
76
 
77
// -------------------------------------------------------------------------
78
// Destructor
79
 
80
Cyg_Flag::~Cyg_Flag()
81
{
82
    CYG_REPORT_FUNCTION();
83
#if 0
84
    CYG_ASSERT( queue.empty(), "Deleting flag with threads waiting");
85
#endif
86
    // Prevent preemption
87
    Cyg_Scheduler::lock();
88
 
89
    while ( ! queue.empty() ) {
90
        Cyg_Thread *thread = queue.dequeue();
91
        thread->set_wake_reason( Cyg_Thread::DESTRUCT );
92
        thread->wake();
93
    }
94
 
95
    // Unlock the scheduler and maybe switch threads
96
    Cyg_Scheduler::unlock();
97
    CYG_REPORT_RETURN();
98
}
99
 
100
// -------------------------------------------------------------------------
101
// debugging/assert function
102
 
103
#ifdef CYGDBG_USE_ASSERTS
104
cyg_bool
105
Cyg_Flag::check_this(cyg_assert_class_zeal zeal) const
106
{
107
    CYG_REPORT_FUNCTION();
108
 
109
    if ( Cyg_Thread::DESTRUCT == Cyg_Thread::self()->get_wake_reason() )
110
        // then the whole thing is invalid, and we know it.
111
        // so return OK, since this check should NOT make an error.
112
        return true;
113
 
114
    // check that we have a non-NULL pointer first
115
    if( this == NULL ) {
116
        CYG_REPORT_RETVAL( false );
117
        return false;
118
    }
119
 
120
    // there ain't a lot to check here.
121
    CYG_REPORT_RETVAL( true );
122
    return true;
123
}
124
#endif
125
 
126
// -------------------------------------------------------------------------
127
// now the members themselves:
128
 
129
// clear some bits in the value (all of them by default) by ANDing with the
130
// argument.  This cannot make a wait condition become true, so there's not
131
// much to it.
132
void
133
Cyg_Flag::maskbits( Cyg_FlagValue arg )
134
{
135
    CYG_REPORT_FUNCTION();
136
 
137
    // Prevent preemption
138
    Cyg_Scheduler::lock();
139
 
140
    value &= arg;
141
    // no need to wake anyone up; no waiter can become valid in
142
    // consequence of this operation.
143
 
144
    // Unlock scheduler and allow other threads to run
145
    Cyg_Scheduler::unlock();
146
    CYG_REPORT_RETURN();
147
}
148
 
149
 
150
// -------------------------------------------------------------------------
151
// set some bits in the value (all of them by default) and wake up any
152
// affected waiting threads; we do the decision making here so as to get
153
// atomicity wrt the other threads waking up - the value might have changed
154
// by the time they get to run.
155
 
156
void
157
Cyg_Flag::setbits( Cyg_FlagValue arg )
158
{
159
    CYG_REPORT_FUNCTION();
160
    CYG_ASSERTCLASS( this, "Bad this pointer");
161
 
162
    // Prevent preemption
163
    Cyg_Scheduler::lock();
164
 
165
    // OR in the argument to get a new flag value.
166
    value |= arg;
167
 
168
    // anyone waiting?
169
    if ( !(queue.empty()) ) {
170
        FlagWaitInfo   *p;
171
        Cyg_Thread     *thread;
172
        Cyg_ThreadQueue holding;
173
 
174
        do {
175
            thread = queue.dequeue();
176
            p = (FlagWaitInfo *)(thread->get_wait_info());
177
 
178
            CYG_ASSERT( (p->allmask == 0) != (p->anymask == 0),
179
                        "Both masks set" );
180
            CYG_ASSERT( 0 == p->value_out, "Thread already awoken?" );
181
 
182
            if ( ((p->allmask != 0) && (p->allmask & value) == p->allmask) ||
183
                 ((p->anymask & value) != 0 ) ) {
184
                // success!  awaken the thread
185
                thread->set_wake_reason( Cyg_Thread::DONE );
186
                thread->wake();
187
                // return the successful value to it
188
                p->value_out = value;
189
                // do we clear the value; is this the end?
190
                if ( p->do_clear ) {
191
                    // we can break here but need to preserve ordering
192
                    value = 0;
193
                    // so let it cycle the whole queue regardless
194
                }
195
            }
196
            else {
197
                // preserve the entry on the holding queue
198
                holding.enqueue( thread );
199
            }
200
        } while ( !(queue.empty()) );
201
 
202
        // Now re-queue the unaffected threads back into the flag queue
203
        while ( !(holding.empty()) ) {
204
            queue.enqueue( holding.dequeue() );
205
        }
206
    }
207
    // Unlock scheduler and allow other threads to run
208
    Cyg_Scheduler::unlock();
209
    CYG_REPORT_RETURN();
210
}
211
 
212
// -------------------------------------------------------------------------
213
// Wait for a match on our pattern, according to the flags given.
214
// Return the matching value.
215
Cyg_FlagValue
216
Cyg_Flag::wait( Cyg_FlagValue pattern, WaitMode mode )
217
{
218
    CYG_REPORT_FUNCTION();
219
    CYG_ASSERTCLASS( this, "Bad this pointer");
220
    CYG_ASSERT( Cyg_Flag::MASK >= mode, "Bad mode" );
221
 
222
    Cyg_FlagValue result;
223
 
224
    // Prevent preemption so that we compare atomically
225
    Cyg_Scheduler::lock();
226
 
227
    // try the current value
228
    result = poll( pattern, mode );
229
 
230
    if ( 0 != result ) {
231
        Cyg_Scheduler::unlock();
232
        CYG_REPORT_RETVAL( result );
233
        return result;                  // all done
234
    }
235
 
236
    // we have to wait until we are awoken
237
    Cyg_Thread *self = Cyg_Thread::self();
238
 
239
    FlagWaitInfo saveme;
240
    saveme.allmask = (Cyg_Flag::OR & mode) ? 0 : pattern;
241
    saveme.anymask = (Cyg_Flag::OR & mode) ? pattern : 0;
242
    saveme.do_clear = (0 != (Cyg_Flag::CLR & mode));
243
 
244
    self->set_wait_info( (CYG_ADDRWORD)&saveme );
245
 
246
    result = true; // just being used as an early-out flag now
247
    // this loop allows us to deal correctly with spurious wakeups
248
    while ( result && (0 == saveme.value_out) ) {
249
        self->set_sleep_reason( Cyg_Thread::WAIT );
250
        self->sleep();
251
        // keep track of myself on the queue of waiting threads
252
        queue.enqueue( self );
253
 
254
        // Allow other threads to run
255
        Cyg_Scheduler::reschedule();
256
 
257
        CYG_ASSERT( ((CYG_ADDRWORD)&saveme) ==
258
                    Cyg_Thread::self()->get_wait_info(),
259
                    "Wait info lost" );
260
 
261
        switch( self->get_wake_reason() )
262
        {
263
        case Cyg_Thread::DESTRUCT:
264
        case Cyg_Thread::BREAK:
265
            result = false;
266
            break;
267
 
268
        case Cyg_Thread::EXIT:
269
            self->exit();
270
            break;
271
 
272
        default:
273
            break;
274
        }
275
    }
276
 
277
    CYG_ASSERT( (false == result) ^ (0 != saveme.value_out),
278
                "Break out but also good result!" );
279
 
280
    // Unlock scheduler and allow other threads to run
281
    Cyg_Scheduler::unlock();
282
    CYG_REPORT_RETVAL( saveme.value_out );
283
    return saveme.value_out;
284
}
285
 
286
// -------------------------------------------------------------------------
287
// Wait for a match on our pattern, with a timeout.
288
// Return the matching value, or zero if timed out.
289
// (zero cannot match any pattern).
290
#ifdef CYGFUN_KERNEL_THREADS_TIMER
291
Cyg_FlagValue
292
Cyg_Flag::wait( Cyg_FlagValue pattern, WaitMode mode,
293
                cyg_tick_count abs_timeout )
294
{
295
    CYG_REPORT_FUNCTION();
296
    CYG_ASSERTCLASS( this, "Bad this pointer");
297
    CYG_ASSERT( Cyg_Flag::MASK >= mode, "Bad mode" );
298
 
299
    Cyg_FlagValue result;
300
 
301
    // Prevent preemption so that we compare atomically
302
    Cyg_Scheduler::lock();
303
 
304
    // try the current value
305
    result = poll( pattern, mode );
306
 
307
    if ( 0 != result ) {
308
        Cyg_Scheduler::unlock();
309
        CYG_REPORT_RETVAL( result );
310
        return result;                  // all done
311
    }
312
 
313
    // we have to wait until we are awoken
314
    Cyg_Thread *self = Cyg_Thread::self();
315
 
316
    FlagWaitInfo saveme;
317
    saveme.allmask = (Cyg_Flag::OR & mode) ? 0 : pattern;
318
    saveme.anymask = (Cyg_Flag::OR & mode) ? pattern : 0;
319
    saveme.do_clear = (0 != (Cyg_Flag::CLR & mode));
320
 
321
    self->set_wait_info( (CYG_ADDRWORD)&saveme );
322
 
323
    // Set the timer _once_ outside the loop.
324
    self->set_timer( abs_timeout, Cyg_Thread::TIMEOUT );
325
 
326
    // If the timeout was in the past, it will have changed the value
327
    // of wake_reason, so avoid going into the loop.
328
    if( self->get_wake_reason() != Cyg_Thread::NONE )
329
        result = false;
330
    else result = true;
331
 
332
    // Result is just being used as an early-out flag now. This loop
333
    // allows us to deal correctly with spurious wakeups.
334
 
335
    while ( result && (0 == saveme.value_out) ) {
336
        self->set_sleep_reason( Cyg_Thread::TIMEOUT );
337
        self->sleep();
338
        // keep track of myself on the queue of waiting threads
339
        queue.enqueue( self );
340
 
341
        // Allow other threads to run
342
        Cyg_Scheduler::reschedule();
343
 
344
        CYG_ASSERT( ((CYG_ADDRWORD)&saveme) ==
345
                    Cyg_Thread::self()->get_wait_info(),
346
                    "Wait info lost" );
347
 
348
        switch( self->get_wake_reason() )
349
        {
350
        case Cyg_Thread::TIMEOUT:
351
            result = false;
352
            break;
353
 
354
        case Cyg_Thread::DESTRUCT:
355
        case Cyg_Thread::BREAK:
356
            result = false;
357
            break;
358
 
359
        case Cyg_Thread::EXIT:
360
            self->exit();
361
            break;
362
 
363
        default:
364
            break;
365
        }
366
    }
367
 
368
    CYG_ASSERT( (false == result) ^ (0 != saveme.value_out),
369
                "Break out but also good result!" );
370
 
371
    // clear the timer; if it actually fired, no worries.
372
    self->clear_timer();
373
 
374
    // Unlock scheduler and allow other threads to run
375
    Cyg_Scheduler::unlock();
376
    // in this version, value_out might be zero meaning timed out.
377
    CYG_REPORT_RETVAL( saveme.value_out );
378
    return saveme.value_out;
379
}
380
#endif // CYGFUN_KERNEL_THREADS_TIMER
381
 
382
// -------------------------------------------------------------------------
383
// Test for a match on our pattern, according to the flags given.
384
// Return the matching value if success, else zero.
385
Cyg_FlagValue
386
Cyg_Flag::poll( Cyg_FlagValue pattern, WaitMode mode )
387
{
388
    CYG_REPORT_FUNCTION();
389
    CYG_ASSERTCLASS( this, "Bad this pointer");
390
    CYG_ASSERT( Cyg_Flag::MASK >= mode, "Bad mode" );
391
 
392
    // Prevent preemption so that we compare atomically
393
    Cyg_Scheduler::lock();
394
 
395
    Cyg_FlagValue result = 0;
396
 
397
    if ( Cyg_Flag::OR & mode ) {
398
        if ( 0 != (value & pattern) )
399
            result = value;
400
    }
401
    else { // Cyg_Flag::AND - all must be set
402
        if ( (pattern != 0) && (pattern == (value & pattern)) )
403
            result = value;
404
    }
405
 
406
    // result != 0 <=> test passed
407
    if ( result && (Cyg_Flag::CLR & mode) )
408
        value = 0;
409
 
410
    Cyg_Scheduler::unlock();
411
 
412
    CYG_REPORT_RETVAL( result );
413
    return result;
414
}
415
 
416
 
417
// -------------------------------------------------------------------------
418
// EOF flag.cxx

powered by: WebSVN 2.1.0

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