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

Subversion Repositories openrisc

[/] [openrisc/] [trunk/] [rtos/] [ecos-3.0/] [packages/] [kernel/] [current/] [src/] [sync/] [flag.cxx] - Blame information for rev 817

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

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

powered by: WebSVN 2.1.0

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