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

Subversion Repositories openrisc

[/] [openrisc/] [trunk/] [rtos/] [ecos-3.0/] [packages/] [kernel/] [current/] [include/] [mboxt.inl] - Blame information for rev 786

Details | Compare with Previous | View Log

Line No. Rev Author Line
1 786 skrzyp
#ifndef CYGONCE_KERNEL_MBOXT_INL
2
#define CYGONCE_KERNEL_MBOXT_INL
3
//==========================================================================
4
//
5
//      mboxt.inl
6
//
7
//      Mboxt mbox template class implementation
8
//
9
//==========================================================================
10
// ####ECOSGPLCOPYRIGHTBEGIN####
11
// -------------------------------------------
12
// This file is part of eCos, the Embedded Configurable Operating System.
13
// Copyright (C) 1998, 1999, 2000, 2001, 2002, 2006 Free Software Foundation, Inc.
14
//
15
// eCos is free software; you can redistribute it and/or modify it under
16
// the terms of the GNU General Public License as published by the Free
17
// Software Foundation; either version 2 or (at your option) any later
18
// version.
19
//
20
// eCos is distributed in the hope that it will be useful, but WITHOUT
21
// ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
22
// FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
23
// for more details.
24
//
25
// You should have received a copy of the GNU General Public License
26
// along with eCos; if not, write to the Free Software Foundation, Inc.,
27
// 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
28
//
29
// As a special exception, if other files instantiate templates or use
30
// macros or inline functions from this file, or you compile this file
31
// and link it with other works to produce a work based on this file,
32
// this file does not by itself cause the resulting work to be covered by
33
// the GNU General Public License. However the source code for this file
34
// must still be made available in accordance with section (3) of the GNU
35
// General Public License v2.
36
//
37
// This exception does not invalidate any other reasons why a work based
38
// on this file might be covered by the GNU General Public License.
39
// -------------------------------------------
40
// ####ECOSGPLCOPYRIGHTEND####
41
//==========================================================================
42
//#####DESCRIPTIONBEGIN####
43
//
44
// Author(s):   hmt
45
// Contributors:        hmt
46
// Date:        1998-02-10
47
// Purpose:     Mboxt template implementation
48
// Description: This file contains the implementations of the mboxt
49
//              template classes.
50
//
51
//####DESCRIPTIONEND####
52
//
53
//==========================================================================
54
 
55
#include 
56
 
57
#include          // base kernel types
58
#include         // tracing macros
59
#include          // assertion macros
60
#include        // instrumentation
61
 
62
#include         // our header
63
 
64
#include        // thread inlines
65
#include         // scheduler inlines
66
#include         // clock inlines
67
 
68
// -------------------------------------------------------------------------
69
// inline function for awakening waiting threads
70
 
71
template 
72
inline void
73
Cyg_Mboxt::wakeup_waiter( Cyg_ThreadQueue &q )
74
{
75
    if( !q.empty() ) {
76
        // The queue is non-empty, so grab the next thread and wake it up.
77
        Cyg_Thread *thread = q.dequeue();
78
 
79
        CYG_ASSERTCLASS( thread, "Bad thread pointer");
80
 
81
        thread->set_wake_reason( Cyg_Thread::DONE );
82
        thread->wake();
83
        CYG_INSTRUMENT_MBOXT(WAKE, this, thread);
84
    }
85
}
86
 
87
// -------------------------------------------------------------------------
88
// Constructor
89
 
90
template 
91
Cyg_Mboxt::Cyg_Mboxt()
92
{
93
    CYG_REPORT_FUNCTION();
94
    base = 0;
95
    count = 0;
96
}
97
 
98
// -------------------------------------------------------------------------
99
// Destructor
100
 
