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

Subversion Repositories or1k

[/] [or1k/] [trunk/] [ecos-2.0/] [packages/] [kernel/] [v2_0/] [include/] [mboxt.inl] - Blame information for rev 1254

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

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

powered by: WebSVN 2.1.0

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