diff packages/kernel/current/include/mboxt2.inl @ 0:3111d98ba7b3 ecos-v1_1-release

Initial commit of eCos version 1.1
author jlarmour
date Tue, 11 May 1999 11:16:07 +0000
parents
children 443894e2e912
line wrap: on
line diff
new file mode 100644
--- /dev/null
+++ b/packages/kernel/current/include/mboxt2.inl
@@ -0,0 +1,681 @@
+#ifndef CYGONCE_KERNEL_MBOXT2_INL
+#define CYGONCE_KERNEL_MBOXT2_INL
+//==========================================================================
+//
+//	mboxt2.inl
+//
+//	Mboxt2 mbox template class implementation
+//
+//==========================================================================
+//####COPYRIGHTBEGIN####
+//
+// -------------------------------------------
+// The contents of this file are subject to the Cygnus eCos Public License
+// Version 1.0 (the "License"); you may not use this file except in
+// compliance with the License.  You may obtain a copy of the License at
+// http://sourceware.cygnus.com/ecos
+// 
+// Software distributed under the License is distributed on an "AS IS"
+// basis, WITHOUT WARRANTY OF ANY KIND, either express or implied.  See the
+// License for the specific language governing rights and limitations under
+// the License.
+// 
+// The Original Code is eCos - Embedded Cygnus Operating System, released
+// September 30, 1998.
+// 
+// The Initial Developer of the Original Code is Cygnus.  Portions created
+// by Cygnus are Copyright (C) 1998 Cygnus Solutions.  All Rights Reserved.
+// -------------------------------------------
+//
+//####COPYRIGHTEND####
+//==========================================================================
+//#####DESCRIPTIONBEGIN####
+//
+// Author(s): 	hmt
+// Contributors:	hmt
+// Date:	1998-02-10
+// Purpose:	Mboxt2 template implementation
+// Description:	This file contains the implementations of the mboxt2
+//              template classes.
+//
+//####DESCRIPTIONEND####
+//
+//==========================================================================
+
+#include <cyg/kernel/ktypes.h>         // base kernel types
+#include <cyg/infra/cyg_trac.h>        // tracing macros
+#include <cyg/infra/cyg_ass.h>         // assertion macros
+#include <cyg/kernel/instrmnt.h>       // instrumentation
+
+#include <cyg/kernel/mboxt2.hxx>       // our header
+
+#include <cyg/kernel/thread.inl>       // thread inlines
+#include <cyg/kernel/sched.inl>        // scheduler inlines
+#include <cyg/kernel/clock.inl>        // clock inlines
+
+// -------------------------------------------------------------------------
+// inline function for awakening waiting threads
+
+template <class T, cyg_count32 QUEUE_SIZE>
+inline void
+Cyg_Mboxt2<T,QUEUE_SIZE>::wakeup_winner( const T &msg )
+{
+    CYG_ASSERT( !get_threadq.empty(), "Where did the winner go?" );
+
+    // The queue is non-empty, so grab the next thread and wake it up.
+    Cyg_Thread *thread = get_threadq.dequeue();
+
+    CYG_ASSERTCLASS( thread, "Bad thread pointer");
+
+    T *msg_ret = (T *)(thread->get_wait_info());
+    *msg_ret = msg;
+
+    thread->set_wake_reason( Cyg_Thread::DONE );
+    thread->wake();
+        
+    CYG_INSTRUMENT_MBOXT(WAKE, this, thread);        
+}
+
+#ifdef CYGMFN_KERNEL_SYNCH_MBOXT_PUT_CAN_WAIT
+template <class T, cyg_count32 QUEUE_SIZE>
+inline void
+Cyg_Mboxt2<T,QUEUE_SIZE>::wakeup_putter( void )
+{
+    if( !put_threadq.empty() ) {
+        // The queue is non-empty, so grab the next thread and wake it up.
+        Cyg_Thread *thread = put_threadq.dequeue();
+
+        CYG_ASSERTCLASS( thread, "Bad thread pointer");
+
+        T *new_msg = (T *)(thread->get_wait_info());
+
+        cyg_count32 in = base + (count++);
+        if ( size <= in )
+            in -= size;
+
+        CYG_ASSERT( size > in, "in overflow" );
+        CYG_ASSERT( 0 <= in, "in overflow" );
+        CYG_ASSERT( size >= count, "count overflow" );
+
+        itemqueue[ in ] = *new_msg;
+
+        thread->set_wake_reason( Cyg_Thread::DONE );
+        thread->wake();
+        
+        CYG_INSTRUMENT_MBOXT(WAKE, this, thread);        
+    }
+}
+#endif
+
+// -------------------------------------------------------------------------
+// Constructor
+
+template <class T, cyg_count32 QUEUE_SIZE>
+Cyg_Mboxt2<T,QUEUE_SIZE>::Cyg_Mboxt2()
+{
+    CYG_REPORT_FUNCTION();
+    base = 0;
+    count = 0;
+    CYG_REPORT_RETURN();
+}
+
+// -------------------------------------------------------------------------
+// Destructor
+
+template <class T, cyg_count32 QUEUE_SIZE>
+Cyg_Mboxt2<T,QUEUE_SIZE>::~Cyg_Mboxt2()
+{
+    CYG_REPORT_FUNCTION();
+#if 0
+    CYG_ASSERT( 0 == count, "Deleting mboxt2 with messages");
+    CYG_ASSERT( get_threadq.empty(), "Deleting mboxt2 with threads waiting to get");
+#ifdef CYGMFN_KERNEL_SYNCH_MBOXT_PUT_CAN_WAIT
+    CYG_ASSERT( put_threadq.empty(), "Deleting mboxt2 with threads waiting to put");
+#endif
+#endif
+    // Prevent preemption
+    Cyg_Scheduler::lock();
+
+    while ( ! get_threadq.empty() ) {
+        Cyg_Thread *thread = get_threadq.dequeue();
+        thread->set_wake_reason( Cyg_Thread::DESTRUCT );
+        thread->wake();
+    }
+#ifdef CYGMFN_KERNEL_SYNCH_MBOXT_PUT_CAN_WAIT
+    while ( ! put_threadq.empty() ) {
+        Cyg_Thread *thread = put_threadq.dequeue();
+        thread->set_wake_reason( Cyg_Thread::DESTRUCT );
+        thread->wake();
+    }
+#endif
+
+    // Unlock the scheduler and maybe switch threads
+    Cyg_Scheduler::unlock();    
+    CYG_REPORT_RETURN();
+}
+
+// -------------------------------------------------------------------------
+// debugging/assert function
+
+#ifdef CYGDBG_USE_ASSERTS
+
+template <class T, cyg_count32 QUEUE_SIZE>
+cyg_bool 
+Cyg_Mboxt2<T,QUEUE_SIZE>::check_this(cyg_assert_class_zeal zeal)
+{
+    if ( Cyg_Thread::DESTRUCT == Cyg_Thread::self()->get_wake_reason() )
+        // then the whole thing is invalid, and we know it.
+        // so return OK, since this check should NOT make an error.
+        return true;
+
+    // check that we have a non-NULL pointer first
+    if( this == NULL ) return false;
+
+#if 0 // thread queues do not have checking funcs.
+    if ( ! get_threadq.check_this( zeal ) ) return false;
+#ifdef CYGMFN_KERNEL_SYNCH_MBOXT_PUT_CAN_WAIT
+    if ( ! put_threadq.check_this( zeal ) ) return false;
+#endif
+#endif
+
+    switch( zeal )
+    {
+    case cyg_system_test:
+    case cyg_extreme:
+    case cyg_thorough:
+    case cyg_quick:
+    case cyg_trivial:
+        // plenty of scope for fencepost problems here
+        if ( size < count ) return false;
+        if ( size <= base ) return false;
+        if ( 0 > count ) return false;
+        if ( 0 > base  ) return false;
+
+        // Comments about needing 2 queues elided; they're not true in this
+        // immediate-dispatch model.  I think we could get away with only
+        // one queue now, biut is it worth it?  4 bytes of redundant info
+        // buys a lot of correctness.
+      
+    case cyg_none:
+    default:
+        break;
+    };
+
+    return true;
+}
+
+#endif
+
+
+// -------------------------------------------------------------------------
+// From here downwards, these are the major functions of the template; if
+// being genuinely used as a template they should probably not be inlined.
+// If being used to construct a specific class, with explicit functions,
+// then they should be.  This is controlled by:
+
+#ifdef CYGIMP_MBOXT_INLINE
+#define CYG_MBOXT_INLINE inline
+#else
+#define CYG_MBOXT_INLINE
+#endif
+
+// -------------------------------------------------------------------------
+// Get an item, or wait for one to arrive
+
+template <class T, cyg_count32 QUEUE_SIZE>
+CYG_MBOXT_INLINE cyg_bool
+Cyg_Mboxt2<T,QUEUE_SIZE>::get( T &ritem )
+{
+    CYG_REPORT_FUNCTION();
+    Cyg_Thread *self = Cyg_Thread::self();
+    
+    // Prevent preemption
+    Cyg_Scheduler::lock();
+
+    CYG_ASSERTCLASS( this, "Bad this pointer");
+    
+    CYG_INSTRUMENT_MBOXT(GET, this, count);
+
+    if ( 0 < count ) {
+        CYG_INSTRUMENT_MBOXT(GOT, this, count);
+    
+        ritem = itemqueue[ (count--, base++) ];
+        CYG_ASSERT( 0 <= count, "Count went -ve" );
+        CYG_ASSERT( size >= base, "Base overflow" );
+
+        if ( size <= base )
+            base = 0;
+
+#ifdef CYGMFN_KERNEL_SYNCH_MBOXT_PUT_CAN_WAIT
+        wakeup_putter();
+#endif
+
+        // Unlock the scheduler and definitely switch threads
+        Cyg_Scheduler::unlock();
+
+        CYG_ASSERTCLASS( this, "Bad this pointer");
+        CYG_REPORT_RETVAL( true );
+        return true;
+    }
+
+    self->set_wait_info( (CYG_ADDRWORD)&ritem );
+    self->set_sleep_reason( Cyg_Thread::WAIT );
+    self->sleep();
+    get_threadq.enqueue( self );
+
+    CYG_INSTRUMENT_MBOXT(WAIT, this, count);
+    CYG_ASSERT( 1 == Cyg_Scheduler::get_sched_lock(),
+                "Called with non-zero scheduler lock");
+        
+    // Unlock scheduler and allow other threads to run
+    Cyg_Scheduler::unlock();
+
+    cyg_bool result = true;
+    switch( self->get_wake_reason() )
+    {
+    case Cyg_Thread::DESTRUCT:
+    case Cyg_Thread::BREAK:
+        result = false;
+        break;
+            
+    case Cyg_Thread::EXIT:            
+        self->exit();
+        break;
+
+    default:
+        break;
+    }
+    CYG_ASSERTCLASS( this, "Bad this pointer");    
+    CYG_REPORT_RETVAL( result );
+    return result;
+}
+
+
+// -------------------------------------------------------------------------
+// Try to get an item with an absolute timeout and return success.
+
+#ifdef CYGFUN_KERNEL_THREADS_TIMER
+template <class T, cyg_count32 QUEUE_SIZE>
+CYG_MBOXT_INLINE cyg_bool
+Cyg_Mboxt2<T,QUEUE_SIZE>::get( T &ritem, cyg_tick_count abs_timeout )
+{
+    CYG_REPORT_FUNCTION();
+        
+    Cyg_Thread *self = Cyg_Thread::self();
+    
+    // Prevent preemption
+    Cyg_Scheduler::lock();
+
+    CYG_ASSERTCLASS( this, "Bad this pointer");
+    
+    CYG_INSTRUMENT_MBOXT(GET, this, count);
+
+    if ( 0 < count ) {
+        CYG_INSTRUMENT_MBOXT(GOT, this, count);
+    
+        ritem = itemqueue[ (count--, base++) ];
+        CYG_ASSERT( 0 <= count, "Count went -ve" );
+        CYG_ASSERT( size >= base, "Base overflow" );
+
+        if ( size <= base )
+            base = 0;
+
+#ifdef CYGMFN_KERNEL_SYNCH_MBOXT_PUT_CAN_WAIT
+        wakeup_putter();
+#endif
+
+        // Unlock the scheduler and maybe switch threads
+        Cyg_Scheduler::unlock();
+
+        CYG_ASSERTCLASS( this, "Bad this pointer");
+        CYG_REPORT_RETVAL( true );
+        return true;
+    }
+
+    // Set the timer
+    self->set_timer( abs_timeout, Cyg_Thread::TIMEOUT );
+
+    // If the timeout is in the past, the wake reason will have been set to
+    // something other than NONE already. If so, skip the wait and go
+    // straight to unlock.
+    
+    if( Cyg_Thread::NONE == self->get_wake_reason() ) {
+        self->set_wait_info( (CYG_ADDRWORD)&ritem );
+        self->sleep();
+        get_threadq.enqueue( self );
+
+        CYG_INSTRUMENT_MBOXT(WAIT, this, count);
+    }
+
+    CYG_ASSERT( 1 == Cyg_Scheduler::get_sched_lock(),
+                "Called with non-zero scheduler lock");
+        
+    // Unlock scheduler and allow other threads to run
+    Cyg_Scheduler::unlock();
+
+    // clear the timer; if it actually fired, no worries.
+    self->clear_timer();
+
+    CYG_ASSERTCLASS( this, "Bad this pointer");        
+
+    cyg_bool result = true;
+    switch( self->get_wake_reason() )
+    {
+    case Cyg_Thread::TIMEOUT:
+        result = false;
+        CYG_INSTRUMENT_MBOXT(TIMEOUT, this, count);
+        break;
+        
+    case Cyg_Thread::DESTRUCT:
+    case Cyg_Thread::BREAK:
+        result = false;
+        break;
+            
+    case Cyg_Thread::EXIT:            
+        self->exit();
+        break;
+
+    default:
+        break;
+    }
+
+    CYG_REPORT_RETVAL( result );
+    return result;
+}
+#endif // CYGFUN_KERNEL_THREADS_TIMER
+
+// -------------------------------------------------------------------------
+// Try to get an item and return success.
+
+template <class T, cyg_count32 QUEUE_SIZE>
+CYG_MBOXT_INLINE cyg_bool
+Cyg_Mboxt2<T,QUEUE_SIZE>::tryget( T &ritem )
+{
+    CYG_REPORT_FUNCTION();
+        
+    CYG_ASSERTCLASS( this, "Bad this pointer");
+    
+    // Prevent preemption
+    Cyg_Scheduler::lock();
+
+    CYG_INSTRUMENT_MBOXT(TRY, this, count);
+    
+    cyg_bool result = ( 0 < count );
+    // If the mboxt2 is not empty, grab an item and return it.
+    if ( result ) {
+        ritem = itemqueue[ (count--, base++) ];
+        CYG_ASSERT( 0 <= count, "Count went -ve" );
+        CYG_ASSERT( size >= base, "Base overflow" );
+        if ( size <= base )
+            base = 0;
+
+#ifdef CYGMFN_KERNEL_SYNCH_MBOXT_PUT_CAN_WAIT
+        wakeup_putter();
+#endif
+    }
+
+    // Unlock the scheduler and maybe switch threads
+    Cyg_Scheduler::unlock();
+    CYG_REPORT_RETVAL( result );
+    return result;    
+}
+
+// -------------------------------------------------------------------------
+// get next item without removing it
+template <class T, cyg_count32 QUEUE_SIZE>
+CYG_MBOXT_INLINE cyg_bool
+Cyg_Mboxt2<T,QUEUE_SIZE>::peek_item( T &ritem )
+{
+    CYG_REPORT_FUNCTION();
+        
+    CYG_ASSERTCLASS( this, "Bad this pointer");
+    
+    // Prevent preemption
+    Cyg_Scheduler::lock();
+
+    CYG_INSTRUMENT_MBOXT(TRY, this, count);
+    
+    cyg_bool result = ( 0 < count );
+    // If the mboxt2 is not empty, grab an item and return it.
+    if ( result )
+        ritem = itemqueue[ base ];
+
+    // Unlock the scheduler and maybe switch threads
+    Cyg_Scheduler::unlock();
+    CYG_REPORT_RETVAL( result );
+    return result;    
+}
+
+// -------------------------------------------------------------------------
+// Put an item in the queue; wait if full.
+
+#ifdef CYGMFN_KERNEL_SYNCH_MBOXT_PUT_CAN_WAIT
+template <class T, cyg_count32 QUEUE_SIZE>
+CYG_MBOXT_INLINE cyg_bool
+Cyg_Mboxt2<T,QUEUE_SIZE>::put( const T item )
+{
+    CYG_REPORT_FUNCTION();
+        
+    Cyg_Thread *self = Cyg_Thread::self();
+
+    // Prevent preemption
+    Cyg_Scheduler::lock();
+
+    CYG_INSTRUMENT_MBOXT(PUT, this, count);
+    CYG_ASSERTCLASS( this, "Bad this pointer");
+
+    if ( size == count ) {
+        CYG_ASSERT( get_threadq.empty(), "Threads waiting AND queue full?" );
+
+        self->set_wait_info( (CYG_ADDRWORD)&item );
+        self->set_sleep_reason( Cyg_Thread::WAIT );
+        self->sleep();
+        put_threadq.enqueue( self );
+
+        CYG_INSTRUMENT_MBOXT(WAIT, this, count);
+        CYG_ASSERT( 1 == Cyg_Scheduler::get_sched_lock(),
+                    "Called with non-zero scheduler lock");
+        
+        // when this returns, our item is in the queue.
+        Cyg_Scheduler::unlock();        // unlock, switch threads
+
+        CYG_ASSERTCLASS( this, "Bad this pointer");    
+
+        cyg_bool result = true;
+        switch( self->get_wake_reason() )
+        {
+        case Cyg_Thread::DESTRUCT:
+        case Cyg_Thread::BREAK:
+            result = false;
+            break;
+            
+        case Cyg_Thread::EXIT:            
+            self->exit();
+            break;
+
+        default:
+            break;
+        }
+        CYG_REPORT_RETVAL( result );
+        return result;
+    }
+
+    if ( !get_threadq.empty() ) {
+        wakeup_winner( item );
+        Cyg_Scheduler::unlock();        // unlock, maybe switch threads
+        CYG_ASSERTCLASS( this, "Bad this pointer");    
+        CYG_REPORT_RETVAL( true );
+        return true;
+    }
+
+    cyg_count32 in = base + (count++);
+    if ( size <= in )
+        in -= size;
+
+    CYG_ASSERT( size > in, "in overflow" );
+    CYG_ASSERT( 0 <= in, "in overflow" );
+    CYG_ASSERT( size >= count, "count overflow" );
+
+    itemqueue[ in ] = item;
+
+    CYG_ASSERTCLASS( this, "Bad this pointer");    
+    
+    // Unlock the scheduler and maybe switch threads
+    Cyg_Scheduler::unlock();
+    CYG_REPORT_RETVAL( true );
+    return true;
+}
+
+// -------------------------------------------------------------------------
+// Put an item in the queue; wait if full, with an absolute timeout;
+// return success.
+
+#ifdef CYGFUN_KERNEL_THREADS_TIMER
+template <class T, cyg_count32 QUEUE_SIZE>
+CYG_MBOXT_INLINE cyg_bool
+Cyg_Mboxt2<T,QUEUE_SIZE>::put( const T item, cyg_tick_count abs_timeout )
+{
+    CYG_REPORT_FUNCTION();
+        
+    Cyg_Thread *self = Cyg_Thread::self();
+
+    // Prevent preemption
+    Cyg_Scheduler::lock();
+
+    CYG_INSTRUMENT_MBOXT(PUT, this, count);
+    CYG_ASSERTCLASS( this, "Bad this pointer");
+
+    if ( size == count ) {
+
+        CYG_ASSERT( get_threadq.empty(), "Threads waiting AND queue full?" );
+
+        // Set the timer
+        self->set_timer( abs_timeout, Cyg_Thread::TIMEOUT );
+
+        // If the timeout is in the past, the wake reason will have been set to
+        // something other than NONE already. If so, skip the wait and go
+        // straight to unlock.
+    
+        if( Cyg_Thread::NONE == self->get_wake_reason() ) {
+            self->set_wait_info( (CYG_ADDRWORD)&item );
+            self->sleep();
+            put_threadq.enqueue( self );
+
+            CYG_INSTRUMENT_MBOXT(WAIT, this, count);
+        }
+        CYG_ASSERT( 1 == Cyg_Scheduler::get_sched_lock(),
+                    "Called with non-zero scheduler lock");
+
+        // when this returns, our item is in the queue.
+        Cyg_Scheduler::unlock();        // unlock, switch threads
+
+        // clear the timer; if it actually fired, no worries.
+        self->clear_timer();
+
+        cyg_bool result = true;
+        switch( self->get_wake_reason() )
+        {
+        case Cyg_Thread::TIMEOUT:
+            result = false;
+            CYG_INSTRUMENT_MBOXT(TIMEOUT, this, count);
+            break;
+        
+        case Cyg_Thread::DESTRUCT:
+        case Cyg_Thread::BREAK:
+            result = false;
+            break;
+            
+        case Cyg_Thread::EXIT:            
+            self->exit();
+            break;
+
+        default:
+            break;
+        }
+
+        CYG_ASSERTCLASS( this, "Bad this pointer");    
+        CYG_REPORT_RETVAL( result );
+        return result;
+    }
+
+
+    if ( !get_threadq.empty() ) {
+        wakeup_winner( item );
+        Cyg_Scheduler::unlock();        // unlock, maybe switch threads
+        CYG_ASSERTCLASS( this, "Bad this pointer");    
+        CYG_REPORT_RETVAL( true );
+        return true;
+    }
+
+    cyg_count32 in = base + (count++);
+    if ( size <= in )
+        in -= size;
+
+    CYG_ASSERT( size > in, "in overflow" );
+    CYG_ASSERT( 0 <= in, "in overflow" );
+    CYG_ASSERT( size >= count, "count overflow" );
+
+    itemqueue[ in ] = item;
+
+    // Unlock the scheduler and maybe switch threads
+    Cyg_Scheduler::unlock();
+    CYG_ASSERTCLASS( this, "Bad this pointer");    
+    CYG_REPORT_RETVAL( true );
+    return true;
+}
+#endif // CYGFUN_KERNEL_THREADS_TIMER
+#endif // CYGMFN_KERNEL_SYNCH_MBOXT_PUT_CAN_WAIT
+
+// -------------------------------------------------------------------------
+// Try to put an item in the queue and return success; queue may be full.
+
+template <class T, cyg_count32 QUEUE_SIZE>
+CYG_MBOXT_INLINE cyg_bool
+Cyg_Mboxt2<T,QUEUE_SIZE>::tryput( const T item )
+{
+    CYG_REPORT_FUNCTION();
+        
+    // Prevent preemption
+    Cyg_Scheduler::lock();
+
+    CYG_INSTRUMENT_MBOXT(PUT, this, count);
+    CYG_ASSERTCLASS( this, "Bad this pointer");
+
+    if ( size == count ) {
+        CYG_ASSERT( get_threadq.empty(), "Threads waiting AND queue full?" );
+        Cyg_Scheduler::unlock();        // unlock, maybe switch threads
+        CYG_REPORT_RETVAL( false );
+        return false;                   // the mboxt2 is full
+    }
+
+    if ( !get_threadq.empty() ) {
+        CYG_ASSERT( 0 == count, "Threads waiting AND queue not empty" );
+        wakeup_winner( item );
+        Cyg_Scheduler::unlock();        // unlock, maybe switch threads
+        CYG_REPORT_RETVAL( true );
+        return true;
+    }
+
+    cyg_count32 in = base + (count++);
+    if ( size <= in )
+        in -= size;
+
+    CYG_ASSERT( size > in, "in overflow" );
+    CYG_ASSERT( 0 <= in, "in overflow" );
+    CYG_ASSERT( size >= count, "count overflow" );
+
+    itemqueue[ in ] = item;
+
+    CYG_ASSERTCLASS( this, "Bad this pointer");    
+
+    // Unlock the scheduler and maybe switch threads
+    Cyg_Scheduler::unlock();
+
+    CYG_REPORT_RETVAL( true );
+    return true;
+}
+
+
+// -------------------------------------------------------------------------
+#endif // ifndef CYGONCE_KERNEL_MBOXT2_INL
+// EOF mboxt2.inl