101
template 
102
Cyg_Mboxt::~Cyg_Mboxt()
103
{
104
    CYG_REPORT_FUNCTION();
105
    CYG_ASSERT( 0 == count, "Deleting mboxt with messages");
106
    CYG_ASSERT( get_threadq.empty(), "Deleting mboxt with threads waiting to get");
107
#ifdef CYGMFN_KERNEL_SYNCH_MBOXT_PUT_CAN_WAIT
108
    CYG_ASSERT( put_threadq.empty(), "Deleting mboxt with threads waiting to put");
109
#endif
110
}
111
 
112
// -------------------------------------------------------------------------
113
// debugging/assert function
114
 
115
#ifdef CYGDBG_USE_ASSERTS
116
 
117
template 
118
cyg_bool
119
Cyg_Mboxt::check_this(cyg_assert_class_zeal zeal) const
120
{
121
    CYG_REPORT_FUNCTION();
122
 
123
    if ( Cyg_Thread::DESTRUCT == Cyg_Thread::self()->get_wake_reason() )
124
        // then the whole thing is invalid, and we know it.
125
        // so return OK, since this check should NOT make an error.
126
        return true;
127
 
128
    // check that we have a non-NULL pointer first
129
    if( this == NULL ) return false;
130
 
131
#if 0 // thread queues do not have checking funcs.
132
    if ( ! get_threadq.check_this( zeal ) ) return false;
133
#ifdef CYGMFN_KERNEL_SYNCH_MBOXT_PUT_CAN_WAIT
134
    if ( ! put_threadq.check_this( zeal ) ) return false;
135
#endif
136
#endif
137
 
138
    switch( zeal )
139
    {
140
    case cyg_system_test:
141
    case cyg_extreme:
142
    case cyg_thorough:
143
    case cyg_quick:
144
    case cyg_trivial:
145
        // plenty of scope for fencepost problems here
146
        if ( size < count ) return false;
147
        if ( size <= base ) return false;
148
        if ( 0 > count ) return false;
149
        if ( 0 > base  ) return false;
150
 
151
        // there was initially a test of the form
152
        //    (0 < count && count < size) && ! threadqueue.empty()
153
        // here - ie. there should only be people waiting if the Q is full
154
        // or empty.  This is bogus, anyone else might run between a waiter
155
        // being awoken, so there can be a 2nd waiter in the Q and a free
156
        // slot (say) simultaneously.
157
 
158
        // Further, we need 2 queues; imagine a 10-slot itemqueue with 25
159
        // attempts to put to it, so 15 sleep.  10 other threads get,
160
        // awakening 10 of the 15 put-sleepers.  Another one gets, and
161
        // can't because there is no data there _yet_; it sleeps, and the
162
        // 10 awakened threads cycle through the run queue, each putting,
163
        // the first awakens the get-sleeper, which in turn awakens a
164
        // further put-sleeper.
165
 
166
        // This requirement for 2 queue only holds if Ngetters > 2 * Nslots
167
        // or Nputters > 2 * Nslots; if these are both false, one queue
168
        // will suffice.  This could be an optimisation for the future -
169
        // wow, 4 bytes.
170
 
171
    case cyg_none:
172
    default:
173
        break;
174
    };
175
 
176
    return true;
177
}
178
 
179
#endif
180
 
181
 
182
// -------------------------------------------------------------------------
183
// From here downwards, these are the major functions of the template; if
184
// being genuinely used as a template they should probably not be inlined.
185
// If being used to construct a specific class, with explicit functions,
186
// then they should be.  This is controlled by:
187
 
188
#ifdef CYGIMP_MBOXT_INLINE
189
#define CYG_MBOXT_INLINE inline
190
#else
191
#define CYG_MBOXT_INLINE
192
#endif
193
 
194
// -------------------------------------------------------------------------
195
// Get an item, or wait for one to arrive
196
 
197
template 
198
CYG_MBOXT_INLINE cyg_bool
199
Cyg_Mboxt::get( T &ritem )
200
{
201
    CYG_REPORT_FUNCTION();
202
    cyg_bool result = true;
203
 
204
    Cyg_Thread *self = Cyg_Thread::self();
205
 
206
    // Prevent preemption
207
    Cyg_Scheduler::lock();
208
 
209
    CYG_ASSERTCLASS( this, "Bad this pointer");
210
 
211
    CYG_INSTRUMENT_MBOXT(GET, this, count);
212
 
213
    // Loop while the mboxt is empty, sleeping each time around
214
    // the loop. This copes with the possibility of a higher priority
215
    // thread grabbing the message between the wakeup in unlock() and
216
    // this thread actually starting.
217
 
218
    while( result && (0 == count) ) {
219
        self->set_sleep_reason( Cyg_Thread::WAIT );
220
        self->sleep();
221
        get_threadq.enqueue( self );
222
 
223
        CYG_INSTRUMENT_MBOXT(WAIT, this, count);
224
 
225
        CYG_ASSERTCLASS( this, "Bad this pointer");
226
 
227
        // Allow other threads to run
228
        Cyg_Scheduler::reschedule();
229
 
230
        switch( self->get_wake_reason() )
231
        {
232
        case Cyg_Thread::DESTRUCT:
233
        case Cyg_Thread::BREAK:
234
            result = false;
235
            break;
236
 
237
        case Cyg_Thread::EXIT:
238
            self->exit();
239
            break;
240
 
241
        default:
242
            break;
243
        }
244
    }
245
 
246
    if ( result ) {
247
        CYG_INSTRUMENT_MBOXT(GOT, this, count);
248
 
249
        ritem = itemqueue[ (count--, base++) ];
250
        CYG_ASSERT( 0 <= count, "Count went -ve" );
251
        CYG_ASSERT( size >= base, "Base overflow" );
252
 
253
        if ( size <= base )
254
            base = 0;
255
 
256
#ifdef CYGMFN_KERNEL_SYNCH_MBOXT_PUT_CAN_WAIT
257
        wakeup_waiter( put_threadq );
258
#endif
259
    }
260
 
261
    CYG_ASSERTCLASS( this, "Bad this pointer");
262
 
263
    // Unlock the scheduler and maybe switch threads
264
    Cyg_Scheduler::unlock();
265
 
266
    CYG_REPORT_RETVAL( result );
267
    return result;
268
}
269
 
270
 
271
// -------------------------------------------------------------------------
272
// Try to get an item with an absolute timeout and return success.
273
 
274
#ifdef CYGFUN_KERNEL_THREADS_TIMER
275
template 
276
CYG_MBOXT_INLINE cyg_bool
277
Cyg_Mboxt::get( T &ritem, cyg_tick_count abs_timeout )
278
{
279
    CYG_REPORT_FUNCTION();
280
    cyg_bool result = true;
281
 
282
    Cyg_Thread *self = Cyg_Thread::self();
283
 
284
    // Prevent preemption
285
    Cyg_Scheduler::lock();
286
 
287
    CYG_ASSERTCLASS( this, "Bad this pointer");
288
 
289
    CYG_INSTRUMENT_MBOXT(GET, this, count);
290
 
291
    // Set the timer _once_ outside the loop.
292
    self->set_timer( abs_timeout, Cyg_Thread::TIMEOUT  );
293
 
294
    // If the timeout is in the past, the wake reason will have been
295
    // set to something other than NONE already. Set the result false
296
    // to force an immediate return.
297
 
298
    if( self->get_wake_reason() != Cyg_Thread::NONE )
299
        result = false;
300
 
301
    // Loop while the mboxt is empty, sleeping each time around the loop.
302
    // This copes with the possibility of a higher priority thread grabbing
303
    // the message between the wakeup in put()&c and this thread actually
304
    // starting.
305
    while ( result && (0 == count) ) {
306
        // must reset the sleep reason every time
307
        self->set_sleep_reason( Cyg_Thread::TIMEOUT );
308
        self->sleep();
309
        get_threadq.enqueue( self );
310
 
311
        CYG_INSTRUMENT_MBOXT(WAIT, this, count);
312
 
313
        // Allow other threads to run
314
        Cyg_Scheduler::reschedule();
315
 
316
        CYG_ASSERTCLASS( this, "Bad this pointer");
317
 
318
        switch( self->get_wake_reason() )
319
        {
320
        case Cyg_Thread::TIMEOUT:
321
            result = false;
322
            CYG_INSTRUMENT_MBOXT(TIMEOUT, this, count);
323
            break;
324
 
325
        case Cyg_Thread::DESTRUCT:
326
        case Cyg_Thread::BREAK:
327
            result = false;
328
            break;
329
 
330
        case Cyg_Thread::EXIT:
331
            self->exit();
332
            break;
333
 
334
        default:
335
            break;
336
        }
337
    }
338
 
339
    // clear the timer; if it actually fired, no worries.
340
    self->clear_timer();
341
 
342
    if ( result ) {
343
 
344
        CYG_INSTRUMENT_MBOXT(GOT, this, count);
345
 
346
        ritem = itemqueue[ (count--, base++) ];
347
        CYG_ASSERT( 0 <= count, "Count went -ve" );
348
        CYG_ASSERT( size >= base, "Base overflow" );
349
 
350
        if ( size <= base )
351
            base = 0;
352
 
353
#ifdef CYGMFN_KERNEL_SYNCH_MBOXT_PUT_CAN_WAIT
354
        wakeup_waiter( put_threadq );
355
#endif
356
    }
357
 
358
    CYG_ASSERTCLASS( this, "Bad this pointer");
359
 
360
    // Unlock the scheduler and maybe switch threads
361
    Cyg_Scheduler::unlock();
362
 
363
    CYG_REPORT_RETVAL( result );
364
    return result;
365
}
366
#endif // CYGFUN_KERNEL_THREADS_TIMER
367
 
368
// -------------------------------------------------------------------------
369
// Try to get an item and return success.
370
 
371
template 
372
CYG_MBOXT_INLINE cyg_bool
373
Cyg_Mboxt::tryget( T &ritem )
374
{
375
    CYG_REPORT_FUNCTION();
376
 
377
    // Prevent preemption
378
    Cyg_Scheduler::lock();
379
 
380
    CYG_ASSERTCLASS( this, "Bad this pointer");
381
 
382
    CYG_INSTRUMENT_MBOXT(TRY, this, count);
383
 
384
    cyg_bool result = ( 0 < count );
385
    // If the mboxt is not empty, grab an item and return it.
386
    if ( result ) {
387
        ritem = itemqueue[ (count--, base++) ];
388
        CYG_ASSERT( 0 <= count, "Count went -ve" );
389
        CYG_ASSERT( size >= base, "Base overflow" );
390
        if ( size <= base )
391
            base = 0;
392
 
393
#ifdef CYGMFN_KERNEL_SYNCH_MBOXT_PUT_CAN_WAIT
394
        wakeup_waiter( put_threadq );
395
#endif
396
    }
397
 
398
    // Unlock the scheduler and maybe switch threads
399
    Cyg_Scheduler::unlock();
400
 
401
    return result;
402
}
403
 
404
// -------------------------------------------------------------------------
405
// get next item without removing it
406
template 
407
CYG_MBOXT_INLINE cyg_bool
408
Cyg_Mboxt::peek_item( T &ritem )
409
{
410
    CYG_REPORT_FUNCTION();
411
 
412
    // Prevent preemption
413
    Cyg_Scheduler::lock();
414
 
415
    CYG_ASSERTCLASS( this, "Bad this pointer");
416
 
417
    CYG_INSTRUMENT_MBOXT(TRY, this, count);
418
 
419
    cyg_bool result = ( 0 < count );
420
    // If the mboxt is not empty, grab an item and return it.
421
    if ( result )
422
        ritem = itemqueue[ base ];
423
 
424
    // Unlock the scheduler and maybe switch threads
425
    Cyg_Scheduler::unlock();
426
 
427
    return result;
428
}
429
 
430
// -------------------------------------------------------------------------
431
// Put an item in the queue; wait if full.
432
 
433
#ifdef CYGMFN_KERNEL_SYNCH_MBOXT_PUT_CAN_WAIT
434
template 
435
CYG_MBOXT_INLINE cyg_bool
436
Cyg_Mboxt::put( const T item )
437
{
438
    CYG_REPORT_FUNCTION();
439
    cyg_bool result = true;
440
 
441
    Cyg_Thread *self = Cyg_Thread::self();
442
 
443
    // Prevent preemption
444
    Cyg_Scheduler::lock();
445
 
446
    CYG_INSTRUMENT_MBOXT(PUT, this, count);
447
    CYG_ASSERTCLASS( this, "Bad this pointer");
448
 
449
    while ( result && (size == count) ) {
450
        self->set_sleep_reason( Cyg_Thread::WAIT );
451
        self->sleep();
452
        put_threadq.enqueue( self );
453
 
454
        CYG_INSTRUMENT_MBOXT(WAIT, this, count);
455
 
456
        // Allow other threads to run
457
        Cyg_Scheduler::reschedule();
458
 
459
        CYG_ASSERTCLASS( this, "Bad this pointer");
460
 
461
        switch( self->get_wake_reason() )
462
        {
463
        case Cyg_Thread::DESTRUCT:
464
        case Cyg_Thread::BREAK:
465
            result = false;
466
            break;
467
 
468
        case Cyg_Thread::EXIT:
469
            self->exit();
470
            break;
471
 
472
        default:
473
            break;
474
        }
475
    }
476
 
477
    if ( result ) {
478
        cyg_count32 in = base + (count++);
479
        if ( size <= in )
480
            in -= size;
481
 
482
        CYG_ASSERT( size > in, "in overflow" );
483
        CYG_ASSERT( 0 <= in, "in overflow" );
484
        CYG_ASSERT( size >= count, "count overflow" );
485
 
486
        itemqueue[ in ] = item;
487
 
488
        wakeup_waiter( get_threadq );
489
    }
490
    CYG_ASSERTCLASS( this, "Bad this pointer");
491
 
492
    // Unlock the scheduler and maybe switch threads
493
    Cyg_Scheduler::unlock();
494
    CYG_REPORT_RETVAL( result );
495
    return result;
496
}
497
 
498
// -------------------------------------------------------------------------
499
// Put an item in the queue; wait if full, with an absolute timeout;
500
// return success.
501
 
502
#ifdef CYGFUN_KERNEL_THREADS_TIMER
503
template 
504
CYG_MBOXT_INLINE cyg_bool
505
Cyg_Mboxt::put( const T item, cyg_tick_count abs_timeout )
506
{
507
    CYG_REPORT_FUNCTION();
508
    cyg_bool result = true;
509
 
510
    Cyg_Thread *self = Cyg_Thread::self();
511
 
512
    // Prevent preemption
513
    Cyg_Scheduler::lock();
514
 
515
    CYG_INSTRUMENT_MBOXT(PUT, this, count);
516
    CYG_ASSERTCLASS( this, "Bad this pointer");
517
 
518
    // Set the timer _once_ outside the loop.
519
    self->set_timer( abs_timeout, Cyg_Thread::TIMEOUT );
520
 
521
    // If the timeout is in the past, the wake reason will have been
522
    // set to something other than NONE already. Set the result false
523
    // to force an immediate return.
524
 
525
    if( self->get_wake_reason() != Cyg_Thread::NONE )
526
        result = false;
527
 
528
    // Loop while the mboxt is full, sleeping each time around the loop.
529
    // This copes with the possibility of a higher priority thread filling
530
    // the empty slot between the wakeup in get()&c and this thread
531
    // actually starting.
532
    while ( result && (size == count) ) {
533
        // must reset the sleep reason every time
534
        self->set_sleep_reason( Cyg_Thread::TIMEOUT );
535
        self->sleep();
536
        put_threadq.enqueue( self );
537
 
538
        CYG_INSTRUMENT_MBOXT(WAIT, this, count);
539
 
540
        // Allow other threads to run
541
        Cyg_Scheduler::reschedule();
542
 
543
        CYG_ASSERTCLASS( this, "Bad this pointer");
544
 
545
        switch( self->get_wake_reason() )
546
        {
547
        case Cyg_Thread::TIMEOUT:
548
            result = false;
549
            CYG_INSTRUMENT_MBOXT(TIMEOUT, this, count);
550
            break;
551
 
552
        case Cyg_Thread::DESTRUCT:
553
        case Cyg_Thread::BREAK:
554
            result = false;
555
            break;
556
 
557
        case Cyg_Thread::EXIT:
558
            self->exit();
559
            break;
560
 
561
        default:
562
            break;
563
        }
564
    }
565
 
566
    // clear the timer; if it actually fired, no worries.
567
    self->clear_timer();
568
 
569
    if ( result ) {
570
        cyg_count32 in = base + (count++);
571
        if ( size <= in )
572
            in -= size;
573
 
574
        CYG_ASSERT( size > in, "in overflow" );
575
        CYG_ASSERT( 0 <= in, "in overflow" );
576
        CYG_ASSERT( size >= count, "count overflow" );
577
 
578
        itemqueue[ in ] = item;
579
 
580
        wakeup_waiter( get_threadq );
581
    }
582
    CYG_ASSERTCLASS( this, "Bad this pointer");
583
 
584
    // Unlock the scheduler and maybe switch threads
585
    Cyg_Scheduler::unlock();
586
    CYG_REPORT_RETVAL( result );
587
    return result;
588
}
589
#endif // CYGFUN_KERNEL_THREADS_TIMER
590
#endif // CYGMFN_KERNEL_SYNCH_MBOXT_PUT_CAN_WAIT
591
 
592
// -------------------------------------------------------------------------
593
// Try to put an item in the queue and return success; queue may be full.
594
 
595
template 
596
CYG_MBOXT_INLINE cyg_bool
597
Cyg_Mboxt::tryput( const T item )
598
{
599
    CYG_REPORT_FUNCTION();
600
 
601
    // Prevent preemption
602
    Cyg_Scheduler::lock();
603
 
604
    CYG_INSTRUMENT_MBOXT(PUT, this, count);
605
    CYG_ASSERTCLASS( this, "Bad this pointer");
606
 
607
    if ( size == count ) {
608
        Cyg_Scheduler::unlock();        // unlock, maybe switch threads
609
        return false;                   // the mboxt is full
610
    }
611
 
612
    cyg_count32 in = base + (count++);
613
    if ( size <= in )
614
        in -= size;
615
 
616
    CYG_ASSERT( size > in, "in overflow" );
617
    CYG_ASSERT( 0 <= in, "in overflow" );
618
    CYG_ASSERT( size >= count, "count overflow" );
619
 
620
    itemqueue[ in ] = item;
621
 
622
    CYG_ASSERTCLASS( this, "Bad this pointer");
623
 
624
    wakeup_waiter( get_threadq );
625
 
626
    // Unlock the scheduler and maybe switch threads
627
    Cyg_Scheduler::unlock();
628
 
629
    return true;
630
}
631
 
632
 
633
// -------------------------------------------------------------------------
634
#endif // ifndef CYGONCE_KERNEL_MBOXT_INL
635
// EOF mboxt.inl

powered by: WebSVN 2.1.0

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