#ifndef CYGONCE_COMPAT_UITRON_UIT_FUNC_INL
#define CYGONCE_COMPAT_UITRON_UIT_FUNC_INL
//===========================================================================
//
//      uit_func.inl
//
//      uITRON compatibility functions
//
//===========================================================================
//####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,1999 Cygnus Solutions.  All Rights Reserved.
// -------------------------------------------
//
//####COPYRIGHTEND####
//===========================================================================
//#####DESCRIPTIONBEGIN####
//
// Author(s):   hmt
// Contributors:        hmt
// Date:        1998-03-13
// Purpose:     uITRON compatibility functions
// Description: 
//
//####DESCRIPTIONEND####
//
//===========================================================================

#ifdef CYGPKG_UITRON

#ifdef CYGPRI_UITRON_FUNCS_HERE_AND_NOW

#include <cyg/compat/uitron/uit_objs.hxx> // uITRON setup CYGNUM_UITRON_SEMAS

// kernel facilities only needed here
#include <cyg/kernel/intr.hxx>
#include <cyg/kernel/sched.hxx>

// and the implementations of other kernel facilities
#include <cyg/kernel/thread.inl>
#include <cyg/kernel/sched.inl>
#include <cyg/kernel/clock.inl>


// ------------------------------------------------------------------------
// The variable where dis_dsp/ena_dsp state is held:
extern cyg_uint32 cyg_uitron_dis_dsp_old_priority;

// ------------------------------------------------------------------------
// Parameter checking; either check the expression and return an error code
// if not true, or assert the truth with a made-up message.

#ifdef CYGSEM_UITRON_BAD_PARAMS_RETURN_ERRORS
// default: uitron error codes are returned
#define CYG_UIT_PARAMCHECK( _true_, _error_ ) CYG_MACRO_START           \
    if ( ! (_true_) ) return (_error_);                                 \
CYG_MACRO_END
#else
// ...but they are asserted if asserts are on
#define CYG_UIT_PARAMCHECK( _true_, _error_ ) CYG_MACRO_START           \
    CYG_ASSERT( (_true_), "CYG_UIT_PARAMCHECK fail: " #_true_ );        \
CYG_MACRO_END
#endif // else !CYGSEM_UITRON_BAD_PARAMS_RETURN_ERRORS

// ------------------------------------------------------------------------
// CYG_UITRON_CHECK_AND_GETP
// 
// Macro to rangecheck and do the addressing of a static uitron system
// object; _which_ sort of object is given, and token pasting is used
// horribly to get the static array, limits and the like.
//
// Usage:
//   INT snd_msg( ID mbxid, ... ) {
//      Cyg_Mbox *p;
//      CYG_UITRON_CHECK_AND_GETP_MBOXES( mbxid, p );
//      p->...(...);

// internal: plain assignment to the object pointer, from static array
#define CYG_UIT_SPTR( _which_, _idx_, _ptr_ ) CYG_MACRO_START           \
        (_ptr_) =  CYG_UITRON_OBJS( _which_ ) + ((_idx_) - 1);          \
CYG_MACRO_END

// internal: plain assignment to the object pointer, from pointer array
// with error checking.
#define CYG_UIT_SPTR_PTR( _which_, _idx_, _ptr_ ) CYG_MACRO_START       \
        (_ptr_) =  CYG_UITRON_PTRS( _which_ )[ ((_idx_) - 1) ];         \
        if ( NULL == (_ptr_) ) return E_NOEXS;                          \
CYG_MACRO_END

#define CYG_UITRON_CHECK_AND_GETP_DIRECT( _which_, _idx_, _ptr_ )       \
CYG_MACRO_START                                                         \
    CYG_UIT_PARAMCHECK( 0 < (_idx_), E_ID );                            \
    CYG_UIT_PARAMCHECK( CYG_UITRON_NUM( _which_ ) >= (_idx_), E_ID );   \
    CYG_UIT_SPTR( _which_, _idx_, _ptr_ );                              \
CYG_MACRO_END

#define CYG_UITRON_CHECK_AND_GETP_INDIRECT( _which_, _idx_, _ptr_ )     \
CYG_MACRO_START                                                         \
    CYG_UIT_PARAMCHECK( 0 < (_idx_), E_ID );                            \
    CYG_UIT_PARAMCHECK( CYG_UITRON_NUM( _which_ ) >= (_idx_), E_ID );   \
    CYG_UIT_SPTR_PTR( _which_, _idx_, _ptr_ );                          \
CYG_MACRO_END

// As above but for handler numbers which return E_PAR when out of range
#define CYG_UITRON_CHECK_AND_GETHDLR( _which_, _num_, _ptr_ )           \
CYG_MACRO_START                                                         \
    CYG_UIT_PARAMCHECK( 0 < (_num_), E_PAR );                           \
    CYG_UIT_PARAMCHECK( CYG_UITRON_NUM( _which_ ) >= (_num_), E_PAR );  \
    CYG_UIT_SPTR( _which_, _num_, _ptr_ );                              \
CYG_MACRO_END

// And a macro to check that creation of an object is OK
#define CYG_UITRON_CHECK_NO_OBJ_LOCK_SCHED( _which_, _idx_ )            \
CYG_MACRO_START                                                         \
    CYG_UIT_PARAMCHECK( 0 < (_idx_), E_ID );                            \
    CYG_UIT_PARAMCHECK( CYG_UITRON_NUM( _which_ ) >= (_idx_), E_ID );   \
    Cyg_Scheduler::lock();                                              \
    if ( NULL != CYG_UITRON_PTRS( _which_ )[ ((_idx_) - 1) ] ) {        \
        Cyg_Scheduler::unlock();                                        \
        return E_OBJ;                                                   \
    }                                                                   \
CYG_MACRO_END

// define a magic new operator in order to call constructors
#define CYG_UITRON_NEWFUNCTION( _class_ )                               \
inline void *operator new(size_t size, _class_ *ptr)                    \
{                                                                       \
    CYG_CHECK_DATA_PTR( ptr, "Bad pointer" );                           \
    return ptr;                                                         \
}

// now configury to support selectable create/delete support ie. an
// array of pointers to the objects themselves.
#ifdef CYGPKG_UITRON_TASKS_CREATE_DELETE
#define CYG_UITRON_CHECK_AND_GETP_TASKS( _idx_, _ptr_ )                 \
    CYG_UITRON_CHECK_AND_GETP_INDIRECT( TASKS, _idx_, _ptr_ )
#else
#define CYG_UITRON_CHECK_AND_GETP_TASKS( _idx_, _ptr_ )                 \
    CYG_UITRON_CHECK_AND_GETP_DIRECT( TASKS, _idx_, _ptr_ )
#endif

#ifdef CYGPKG_UITRON_SEMAS_CREATE_DELETE
#define CYG_UITRON_CHECK_AND_GETP_SEMAS( _idx_, _ptr_ )                 \
    CYG_UITRON_CHECK_AND_GETP_INDIRECT( SEMAS, _idx_, _ptr_ )
#else
#define CYG_UITRON_CHECK_AND_GETP_SEMAS( _idx_, _ptr_ )                 \
    CYG_UITRON_CHECK_AND_GETP_DIRECT( SEMAS, _idx_, _ptr_ )
#endif

#ifdef CYGPKG_UITRON_MBOXES_CREATE_DELETE
#define CYG_UITRON_CHECK_AND_GETP_MBOXES( _idx_, _ptr_ )                \
    CYG_UITRON_CHECK_AND_GETP_INDIRECT( MBOXES, _idx_, _ptr_ )
#else
#define CYG_UITRON_CHECK_AND_GETP_MBOXES( _idx_, _ptr_ )                \
    CYG_UITRON_CHECK_AND_GETP_DIRECT( MBOXES, _idx_, _ptr_ )
#endif

#ifdef CYGPKG_UITRON_FLAGS_CREATE_DELETE
#define CYG_UITRON_CHECK_AND_GETP_FLAGS( _idx_, _ptr_ )                 \
    CYG_UITRON_CHECK_AND_GETP_INDIRECT( FLAGS, _idx_, _ptr_ )
#else
#define CYG_UITRON_CHECK_AND_GETP_FLAGS( _idx_, _ptr_ )                 \
    CYG_UITRON_CHECK_AND_GETP_DIRECT( FLAGS, _idx_, _ptr_ )
#endif

#ifdef CYGPKG_UITRON_MEMPOOLFIXED_CREATE_DELETE
#define CYG_UITRON_CHECK_AND_GETP_MEMPOOLFIXED( _idx_, _ptr_ )          \
    CYG_UITRON_CHECK_AND_GETP_INDIRECT( MEMPOOLFIXED, _idx_, _ptr_ )
#else
#define CYG_UITRON_CHECK_AND_GETP_MEMPOOLFIXED( _idx_, _ptr_ )          \
    CYG_UITRON_CHECK_AND_GETP_DIRECT( MEMPOOLFIXED, _idx_, _ptr_ )
#endif

#ifdef CYGPKG_UITRON_MEMPOOLVAR_CREATE_DELETE
#define CYG_UITRON_CHECK_AND_GETP_MEMPOOLVAR( _idx_, _ptr_ )            \
    CYG_UITRON_CHECK_AND_GETP_INDIRECT( MEMPOOLVAR, _idx_, _ptr_ )
#else
#define CYG_UITRON_CHECK_AND_GETP_MEMPOOLVAR( _idx_, _ptr_ )            \
    CYG_UITRON_CHECK_AND_GETP_DIRECT( MEMPOOLVAR, _idx_, _ptr_ )
#endif

// ------------------------------------------------------------------------
// Common error checking macros

#if !defined( CYGSEM_UITRON_BAD_PARAMS_RETURN_ERRORS ) && \
    !defined( CYGDBG_USE_ASSERTS )
// if not checking and not asserted, these are removed to avoid usused
// variable warnings.
#define CYG_UITRON_CHECK_TASK_CONTEXT_SELF( _self_ )     CYG_EMPTY_STATEMENT
#define CYG_UITRON_CHECK_TASK_CONTEXT()                  CYG_EMPTY_STATEMENT
#define CYG_UITRON_CHECK_DISPATCH_ENABLED()              CYG_EMPTY_STATEMENT
#define CYG_UITRON_CHECK_DISPATCH_ENABLED_TMO( _tmout_ ) CYG_EMPTY_STATEMENT

#else
// the default:
// Check a task is actually a uITRON task
#define CYG_UITRON_CHECK_TASK_CONTEXT_SELF( _self_ ) CYG_MACRO_START    \
    CYG_UIT_PARAMCHECK(                                                 \
        (&cyg_uitron_TASKS[0] <= (_self_)) &&                           \
        ((_self_) < &cyg_uitron_TASKS[CYGNUM_UITRON_TASKS]),            \
                                  E_CTX );                              \
CYG_MACRO_END

#define CYG_UITRON_CHECK_TASK_CONTEXT() CYG_MACRO_START                 \
    Cyg_Thread *self = Cyg_Thread::self();                              \
    CYG_UITRON_CHECK_TASK_CONTEXT_SELF( self );                         \
CYG_MACRO_END

// Check dispatching is enabled for calls which might wait
#define CYG_UITRON_CHECK_DISPATCH_ENABLED()  CYG_MACRO_START            \
    CYG_UIT_PARAMCHECK( 0 == cyg_uitron_dis_dsp_old_priority, E_CTX );  \
CYG_MACRO_END

#define CYG_UITRON_CHECK_DISPATCH_ENABLED_TMO(_tmout_)  CYG_MACRO_START \
    CYG_UIT_PARAMCHECK( -1 <= (_tmout_), E_PAR );                       \
    if ( TMO_POL != (_tmout_) )                                         \
        CYG_UITRON_CHECK_DISPATCH_ENABLED();                            \
CYG_MACRO_END

#endif

#ifdef CYGSEM_UITRON_PARAMS_NULL_IS_GOOD_PTR
#define CYG_UIT_PARAMCHECK_PTR( _p_ )   CYG_MACRO_START                 \
        CYG_UIT_PARAMCHECK( NADR != (_p_), E_PAR );                     \
CYG_MACRO_END
#else // do check for NULL
#define CYG_UIT_PARAMCHECK_PTR( _p_ )   CYG_MACRO_START                 \
        CYG_UIT_PARAMCHECK( NADR != (_p_), E_PAR );                     \
        CYG_UIT_PARAMCHECK( NULL != (_p_), E_PAR );                     \
CYG_MACRO_END
#endif // !CYGSEM_UITRON_PARAMS_NULL_IS_GOOD_PTR

// ------------------------------------------------------------------------
// CYG_UITRON_FAIL_RETURN
//
// After a call which waits, it might return with success, or due to a
// timeout or a release wait (a forced escape from the waiting condition).
// This macro examines context and finds out which, then executes a return
// with the correct uITRON condition code.

#define CYG_UITRON_FAIL_RETURN_SELF( _self_ ) CYG_MACRO_START           \
    Cyg_Thread::cyg_reason reason = (_self_)->get_wake_reason();        \
    if ( Cyg_Thread::TIMEOUT  == reason )                               \
        return E_TMOUT;                                                 \
    if ( Cyg_Thread::BREAK    == reason )                               \
        return E_RLWAI;                                                 \
    if ( Cyg_Thread::DESTRUCT == reason )                               \
        return E_DLT;                                                   \
    return E_SYS; /* if no plausible reason was found */                \
CYG_MACRO_END

#define CYG_UITRON_FAIL_RETURN() CYG_MACRO_START                        \
    Cyg_Thread *self = Cyg_Thread::self();                              \
    CYG_UITRON_FAIL_RETURN_SELF( self );                                \
CYG_MACRO_END

// ------------------------------------------------------------------------
// Interrupts disabled?
#define CYG_UITRON_CHECK_CPU_UNLOC()                                    \
    CYG_UIT_PARAMCHECK( (Cyg_Interrupt::interrupts_enabled()), E_CTX )

// ------------------------------------------------------------------------
// the function definitions themselves:

// ******************************************************
// ***    6.5 C Language Interfaces                   ***
// ******************************************************

// - Task Management Functions

#ifdef CYGPKG_UITRON_TASKS_CREATE_DELETE
CYG_UITRON_NEWFUNCTION( Cyg_Thread )

CYG_UIT_FUNC_INLINE
ER
cre_tsk ( ID tskid, T_CTSK *pk_ctsk )
{
    ER ret = E_OK;
    CYG_UIT_PARAMCHECK_PTR( pk_ctsk );
    CYG_UITRON_CHECK_NO_OBJ_LOCK_SCHED( TASKS, tskid );

    Cyg_Thread *p = &(CYG_UITRON_OBJS( TASKS )[ tskid - 1 ]);
    cyg_uint32 state = p->get_state();
    if ( 0 == (state & Cyg_Thread::EXITED) )
        ret = E_OBJ; // how did it get to be running?
    else if ( ((INT)p->get_stack_size()) < pk_ctsk->stksz )
        ret = E_NOMEM; // more stack requested than available
    else {
        CYG_UITRON_PTRS( TASKS )[ tskid - 1 ] =
            new( p ) Cyg_Thread(
                (CYG_ADDRWORD)      pk_ctsk->itskpri,
                (cyg_thread_entry *)pk_ctsk->task,
                (CYG_ADDRWORD)      0,
                // preserve the original name and stack:
#ifdef CYGVAR_KERNEL_THREADS_NAME
                p->get_name(),
#else
                NULL,
#endif
                p->get_stack_base(),
                p->get_stack_size() );
        // but ensure the task state is dormant:
        // (it is not constructed dormant, but suspended)
        p->kill();
#ifdef CYGIMP_THREAD_PRIORITY
        // and record the initial priority outside the task too.
        CYG_UITRON_TASK_INITIAL_PRIORITY( tskid ) = pk_ctsk->itskpri;
#endif
    }
    Cyg_Scheduler::unlock();
    return ret;
}

CYG_UIT_FUNC_INLINE
ER
del_tsk ( ID tskid )
{
    Cyg_Thread *p;
    ER ret = E_OK;
    CYG_UITRON_CHECK_AND_GETP_TASKS( tskid, p );
    
    Cyg_Scheduler::lock();
    // deal with the race condition here
    if ( p != CYG_UITRON_PTRS( TASKS )[ tskid - 1 ] ) {
        Cyg_Scheduler::unlock();
        return E_NOEXS;
    }
    cyg_uint32 state = p->get_state();
    if ( state & Cyg_Thread::EXITED )
        // just disconnect the pointer from its object
        CYG_UITRON_PTRS( TASKS )[ tskid - 1 ] = NULL;
    else
        ret = E_OBJ;
    Cyg_Scheduler::unlock();
    return ret;
}
#endif // CYGPKG_UITRON_TASKS_CREATE_DELETE

CYG_UIT_FUNC_INLINE
ER
sta_tsk ( ID tskid, INT stacd )
{
    Cyg_Thread *p;
    ER ret = E_OK;
    CYG_UITRON_CHECK_AND_GETP_TASKS( tskid, p );
    
    Cyg_Scheduler::lock();
    cyg_uint32 state = p->get_state();
#ifdef CYGPKG_UITRON_TASKS_CREATE_DELETE
    // there is a race condition with deleting the task
    // so test it now that we have the scheduler locked
    if ( p != CYG_UITRON_PTRS( TASKS )[ tskid - 1 ] )
        ret = E_NOEXS;
    else // NOTE dangling else to the next line:
#endif
    if ( state & Cyg_Thread::EXITED ) {
        p->reinitialize();
#ifdef CYGIMP_THREAD_PRIORITY
        p->set_priority( CYG_UITRON_TASK_INITIAL_PRIORITY( tskid ) );
#endif
        p->set_entry_data( (CYG_ADDRWORD)stacd );
        p->force_resume();
    }
    else
        ret = E_OBJ;
    Cyg_Scheduler::unlock();
    return ret;
}

CYG_UIT_FUNC_INLINE
void
ext_tsk ( void )
{    
    Cyg_Thread::exit();
}

CYG_UIT_FUNC_INLINE
void
exd_tsk ( void )
{
#ifdef CYGPKG_UITRON_TASKS_CREATE_DELETE
    Cyg_Thread *p;

    Cyg_Scheduler::lock();
    p = Cyg_Thread::self();
    ID tskid = (p - (&cyg_uitron_TASKS[0])) + 1;    
    // just disconnect the pointer from its object
    CYG_UITRON_PTRS( TASKS )[ tskid - 1 ] = NULL;
    // Any associated storage management, and possibly calling the task
    // destructor, is for future versions.
#else
    // do nothing - deletion not supported so just exit...
#endif
    Cyg_Thread::exit();
    // does not return, does unlock the scheduler for us
}

CYG_UIT_FUNC_INLINE
ER
ter_tsk ( ID tskid )
{
    Cyg_Thread *p;
    ER ret = E_OK;
    CYG_UITRON_CHECK_AND_GETP_TASKS( tskid, p );
    CYG_UIT_PARAMCHECK( Cyg_Thread::self() != p, E_OBJ );
    Cyg_Scheduler::lock();
    if ( (0 != (Cyg_Thread::EXITED & p->get_state())) ||
         (Cyg_Thread::EXIT == p->get_wake_reason()) )
        // already dormant
        ret = E_OBJ;
    else {
        p->force_resume(); // let it run
        p->kill(); // and set prio high so it runs RIGHT NOW!!
#ifdef CYGIMP_THREAD_PRIORITY
#if CYG_SCHED_UNIQUE_PRIORITIES != 0
        // see if we are already at prio 0:
        if ( 0 == cyg_uitron_dis_dsp_old_priority )
            // then dispatch is enabled, we are not at prio 0
#endif
            p->set_priority( (cyg_priority) 0 );
        // if we do not do this, then we are not running a strictly
        // uITRON compatible scheduler - so just hope for the best.
#endif
    }
    Cyg_Scheduler::unlock();
#ifdef CYGIMP_THREAD_PRIORITY
#if CYG_SCHED_UNIQUE_PRIORITIES == 0
    if ( (E_OK == ret) && (0 != cyg_uitron_dis_dsp_old_priority) ) {
        // then dispatching is disabled, so our prio is 0 too
        Cyg_Thread::yield(); // so let the dying thread run;
        Cyg_Thread::yield(); // no cost here of making sure.
    }
#endif
#endif
    return ret;
}

CYG_UIT_FUNC_INLINE
ER
dis_dsp ( void )
{
    CYG_UITRON_CHECK_TASK_CONTEXT();
    CYG_UITRON_CHECK_CPU_UNLOC();
    Cyg_Scheduler::lock();
    // Prevent preemption by going up to prio 0
    if ( 0 == cyg_uitron_dis_dsp_old_priority ) {
#ifdef CYGIMP_THREAD_PRIORITY
        Cyg_Thread *p = Cyg_Thread::self();
        cyg_uitron_dis_dsp_old_priority = p->get_priority();
        p->set_priority( 0 );
#else
        cyg_uitron_dis_dsp_old_priority = 1;
#endif
    }
    Cyg_Scheduler::unlock();
    return E_OK;
}

CYG_UIT_FUNC_INLINE
ER
ena_dsp ( void )
{
    CYG_UITRON_CHECK_TASK_CONTEXT();
    CYG_UITRON_CHECK_CPU_UNLOC();
    Cyg_Scheduler::lock();
    // Enable dispatching (if disabled) and maybe switch threads
    if ( 0 != cyg_uitron_dis_dsp_old_priority ) {
        // We had prevented preemption by going up to prio 0
#ifdef CYGIMP_THREAD_PRIORITY
        Cyg_Thread *p = Cyg_Thread::self();
        p->set_priority( cyg_uitron_dis_dsp_old_priority );
        p->to_queue_head(); // to ensure we continue to run
                            // if nobody higher pri
#endif
        cyg_uitron_dis_dsp_old_priority = 0;
    }
    Cyg_Scheduler::unlock();
    CYG_UITRON_CHECK_DISPATCH_ENABLED(); // NB: afterwards!
    return E_OK;
}


CYG_UIT_FUNC_INLINE
ER
chg_pri ( ID tskid, PRI tskpri )
{
    Cyg_Thread *p;
    ER ret = E_OK;
    if ( 0 == tskid ) {
        p = Cyg_Thread::self();
        CYG_UITRON_CHECK_TASK_CONTEXT_SELF( p );
    }
    else
        CYG_UITRON_CHECK_AND_GETP_TASKS( tskid, p );

#ifdef CYGIMP_THREAD_PRIORITY
    if ( 0 == tskpri )
        // then use the initial priority [Level X]
        tskpri = CYG_UITRON_TASK_INITIAL_PRIORITY( tskid );
#endif
    CYG_UIT_PARAMCHECK( 0 < tskpri, E_PAR );
#ifdef CYGIMP_THREAD_PRIORITY
#if CYG_THREAD_MAX_PRIORITY < CYG_THREAD_MIN_PRIORITY
    CYG_UIT_PARAMCHECK( CYG_THREAD_MAX_PRIORITY <= tskpri &&
                        tskpri <= CYG_THREAD_MIN_PRIORITY, E_PAR );
#else    
    CYG_UIT_PARAMCHECK( CYG_THREAD_MAX_PRIORITY >= tskpri &&
                        tskpri >= CYG_THREAD_MIN_PRIORITY, E_PAR );
#endif
    // Handle changing our own prio specially, if dispatch disabled:
    if ( 0 != cyg_uitron_dis_dsp_old_priority ) {
        // our actual prio is 0 now and must remain so:
        if ( Cyg_Thread::self() == p ) {  // by whichever route p was set
            // set the priority we will return to when dispatch is enabled:
            cyg_uitron_dis_dsp_old_priority = (cyg_uint32)tskpri;
            return E_OK;
        }
    }
    Cyg_Scheduler::lock();
    if ( (p->get_state() & (Cyg_Thread::EXITED | Cyg_Thread::CREATING)) ||
         (Cyg_Thread::EXIT == p->get_wake_reason()) )
        ret = E_OBJ; // task is dormant
    else
        p->set_priority( (cyg_priority)tskpri );
    Cyg_Scheduler::unlock();
#endif // CYGIMP_THREAD_PRIORITY got priorities at all?
    return ret;
}

CYG_UIT_FUNC_INLINE
ER
rot_rdq ( PRI tskpri )
{
    // zero means our level; easiet way is to yield() the CPU.
    if ( 0 == tskpri ) {
        Cyg_Thread::yield();
        return E_OK;
    }
#ifdef CYGIMP_THREAD_PRIORITY
#if CYG_THREAD_MAX_PRIORITY < CYG_THREAD_MIN_PRIORITY
    CYG_UIT_PARAMCHECK( CYG_THREAD_MAX_PRIORITY <= tskpri &&
                        tskpri <= CYG_THREAD_MIN_PRIORITY, E_PAR );
#else    
    CYG_UIT_PARAMCHECK( CYG_THREAD_MAX_PRIORITY >= tskpri &&
                        tskpri >= CYG_THREAD_MIN_PRIORITY, E_PAR );
#endif
    Cyg_Thread::rotate_queue( tskpri );
#endif // CYGIMP_THREAD_PRIORITY got priorities at all?
    return E_OK;
}

CYG_UIT_FUNC_INLINE
ER
rel_wai ( ID tskid )
{
    Cyg_Thread *p;
    ER ret = E_OK;
    CYG_UITRON_CHECK_AND_GETP_TASKS( tskid, p );
    CYG_UIT_PARAMCHECK( Cyg_Thread::self() != p, E_OBJ );
    Cyg_Scheduler::lock();              // get an atomic view of the task
    if ( (p->get_state() & (Cyg_Thread::EXITED | Cyg_Thread::CREATING)) ||
         (Cyg_Thread::EXIT == p->get_wake_reason()) )
        ret = E_OBJ;                    // task is dormant
    else {
        p->release();
        // return E_OBJ if the thread was not sleeping
        if ( Cyg_Thread::BREAK != p->get_wake_reason() )
            ret = E_OBJ;
    }
    Cyg_Scheduler::unlock();
    return ret;
}

CYG_UIT_FUNC_INLINE
ER
get_tid ( ID *p_tskid )
{
    Cyg_Thread *self = Cyg_Thread::self();
    CYG_UIT_PARAMCHECK_PTR( p_tskid );
    if ( (&cyg_uitron_TASKS[0] <= (self)) &&
        ((self) < &cyg_uitron_TASKS[CYGNUM_UITRON_TASKS]) )
        // then I am a uITRON task
        *p_tskid = (self - (&cyg_uitron_TASKS[0])) + 1;
    else
        *p_tskid = 0; // Otherwise, non-task portion
    return E_OK;
}

CYG_UIT_FUNC_INLINE
ER
ref_tsk ( T_RTSK *pk_rtsk, ID tskid )
{
    Cyg_Thread *p;
    if ( 0 == tskid ) {
        p = Cyg_Thread::self();
        CYG_UITRON_CHECK_TASK_CONTEXT_SELF( p );
        tskid = (p - (&cyg_uitron_TASKS[0])) + 1; // it gets used below
    }
    else
        CYG_UITRON_CHECK_AND_GETP_TASKS( tskid, p );

    CYG_UIT_PARAMCHECK_PTR( pk_rtsk );
    pk_rtsk->exinf  = NADR;
    Cyg_Scheduler::lock();              // get an atomic view of the task
    cyg_uint32 state = p->get_state();
    if ( (state & (Cyg_Thread::EXITED | Cyg_Thread::CREATING)) ||
         (Cyg_Thread::EXIT == p->get_wake_reason()) )
        pk_rtsk->tskstat = TTS_DMT;
    else if ( state == Cyg_Thread::RUNNING )
        // If it's us, it's running, else it's ready
        pk_rtsk->tskstat = (Cyg_Thread::self() == p)
            ? TTS_RUN                   // RUN state (we are it)
            : TTS_RDY;                  // READY state
    else if ( state & Cyg_Thread::SUSPENDED )
        pk_rtsk->tskstat =
            (state & (Cyg_Thread::COUNTSLEEP | Cyg_Thread::SLEEPING))
            ? TTS_WAS                   // WAIT-SUSPEND state
            : TTS_SUS;                  // SUSPEND state
    else
        pk_rtsk->tskstat =
            (state & (Cyg_Thread::COUNTSLEEP | Cyg_Thread::SLEEPING))
            ? TTS_WAI                   // WAIT state
            : 0;                        // Not sure what's happening here!
#ifdef CYGIMP_THREAD_PRIORITY
    if ( TTS_DMT == pk_rtsk->tskstat )
        pk_rtsk->tskpri = CYG_UITRON_TASK_INITIAL_PRIORITY( tskid );
    else if ( (TTS_RUN == pk_rtsk->tskstat) && 
              (0 != cyg_uitron_dis_dsp_old_priority) )
        // then we are it and dispatching is disabled, so
        // report our "real" priority - it is 0 in the kernel at the moment
        pk_rtsk->tskpri = cyg_uitron_dis_dsp_old_priority;
    else
        pk_rtsk->tskpri = p->get_priority();
#else
    pk_rtsk->tskpri = -1;  // Not applicable
#endif
    Cyg_Scheduler::unlock();
    return E_OK;
}
        
// - Task-Dependent Synchronization Functions
        
CYG_UIT_FUNC_INLINE
ER
sus_tsk ( ID tskid )
{
    Cyg_Thread *p;
    ER ret = E_OK;
    CYG_UITRON_CHECK_AND_GETP_TASKS( tskid, p );
    CYG_UIT_PARAMCHECK( Cyg_Thread::self() != p, E_OBJ );
    Cyg_Scheduler::lock();              // get an atomic view of the task
    if ( (p->get_state() & (Cyg_Thread::EXITED | Cyg_Thread::CREATING)) ||
         (Cyg_Thread::EXIT == p->get_wake_reason()) )
        ret = E_OBJ;                    // task is dormant
    else
        p->suspend();
    Cyg_Scheduler::unlock();
    return ret;
}

CYG_UIT_FUNC_INLINE
ER
rsm_tsk ( ID tskid )
{
    Cyg_Thread *p;
    ER ret = E_OK;
    CYG_UITRON_CHECK_AND_GETP_TASKS( tskid, p );
    CYG_UIT_PARAMCHECK( Cyg_Thread::self() != p, E_OBJ );
    Cyg_Scheduler::lock();              // get an atomic view of the task
    cyg_uint32 state = p->get_state();
    if ( 0 == (Cyg_Thread::SUSPENDED & state) )
        ret = E_OBJ;                    // thread is not suspended
    else
        p->resume();
    Cyg_Scheduler::unlock();
    return ret;
}

CYG_UIT_FUNC_INLINE
ER
frsm_tsk ( ID tskid )
{
    Cyg_Thread *p;
    ER ret = E_OK;
    CYG_UITRON_CHECK_AND_GETP_TASKS( tskid, p );
    CYG_UIT_PARAMCHECK( Cyg_Thread::self() != p, E_OBJ );
    Cyg_Scheduler::lock();              // get an atomic view of the task
    cyg_uint32 state = p->get_state();
    if ( 0 == (Cyg_Thread::SUSPENDED & state) )
        ret = E_OBJ;                    // thread is not suspended
    else
        p->force_resume();
    Cyg_Scheduler::unlock();
    return ret;
}

CYG_UIT_FUNC_INLINE
ER
slp_tsk ( void )
{
    Cyg_Thread *self = Cyg_Thread::self();
    CYG_UITRON_CHECK_TASK_CONTEXT_SELF( self );
    CYG_UITRON_CHECK_DISPATCH_ENABLED();
    // do this now for the case when no sleeping actually occurs
    self->set_wake_reason( Cyg_Thread::DONE );
    Cyg_Thread::counted_sleep();
    if ( Cyg_Thread::DONE != self->get_wake_reason() )
        CYG_UITRON_FAIL_RETURN_SELF( self );
    return E_OK;
}

#ifdef CYGFUN_KERNEL_THREADS_TIMER
CYG_UIT_FUNC_INLINE
ER
tslp_tsk ( TMO tmout )
{
    Cyg_Thread *self = Cyg_Thread::self();
    CYG_UITRON_CHECK_TASK_CONTEXT_SELF( self );
    CYG_UIT_PARAMCHECK( -1 <= tmout, E_PAR );
    CYG_UITRON_CHECK_DISPATCH_ENABLED();
    // do this now for the case when no sleeping actually occurs
    self->set_wake_reason( Cyg_Thread::DONE );
    // note that TMO_POL is not treated specially, though it
    // happens to work almost as a poll (some sleeping may occur)
    if ( TMO_FEVR == tmout )
        Cyg_Thread::counted_sleep();
    else
        Cyg_Thread::counted_sleep( (cyg_tick_count)tmout );
    if ( Cyg_Thread::DONE != self->get_wake_reason() )
        CYG_UITRON_FAIL_RETURN_SELF( self );
    return E_OK;
}
#endif // CYGFUN_KERNEL_THREADS_TIMER

CYG_UIT_FUNC_INLINE
ER
wup_tsk ( ID tskid )
{
    Cyg_Thread *p;
    ER ret = E_OK;
    CYG_UITRON_CHECK_AND_GETP_TASKS( tskid, p );
    CYG_UIT_PARAMCHECK( Cyg_Thread::self() != p, E_OBJ );
    Cyg_Scheduler::lock();              // get an atomic view of the task
    if ( (p->get_state() & (Cyg_Thread::EXITED | Cyg_Thread::CREATING)) ||
         (Cyg_Thread::EXIT == p->get_wake_reason()) )
        ret = E_OBJ;                    // task is dormant
    else
        p->counted_wake();
    Cyg_Scheduler::unlock();
    return ret;
}

CYG_UIT_FUNC_INLINE
ER
can_wup ( INT *p_wupcnt, ID tskid )
{
    Cyg_Thread *p;
    ER ret = E_OK;
    if ( 0 == tskid ) {
        p = Cyg_Thread::self();
        CYG_UITRON_CHECK_TASK_CONTEXT_SELF( p );
    }
    else
        CYG_UITRON_CHECK_AND_GETP_TASKS( tskid, p );
    CYG_UIT_PARAMCHECK_PTR( p_wupcnt );
    Cyg_Scheduler::lock();              // get an atomic view of the task
    if ( (p->get_state() & (Cyg_Thread::EXITED | Cyg_Thread::CREATING)) ||
         (Cyg_Thread::EXIT == p->get_wake_reason()) )
        ret = E_OBJ;                    // task is dormant
    else {
        cyg_uint32 result = p->cancel_counted_wake();
        *p_wupcnt = result;
    }
    Cyg_Scheduler::unlock();
    return ret;
}
        
// - Synchronization and Communication Functions
        
#ifdef CYGPKG_UITRON_SEMAS
#if 0 < CYG_UITRON_NUM( SEMAS )

#ifdef CYGPKG_UITRON_SEMAS_CREATE_DELETE

CYG_UITRON_NEWFUNCTION( Cyg_Counting_Semaphore2 )

CYG_UIT_FUNC_INLINE
ER
cre_sem ( ID semid, T_CSEM *pk_csem )
{
    ER ret = E_OK;
    CYG_UIT_PARAMCHECK_PTR( pk_csem );
    CYG_UITRON_CHECK_NO_OBJ_LOCK_SCHED( SEMAS, semid );
    if ( TA_TFIFO != pk_csem->sematr )
        ret = E_RSATR;
    else
        CYG_UITRON_PTRS( SEMAS )[ semid - 1 ] =
            new( &(CYG_UITRON_OBJS( SEMAS )[ semid - 1 ]) )
            Cyg_Counting_Semaphore2( (cyg_count32)pk_csem->isemcnt );
    Cyg_Scheduler::unlock();
    return ret;
}

CYG_UIT_FUNC_INLINE
ER
del_sem ( ID semid )
{
    Cyg_Counting_Semaphore2 *p;
    CYG_UITRON_CHECK_AND_GETP_SEMAS( semid, p );
    Cyg_Scheduler::lock();
    // deal with the race condition here
    if ( p != CYG_UITRON_PTRS( SEMAS )[ semid - 1 ] ) {
        Cyg_Scheduler::unlock();
        return E_NOEXS;
    }
    CYG_UITRON_PTRS( SEMAS )[ semid - 1 ] = NULL;
    p->~Cyg_Counting_Semaphore2();
    Cyg_Scheduler::unlock();
    return E_OK;
}
#endif // CYGPKG_UITRON_SEMAS_CREATE_DELETE

CYG_UIT_FUNC_INLINE
ER
sig_sem( ID semid )
{
    Cyg_Counting_Semaphore2 *p;
    CYG_UITRON_CHECK_AND_GETP_SEMAS( semid, p );
    p->post();
    return E_OK;
}

CYG_UIT_FUNC_INLINE
ER
wai_sem( ID semid )
{
    Cyg_Counting_Semaphore2 *p;
    CYG_UITRON_CHECK_AND_GETP_SEMAS( semid, p );
    CYG_UITRON_CHECK_DISPATCH_ENABLED();
    cyg_bool result = p->wait();
    if ( !result )
        CYG_UITRON_FAIL_RETURN();
    return E_OK;
}

CYG_UIT_FUNC_INLINE
ER
preq_sem ( ID semid )
{
    Cyg_Counting_Semaphore2 *p;
    CYG_UITRON_CHECK_AND_GETP_SEMAS( semid, p );
    cyg_bool result = p->trywait();
    if ( !result )
        return E_TMOUT;
    return E_OK;
}

#ifdef CYGFUN_KERNEL_THREADS_TIMER
CYG_UIT_FUNC_INLINE
ER
twai_sem ( ID semid, TMO tmout )
{
    Cyg_Counting_Semaphore2 *p;
    CYG_UITRON_CHECK_AND_GETP_SEMAS( semid, p );
    CYG_UITRON_CHECK_DISPATCH_ENABLED_TMO( tmout );
    // do this now for the case when no sleeping actually occurs
    Cyg_Thread *self = Cyg_Thread::self();
    self->set_wake_reason( Cyg_Thread::TIMEOUT );
    cyg_bool result;
    if ( TMO_FEVR == tmout )
        result = p->wait();
    else if ( TMO_POL == tmout )
        result = p->trywait();
    else
        result = p->wait(
            Cyg_Clock::real_time_clock->current_value() +
            (cyg_tick_count)tmout );
    if ( ! result )
        CYG_UITRON_FAIL_RETURN_SELF( self );
    return E_OK;

}
#endif // CYGFUN_KERNEL_THREADS_TIMER

CYG_UIT_FUNC_INLINE
ER
ref_sem ( T_RSEM *pk_rsem, ID semid )
{
    Cyg_Counting_Semaphore2 *p;
    CYG_UITRON_CHECK_AND_GETP_SEMAS( semid, p );
    CYG_UIT_PARAMCHECK_PTR( pk_rsem );
    pk_rsem->exinf  = NADR;
    pk_rsem->wtsk   = p->waiting();
    pk_rsem->semcnt = p->peek();
    return E_OK;
}

#endif // 0 < CYG_UITRON_NUM( SEMAS )
#endif // CYGPKG_UITRON_SEMAS

#ifdef CYGPKG_UITRON_FLAGS
#if 0 < CYG_UITRON_NUM( FLAGS )

#ifdef CYGPKG_UITRON_FLAGS_CREATE_DELETE

CYG_UITRON_NEWFUNCTION( Cyg_Flag )

CYG_UIT_FUNC_INLINE
ER
cre_flg ( ID flgid, T_CFLG *pk_cflg )
{
    ER ret = E_OK;
    CYG_UIT_PARAMCHECK_PTR( pk_cflg );
    CYG_UITRON_CHECK_NO_OBJ_LOCK_SCHED( FLAGS, flgid );
    if ( 0 != ((~(TA_WMUL | TA_WSGL)) & pk_cflg->flgatr) )
        ret = E_RSATR;
    else
        CYG_UITRON_PTRS( FLAGS )[ flgid - 1 ] =
            new( &(CYG_UITRON_OBJS( FLAGS )[ flgid - 1 ]) )
            Cyg_Flag( (Cyg_FlagValue) pk_cflg->iflgptn );
    Cyg_Scheduler::unlock();
    return ret;
}

CYG_UIT_FUNC_INLINE
ER
del_flg ( ID flgid )
{
    Cyg_Flag *p;
    CYG_UITRON_CHECK_AND_GETP_FLAGS( flgid, p );
    Cyg_Scheduler::lock();
    // deal with the race condition here
    if ( p != CYG_UITRON_PTRS( FLAGS )[ flgid - 1 ] ) {
        Cyg_Scheduler::unlock();
        return E_NOEXS;
    }
    CYG_UITRON_PTRS( FLAGS )[ flgid - 1 ] = NULL;
    p->~Cyg_Flag();
    Cyg_Scheduler::unlock();
    return E_OK;
}
#endif // CYGPKG_UITRON_FLAGS_CREATE_DELETE

CYG_UIT_FUNC_INLINE
ER
set_flg ( ID flgid, UINT setptn )
{
    Cyg_Flag *p;
    CYG_UITRON_CHECK_AND_GETP_FLAGS( flgid, p );
    p->setbits( setptn );
    return E_OK;
}

CYG_UIT_FUNC_INLINE
ER
clr_flg ( ID flgid, UINT clrptn )
{
    Cyg_Flag *p;
    CYG_UITRON_CHECK_AND_GETP_FLAGS( flgid, p );
    p->maskbits( clrptn );
    return E_OK;
}

CYG_UIT_FUNC_INLINE
ER
wai_flg ( UINT *p_flgptn, ID flgid, UINT waiptn, UINT wfmode )
{
    Cyg_Flag *p;
    CYG_UITRON_CHECK_AND_GETP_FLAGS( flgid, p );
    CYG_UIT_PARAMCHECK_PTR( p_flgptn );
    CYG_UIT_PARAMCHECK( 0 == (wfmode & ~Cyg_Flag::MASK), E_PAR );
    CYG_UIT_PARAMCHECK( 0 != waiptn, E_PAR );
    CYG_UITRON_CHECK_DISPATCH_ENABLED();
    // check we can use the wfmode value unchanged
    CYG_ASSERT( Cyg_Flag::AND == TWF_ANDW, "Flag AND value bad" );
    CYG_ASSERT( Cyg_Flag::OR  == TWF_ORW,  "Flag OR value bad" );
    CYG_ASSERT( Cyg_Flag::CLR == TWF_CLR,  "Flag CLR value bad" );

    UINT result = p->wait( waiptn, wfmode );
    if ( ! result )
        CYG_UITRON_FAIL_RETURN();
    *p_flgptn  = result;
    return E_OK;
}

CYG_UIT_FUNC_INLINE
ER
pol_flg ( UINT *p_flgptn, ID flgid, UINT waiptn, UINT wfmode )
{
    Cyg_Flag *p;
    CYG_UITRON_CHECK_AND_GETP_FLAGS( flgid, p );
    CYG_UIT_PARAMCHECK_PTR( p_flgptn );
    CYG_UIT_PARAMCHECK( 0 == (wfmode & ~Cyg_Flag::MASK), E_PAR );
    CYG_UIT_PARAMCHECK( 0 != waiptn, E_PAR );
    // check we can use the wfmode value unchanged
    CYG_ASSERT( Cyg_Flag::AND == TWF_ANDW, "Flag AND value bad" );
    CYG_ASSERT( Cyg_Flag::OR  == TWF_ORW,  "Flag OR value bad" );
    CYG_ASSERT( Cyg_Flag::CLR == TWF_CLR,  "Flag CLR value bad" );

    UINT result = p->poll( waiptn, wfmode );
    if ( ! result )
        return E_TMOUT;
    *p_flgptn  = result;
    return E_OK;
}

#ifdef CYGFUN_KERNEL_THREADS_TIMER
CYG_UIT_FUNC_INLINE
ER
twai_flg ( UINT *p_flgptn, ID flgid, UINT waiptn, UINT wfmode,
              TMO tmout )
{
    Cyg_Flag *p;
    CYG_UITRON_CHECK_AND_GETP_FLAGS( flgid, p );
    CYG_UIT_PARAMCHECK_PTR( p_flgptn );
    CYG_UIT_PARAMCHECK( 0 == (wfmode & ~Cyg_Flag::MASK), E_PAR );
    CYG_UIT_PARAMCHECK( 0 != waiptn, E_PAR );
    CYG_UITRON_CHECK_DISPATCH_ENABLED_TMO( tmout );
    // check we can use the wfmode value unchanged
    CYG_ASSERT( Cyg_Flag::AND == TWF_ANDW, "Flag AND value bad" );
    CYG_ASSERT( Cyg_Flag::OR  == TWF_ORW,  "Flag OR value bad" );
    CYG_ASSERT( Cyg_Flag::CLR == TWF_CLR,  "Flag CLR value bad" );

    // do this now for the case when no sleeping actually occurs
    Cyg_Thread *self = Cyg_Thread::self();
    self->set_wake_reason( Cyg_Thread::TIMEOUT );
    UINT result;
    if ( TMO_FEVR == tmout )
        result = p->wait( waiptn, wfmode );
    else if ( TMO_POL == tmout )
        result = p->poll( waiptn, wfmode );
    else
        result = p->wait( waiptn, wfmode,
                          Cyg_Clock::real_time_clock->current_value() +
                          (cyg_tick_count)tmout );
    if ( ! result )
        CYG_UITRON_FAIL_RETURN_SELF( self );
    *p_flgptn  = result;
    return E_OK;
}
#endif // CYGFUN_KERNEL_THREADS_TIMER

CYG_UIT_FUNC_INLINE
ER
ref_flg ( T_RFLG *pk_rflg, ID flgid )
{
    Cyg_Flag *p;
    CYG_UITRON_CHECK_AND_GETP_FLAGS( flgid, p );
    CYG_UIT_PARAMCHECK_PTR( pk_rflg );
    pk_rflg->exinf  = NADR;
    pk_rflg->wtsk   = p->waiting();
    pk_rflg->flgptn = p->peek();
    return E_OK;
}

#endif // 0 < CYG_UITRON_NUM( FLAGS )
#endif // CYGPKG_UITRON_FLAGS

#ifdef CYGPKG_UITRON_MBOXES
#if 0 < CYG_UITRON_NUM( MBOXES )

#ifdef CYGPKG_UITRON_MBOXES_CREATE_DELETE
CYG_UITRON_NEWFUNCTION( Cyg_Mbox )

CYG_UIT_FUNC_INLINE
ER
cre_mbx ( ID mbxid, T_CMBX* pk_cmbx )
{
    ER ret = E_OK;
    CYG_UIT_PARAMCHECK_PTR( pk_cmbx );
    CYG_UITRON_CHECK_NO_OBJ_LOCK_SCHED( MBOXES, mbxid );
    if ( ((ATR)(TA_TFIFO + TA_MFIFO)) != pk_cmbx->mbxatr )
        ret = E_RSATR;
    else
        CYG_UITRON_PTRS( MBOXES )[ mbxid - 1 ] =
            new( &(CYG_UITRON_OBJS( MBOXES )[ mbxid - 1 ]) )
            Cyg_Mbox();
    Cyg_Scheduler::unlock();
    return ret;
}

CYG_UIT_FUNC_INLINE
ER
del_mbx ( ID mbxid )
{
    Cyg_Mbox *p;
    CYG_UITRON_CHECK_AND_GETP_MBOXES( mbxid, p );
    Cyg_Scheduler::lock();
    // deal with the race condition here
    if ( p != CYG_UITRON_PTRS( MBOXES )[ mbxid - 1 ] ) {
        Cyg_Scheduler::unlock();
        return E_NOEXS;
    }
    CYG_UITRON_PTRS( MBOXES )[ mbxid - 1 ] = NULL;
    p->~Cyg_Mbox();
    Cyg_Scheduler::unlock();
    return E_OK;
}
#endif // CYGPKG_UITRON_MBOXES_CREATE_DELETE

// This bit of unpleasantness is to allow uITRON programs to send a NULL
// message - if permitted by the parameter checking.
// 
// NULL is used internally to mean no message; but -1 is fine.  So we send
// a NULL as a NADR and if we see a NULL coming back, change it to a NADR.
//
// One hopes that often this will be optimized out, since the one or both
// of these being true has been detected and errored out just above.

#ifdef CYGSEM_UITRON_PARAMS_NULL_IS_GOOD_PTR
// represent a NULL as NADR internally
#define CYG_UIT_TMSG_FIXUP_IN( _p_ )    CYG_MACRO_START                 \
    if ( NULL == (_p_) )                                                \
        (_p_) = (T_MSG *)NADR;                                          \
CYG_MACRO_END

// we get a NADR back sometimes, meaning NULL
#define CYG_UIT_TMSG_FIXUP_OUT( _p_ )   CYG_MACRO_START                 \
    if ( NADR == (_p_) )                                                \
        (_p_) = (T_MSG *)NULL;                                          \
CYG_MACRO_END

#else
// NULL is checked for and makes an error
#define CYG_UIT_TMSG_FIXUP_IN( _p_ )    CYG_EMPTY_STATEMENT
#define CYG_UIT_TMSG_FIXUP_OUT( _p_ )   CYG_EMPTY_STATEMENT
#endif

// and sometimes either in status enquiries
#define CYG_UIT_TMSG_FIXUP_ALL( _p_ )   CYG_MACRO_START                 \
    if ( NULL == (_p_) )                                                \
        (_p_) = (T_MSG *)NADR;                                          \
    else if ( NADR == (_p_) )                                           \
        (_p_) = (T_MSG *)NULL;                                          \
CYG_MACRO_END

CYG_UIT_FUNC_INLINE
ER
snd_msg ( ID mbxid, T_MSG *pk_msg )
{
    Cyg_Mbox *p;
    CYG_UITRON_CHECK_AND_GETP_MBOXES( mbxid, p );
    CYG_UIT_PARAMCHECK_PTR( pk_msg );
    CYG_UIT_TMSG_FIXUP_IN( pk_msg );
    cyg_bool result = p->tryput( (void *)pk_msg );
    if ( ! result )
        return E_QOVR;
    return E_OK;
}


CYG_UIT_FUNC_INLINE
ER
rcv_msg ( T_MSG **ppk_msg, ID mbxid )
{
    Cyg_Mbox *p;
    CYG_UITRON_CHECK_AND_GETP_MBOXES( mbxid, p );
    CYG_UIT_PARAMCHECK_PTR( ppk_msg );
    CYG_UITRON_CHECK_DISPATCH_ENABLED();
    T_MSG *result = (T_MSG *)p->get();
    if ( ! result )
        CYG_UITRON_FAIL_RETURN();
    CYG_UIT_TMSG_FIXUP_OUT( result );
    *ppk_msg = result;
    return E_OK;
}

CYG_UIT_FUNC_INLINE
ER
prcv_msg ( T_MSG **ppk_msg, ID mbxid )
{
    Cyg_Mbox *p;
    CYG_UITRON_CHECK_AND_GETP_MBOXES( mbxid, p );
    CYG_UIT_PARAMCHECK_PTR( ppk_msg );
    T_MSG *result = (T_MSG *)p->tryget();
    if ( ! result )
        return E_TMOUT;
    CYG_UIT_TMSG_FIXUP_OUT( result );
    *ppk_msg = result;
    return E_OK;
}

#ifdef CYGFUN_KERNEL_THREADS_TIMER
CYG_UIT_FUNC_INLINE
ER
trcv_msg ( T_MSG **ppk_msg, ID mbxid, TMO tmout )
{
    Cyg_Mbox *p;
    CYG_UITRON_CHECK_AND_GETP_MBOXES( mbxid, p );
    CYG_UIT_PARAMCHECK_PTR( ppk_msg );
    CYG_UITRON_CHECK_DISPATCH_ENABLED_TMO( tmout );
    // do this now for the case when no sleeping actually occurs
    Cyg_Thread *self = Cyg_Thread::self();
    self->set_wake_reason( Cyg_Thread::TIMEOUT );
    T_MSG *result;
    if ( TMO_FEVR == tmout )
        result = (T_MSG *)p->get();
    else if ( TMO_POL == tmout )
        result = (T_MSG *)p->tryget();
    else
        result = (T_MSG *)p->get(
            Cyg_Clock::real_time_clock->current_value() +
            (cyg_tick_count)tmout );
    if ( ! result )
        CYG_UITRON_FAIL_RETURN_SELF( self );
    CYG_UIT_TMSG_FIXUP_OUT( result );
    *ppk_msg = result;
    return E_OK;
}
#endif // CYGFUN_KERNEL_THREADS_TIMER

CYG_UIT_FUNC_INLINE
ER
ref_mbx ( T_RMBX *pk_rmbx, ID mbxid )
{
    Cyg_Mbox *p;
    CYG_UITRON_CHECK_AND_GETP_MBOXES( mbxid, p );
    CYG_UIT_PARAMCHECK_PTR( pk_rmbx );
    pk_rmbx->exinf  = NADR;
    pk_rmbx->wtsk   = p->waiting_to_get();
    pk_rmbx->pk_msg = (T_MSG *)p->peek_item();
    CYG_UIT_TMSG_FIXUP_ALL( pk_rmbx->pk_msg );
    return E_OK;
}

#undef CYG_UIT_TMSG_FIXUP_IN
#undef CYG_UIT_TMSG_FIXUP_OUT
#undef CYG_UIT_TMSG_FIXUP_ALL
        
#endif // 0 < CYG_UITRON_NUM( MBOXES )
#endif // CYGPKG_UITRON_MBOXES

// - Extended Synchronization and Communication Functions
        
#if 0 // NOT SUPPORTED
ER      cre_mbf ( ID mbfid, T_CMBF *pk_cmbf );
ER      del_mbf ( ID mbfid );
ER      snd_mbf ( ID mbfid, VP msg, INT msgsz );
ER      psnd_mbf ( ID mbfid, VP msg, INT msgsz );
ER      tsnd_mbf ( ID mbfid, VP msg, INT msgsz, TMO tmout );
ER      rcv_mbf ( VP msg, INT *p_msgsz, ID mbfid );
ER      prcv_mbf ( VP msg, INT *p_msgsz, ID mbfid );
ER      trcv_mbf ( VP msg, INT *p_msgsz, ID mbfid, TMO tmout );
ER      ref_mbf ( T_RMBF *pk_rmbf, ID mbfid );
ER      cre_por ( ID porid, T_CPOR *pk_cpor );
ER      del_por ( ID porid );
ER      cal_por ( VP msg, INT *p_rmsgsz, ID porid, UINT calptn, INT
              cmsgsz );
ER      pcal_por ( VP msg, INT *p_rmsgsz, ID porid, UINT calptn, INT
              cmsgsz );
ER      tcal_por ( VP msg, INT *p_rmsgsz, ID porid, UINT calptn, INT
              cmsgsz, TMO tmout );
ER      acp_por ( RNO *p_rdvno, VP msg, INT *p_cmsgsz, ID porid, UINT
              acpptn );
ER      pacp_por ( RNO *p_rdvno, VP msg, INT *p_cmsgsz, ID porid, UINT
              acpptn );
ER      tacp_por ( RNO *p_rdvno, VP msg, INT *p_cmsgsz, ID porid, UINT
              acpptn, TMO tmout );
ER      fwd_por ( ID porid, UINT calptn, RNO rdvno, VP msg, INT cmsgsz
              );
ER      rpl_rdv ( RNO rdvno, VP msg, INT rmsgsz );
ER      ref_por ( T_RPOR *pk_rpor, ID porid );
#endif
        
// - Interrupt Management Functions
        
#if 0 // NOT SUPPORTED
ER      def_int ( UINT dintno, T_DINT *pk_dint );
void    ret_wup ( ID tskid );
#endif

CYG_UIT_FUNC_INLINE
ER
loc_cpu ( void )
{
    CYG_UITRON_CHECK_TASK_CONTEXT();
    Cyg_Scheduler::lock();
    // Prevent preemption by going up to prio 0
    if ( 0 == cyg_uitron_dis_dsp_old_priority ) {
#ifdef CYGIMP_THREAD_PRIORITY
        Cyg_Thread *p = Cyg_Thread::self();
        cyg_uitron_dis_dsp_old_priority = p->get_priority();
        p->set_priority( 0 );
#else
        cyg_uitron_dis_dsp_old_priority = 1;
#endif
    }
    Cyg_Interrupt::disable_interrupts();
    Cyg_Scheduler::unlock();
    return E_OK;
}

CYG_UIT_FUNC_INLINE
ER
unl_cpu ( void )
{
    CYG_UITRON_CHECK_TASK_CONTEXT();
    Cyg_Scheduler::lock();
    // Enable dispatching (if disabled) and maybe switch threads
    if ( 0 != cyg_uitron_dis_dsp_old_priority ) {
        // We had prevented preemption by going up to prio 0
#ifdef CYGIMP_THREAD_PRIORITY
        Cyg_Thread *p = Cyg_Thread::self();
        p->set_priority( cyg_uitron_dis_dsp_old_priority );
#endif
        cyg_uitron_dis_dsp_old_priority = 0;
    }
    Cyg_Interrupt::enable_interrupts();
    Cyg_Scheduler::unlock();
    CYG_UITRON_CHECK_DISPATCH_ENABLED(); // NB: afterwards!
    return E_OK;
}

#if 0 // NOT SUPPORTED
ER      dis_int ( UINT eintno );
ER      ena_int ( UINT eintno );
ER      chg_iXX ( UINT iXXXX );
ER      ref_iXX ( UINT *p_iXXXX );
#endif
        
// - Memorypool Management Functions
#ifdef CYGPKG_UITRON_MEMPOOLVAR
#if 0 < CYG_UITRON_NUM( MEMPOOLVAR )

#ifdef CYGPKG_UITRON_MEMPOOLVAR_CREATE_DELETE

CYG_UITRON_NEWFUNCTION( Cyg_Mempool_Variable )

CYG_UIT_FUNC_INLINE
ER
cre_mpl ( ID mplid, T_CMPL *pk_cmpl )
{
    ER ret = E_OK;
    CYG_UIT_PARAMCHECK_PTR( pk_cmpl );
    CYG_UITRON_CHECK_NO_OBJ_LOCK_SCHED( MEMPOOLVAR, mplid );
    Cyg_Mempool_Variable *p = &(CYG_UITRON_OBJS( MEMPOOLVAR )[ mplid - 1 ]);
    cyg_uint8 *base;
    cyg_int32 size;
    CYG_ADDRWORD scratch;
    // preserve the original memory area to use
    p->get_arena( base, size, scratch );

    if ( size < pk_cmpl->mplsz )
        ret = E_NOMEM;
    else if ( TA_TFIFO != pk_cmpl->mplatr )
        ret = E_RSATR;
    else
        CYG_UITRON_PTRS( MEMPOOLVAR )[ mplid - 1 ] =
            new( p ) Cyg_Mempool_Variable( base, size );
    Cyg_Scheduler::unlock();
    return ret;
}

CYG_UIT_FUNC_INLINE
ER
del_mpl ( ID mplid )
{
    Cyg_Mempool_Variable *p;
    CYG_UITRON_CHECK_AND_GETP_MEMPOOLVAR( mplid, p );
    Cyg_Scheduler::lock();
    // deal with the race condition here
    if ( p != CYG_UITRON_PTRS( MEMPOOLVAR )[ mplid - 1 ] ) {
        Cyg_Scheduler::unlock();
        return E_NOEXS;
    }
    CYG_UITRON_PTRS( MEMPOOLVAR )[ mplid - 1 ] = NULL;
    p->~Cyg_Mempool_Variable();
    Cyg_Scheduler::unlock();
    return E_OK;
}
#endif // CYGPKG_UITRON_MEMPOOLVAR_CREATE_DELETE

CYG_UIT_FUNC_INLINE
ER
get_blk ( VP *p_blk, ID mplid, INT blksz )
{
    Cyg_Mempool_Variable *p;
    CYG_UITRON_CHECK_AND_GETP_MEMPOOLVAR( mplid, p );
    CYG_UIT_PARAMCHECK_PTR( p_blk );
    CYG_UIT_PARAMCHECK( blksz > 0, E_PAR );
    CYG_UITRON_CHECK_DISPATCH_ENABLED();
    VP result = (VP)p->alloc(blksz);
    if ( ! result )
        CYG_UITRON_FAIL_RETURN();
    *p_blk = result;
    return E_OK;
}


CYG_UIT_FUNC_INLINE
ER
pget_blk ( VP *p_blk, ID mplid, INT blksz )
{
    Cyg_Mempool_Variable *p;
    CYG_UITRON_CHECK_AND_GETP_MEMPOOLVAR( mplid, p );
    CYG_UIT_PARAMCHECK_PTR( p_blk );
    CYG_UIT_PARAMCHECK( blksz > 0, E_PAR );
    VP result = (VP)p->try_alloc(blksz);
    if ( ! result )
        return E_TMOUT;
    *p_blk = result;
    return E_OK;
}

#ifdef CYGFUN_KERNEL_THREADS_TIMER
CYG_UIT_FUNC_INLINE
ER
tget_blk ( VP *p_blk, ID mplid, INT blksz, TMO tmout )
{
    Cyg_Mempool_Variable *p;
    CYG_UITRON_CHECK_AND_GETP_MEMPOOLVAR( mplid, p );
    CYG_UIT_PARAMCHECK_PTR( p_blk );
    CYG_UIT_PARAMCHECK( blksz > 0, E_PAR );
    CYG_UITRON_CHECK_DISPATCH_ENABLED_TMO( tmout );
    // do this now for the case when no sleeping actually occurs
    Cyg_Thread *self = Cyg_Thread::self();
    self->set_wake_reason( Cyg_Thread::TIMEOUT );
    VP result;
    if ( TMO_FEVR == tmout )
        result = p->alloc(blksz);
    else if ( TMO_POL == tmout )
        result = p->try_alloc(blksz);
    else
        result = p->alloc( blksz,
            Cyg_Clock::real_time_clock->current_value() +
            (cyg_tick_count)tmout );
    if ( ! result )
        CYG_UITRON_FAIL_RETURN_SELF( self );
    *p_blk = result;
    return E_OK;
}
#endif // CYGFUN_KERNEL_THREADS_TIMER

CYG_UIT_FUNC_INLINE
ER
rel_blk ( ID mplid, VP blk )
{
    Cyg_Mempool_Variable *p;
    CYG_UITRON_CHECK_AND_GETP_MEMPOOLVAR( mplid, p );
    CYG_UIT_PARAMCHECK_PTR( blk );
    cyg_bool result = p->free( (cyg_uint8 *)blk, 0 );
    if ( ! result )
        return E_PAR;
    return E_OK;
}

CYG_UIT_FUNC_INLINE
ER
ref_mpl ( T_RMPL *pk_rmpl, ID mplid )
{
    Cyg_Mempool_Variable *p;
    CYG_UITRON_CHECK_AND_GETP_MEMPOOLVAR( mplid, p );
    CYG_UIT_PARAMCHECK_PTR( pk_rmpl );
    pk_rmpl->exinf = NADR;
    pk_rmpl->wtsk = p->waiting();
    pk_rmpl->frsz = p->get_freemem();
    
    cyg_uint8 *base;
    cyg_int32 size;
    CYG_ADDRWORD maxfree;
    p->get_arena(base, size, maxfree);
    pk_rmpl->maxsz = maxfree;

    return E_OK;
}

#endif // 0 < CYG_UITRON_NUM( MEMPOOLVAR )
#endif // CYGPKG_UITRON_MEMPOOLVAR

#ifdef CYGPKG_UITRON_MEMPOOLFIXED
#if 0 < CYG_UITRON_NUM( MEMPOOLFIXED )

#ifdef CYGPKG_UITRON_MEMPOOLFIXED_CREATE_DELETE

CYG_UITRON_NEWFUNCTION( Cyg_Mempool_Fixed )

CYG_UIT_FUNC_INLINE
ER
cre_mpf ( ID mpfid, T_CMPF *pk_cmpf )
{
    ER ret = E_OK;
    CYG_UIT_PARAMCHECK_PTR( pk_cmpf );
    CYG_UITRON_CHECK_NO_OBJ_LOCK_SCHED( MEMPOOLFIXED, mpfid );
    Cyg_Mempool_Fixed *p = &(CYG_UITRON_OBJS( MEMPOOLFIXED )[ mpfid - 1 ]);
    cyg_uint8 *base;
    cyg_int32 size;
    CYG_ADDRWORD scratch;
    // preserve the original memory area to use
    p->get_arena( base, size, scratch );

    if ( size < (pk_cmpf->blfsz * (pk_cmpf->mpfcnt + 1)) )
        ret = E_NOMEM;
    else if ( TA_TFIFO != pk_cmpf->mpfatr )
        ret = E_RSATR;
    else
        CYG_UITRON_PTRS( MEMPOOLFIXED )[ mpfid - 1 ] =
            new( p )
            Cyg_Mempool_Fixed( base, size,
                               (CYG_ADDRWORD)pk_cmpf->blfsz );
    Cyg_Scheduler::unlock();
    return ret;
}

CYG_UIT_FUNC_INLINE
ER
del_mpf ( ID mpfid )
{
    Cyg_Mempool_Fixed *p;
    CYG_UITRON_CHECK_AND_GETP_MEMPOOLFIXED( mpfid, p );
    Cyg_Scheduler::lock();
    // deal with the race condition here
    if ( p != CYG_UITRON_PTRS( MEMPOOLFIXED )[ mpfid - 1 ] ) {
        Cyg_Scheduler::unlock();
        return E_NOEXS;
    }
    CYG_UITRON_PTRS( MEMPOOLFIXED )[ mpfid - 1 ] = NULL;
    p->~Cyg_Mempool_Fixed();
    Cyg_Scheduler::unlock();
    return E_OK;
}
#endif // CYGPKG_UITRON_MEMPOOLFIXED_CREATE_DELETE

CYG_UIT_FUNC_INLINE
ER
get_blf ( VP *p_blf, ID mpfid )
{
    Cyg_Mempool_Fixed *p;
    CYG_UITRON_CHECK_AND_GETP_MEMPOOLFIXED( mpfid, p );
    CYG_UIT_PARAMCHECK_PTR( p_blf );
    CYG_UITRON_CHECK_DISPATCH_ENABLED();
    VP result = (VP)p->alloc();
    if ( ! result )
        CYG_UITRON_FAIL_RETURN();
    *p_blf = result;
    return E_OK;
}

CYG_UIT_FUNC_INLINE
ER
pget_blf ( VP *p_blf, ID mpfid )
{
    Cyg_Mempool_Fixed *p;
    CYG_UITRON_CHECK_AND_GETP_MEMPOOLFIXED( mpfid, p );
    CYG_UIT_PARAMCHECK_PTR( p_blf );
    VP result = (VP)p->try_alloc();
    if ( ! result )
        return E_TMOUT;
    *p_blf = result;
    return E_OK;
}

#ifdef CYGFUN_KERNEL_THREADS_TIMER
CYG_UIT_FUNC_INLINE
ER
tget_blf ( VP *p_blf, ID mpfid, TMO tmout )
{
    Cyg_Mempool_Fixed *p;
    CYG_UITRON_CHECK_AND_GETP_MEMPOOLFIXED( mpfid, p );
    CYG_UIT_PARAMCHECK_PTR( p_blf );
    CYG_UITRON_CHECK_DISPATCH_ENABLED_TMO( tmout );
    // do this now for the case when no sleeping actually occurs
    Cyg_Thread *self = Cyg_Thread::self();
    self->set_wake_reason( Cyg_Thread::TIMEOUT );
    VP result;
    if ( TMO_FEVR == tmout )
        result = p->alloc();
    else if ( TMO_POL == tmout )
        result = p->try_alloc();
    else
        result = p->alloc(
            Cyg_Clock::real_time_clock->current_value() +
            (cyg_tick_count)tmout );
    if ( ! result )
        CYG_UITRON_FAIL_RETURN_SELF( self );
    *p_blf = result;
    return E_OK;
}
#endif // CYGFUN_KERNEL_THREADS_TIMER

CYG_UIT_FUNC_INLINE
ER
rel_blf ( ID mpfid, VP blf )
{
    Cyg_Mempool_Fixed *p;
    CYG_UITRON_CHECK_AND_GETP_MEMPOOLFIXED( mpfid, p );
    CYG_UIT_PARAMCHECK_PTR( blf );
    cyg_bool result = p->free( (cyg_uint8 *)blf );
    if ( ! result )
        return E_PAR;
    return E_OK;
}

CYG_UIT_FUNC_INLINE
ER
ref_mpf ( T_RMPF *pk_rmpf, ID mpfid )
{
    Cyg_Mempool_Fixed *p;
    CYG_UITRON_CHECK_AND_GETP_MEMPOOLFIXED( mpfid, p );
    CYG_UIT_PARAMCHECK_PTR( pk_rmpf );
    pk_rmpf->exinf = NADR;
    pk_rmpf->wtsk = p->waiting();

    cyg_int32 blocksize = p->get_blocksize();
    pk_rmpf->frbcnt = p->get_freemem() / blocksize;
    // these two are "implementation dependent" ie. eCos only
    pk_rmpf->numbcnt = p->get_totalmem() / blocksize;
    pk_rmpf->bsize = blocksize;

    return E_OK;
}
        
#endif // 0 < CYG_UITRON_NUM( MEMPOOLFIXED )
#endif // CYGPKG_UITRON_MEMPOOLFIXED

// - Time Management Functions
        
#ifdef CYGVAR_KERNEL_COUNTERS_CLOCK
CYG_UIT_FUNC_INLINE
ER
set_tim ( SYSTIME *pk_tim )
{
    CYG_UIT_PARAMCHECK_PTR( pk_tim );
    Cyg_Clock::real_time_clock->set_value( *pk_tim );
    return E_OK;
}

CYG_UIT_FUNC_INLINE
ER
get_tim ( SYSTIME *pk_tim )
{
    CYG_UIT_PARAMCHECK_PTR( pk_tim );
    *pk_tim = Cyg_Clock::real_time_clock->current_value();
    return E_OK;
}
#endif // CYGVAR_KERNEL_COUNTERS_CLOCK


#ifdef CYGFUN_KERNEL_THREADS_TIMER
CYG_UIT_FUNC_INLINE
ER
dly_tsk ( DLYTIME dlytim )
{
    CYG_UIT_PARAMCHECK( 0 <= dlytim, E_PAR );
    CYG_UITRON_CHECK_DISPATCH_ENABLED();
    if ( 0 >= dlytim )
        return E_OK;
    Cyg_Thread *self = Cyg_Thread::self();
    CYG_UITRON_CHECK_TASK_CONTEXT_SELF( self );
    self->delay( dlytim );
    if ( Cyg_Thread::DONE != self->get_wake_reason() )
        CYG_UITRON_FAIL_RETURN_SELF( self );
    return E_OK;
}
#endif // CYGFUN_KERNEL_THREADS_TIMER

#ifdef CYGVAR_KERNEL_COUNTERS_CLOCK
#ifdef CYGPKG_UITRON_CYCLICS
#if 0 < CYG_UITRON_NUM( CYCLICS )
CYG_UIT_FUNC_INLINE
ER
def_cyc ( HNO cycno, T_DCYC *pk_dcyc )
{
    // pk_dcyc->cycatr is ignored
    // The only relevant attribute is TA_HLNG/TA_ASM.
    // This can be ignored as assembler routines are defined to be
    // more conservative with registers than the procedure call standard.

    Cyg_Timer *p;
    CYG_UITRON_CHECK_AND_GETHDLR( CYCLICS, cycno, p );
#ifndef CYGSEM_UITRON_PARAMS_NULL_IS_GOOD_PTR
    CYG_UIT_PARAMCHECK( NULL != pk_dcyc, E_PAR );
#endif
    if( NADR == pk_dcyc ) {
        p->~Cyg_Timer();
        return E_OK;
    }
    CYG_UIT_PARAMCHECK( 0 == (pk_dcyc->cycact & ~TCY_ON), E_PAR );
    CYG_UIT_PARAMCHECK( 0 < pk_dcyc->cyctim, E_PAR );
    p->initialize(
        Cyg_Clock::real_time_clock,
        (cyg_alarm_fn *)pk_dcyc->cychdr,
        (CYG_ADDRWORD)pk_dcyc->exinf,
        Cyg_Clock::real_time_clock->current_value() + pk_dcyc->cyctim,
        pk_dcyc->cyctim,
        pk_dcyc->cycact);
    return E_OK;
}

CYG_UIT_FUNC_INLINE
ER
act_cyc ( HNO cycno, UINT cycact )
{
    Cyg_Timer *p;
    CYG_UITRON_CHECK_AND_GETHDLR( CYCLICS, cycno, p );
    CYG_UIT_PARAMCHECK( p->is_initialized(), E_NOEXS);
    CYG_UIT_PARAMCHECK( 0 == (cycact & ~(TCY_ON | TCY_INI)), E_PAR );
    p->activate(cycact);
    return E_OK;
}


CYG_UIT_FUNC_INLINE
ER
ref_cyc ( T_RCYC *pk_rcyc, HNO cycno )
{
    Cyg_Timer *p;
    cyg_tick_count t;
    CYG_UITRON_CHECK_AND_GETHDLR( CYCLICS, cycno, p );
    CYG_UIT_PARAMCHECK( p->is_initialized(), E_NOEXS);
    CYG_UIT_PARAMCHECK_PTR( pk_rcyc );

    pk_rcyc->exinf = (VP)p->get_data();
    Cyg_Scheduler::lock();
    t = p->get_trigger() - Cyg_Clock::real_time_clock->current_value();
    Cyg_Scheduler::unlock();
    pk_rcyc->lfttim = t;
    pk_rcyc->cycact = (UINT)p->is_enabled();
    return E_OK;
}
#endif // 0 < CYG_UITRON_NUM( CYCLICS )
#endif // CYGPKG_UITRON_CYCLICS

#ifdef CYGPKG_UITRON_ALARMS
#if 0 < CYG_UITRON_NUM( ALARMS )
CYG_UIT_FUNC_INLINE
ER
def_alm ( HNO almno, T_DALM *pk_dalm )
{
    Cyg_Timer *p;
    cyg_tick_count t, now;
    CYG_UITRON_CHECK_AND_GETHDLR( ALARMS, almno, p );
#ifndef CYGSEM_UITRON_PARAMS_NULL_IS_GOOD_PTR
    CYG_UIT_PARAMCHECK( NULL != pk_dalm, E_PAR );
#endif
    if( NADR == pk_dalm ) {
        p->~Cyg_Timer();
        return E_OK;
    }

    CYG_UIT_PARAMCHECK( 0 == (pk_dalm->tmmode & ~TTM_REL), E_PAR );

    // make the time arithmetic safe without locking
    now = Cyg_Clock::real_time_clock->current_value();
    t = pk_dalm->almtim;
    if( TTM_REL & pk_dalm->tmmode )
        t += now;

    CYG_UIT_PARAMCHECK( now < t, E_PAR );

    p->initialize(Cyg_Clock::real_time_clock,
                  (cyg_alarm_fn *)pk_dalm->almhdr,
                  (CYG_ADDRWORD)pk_dalm->exinf,
                  t, 0, Cyg_Timer::ENABLE);

    return E_OK;
}

CYG_UIT_FUNC_INLINE
ER
ref_alm ( T_RALM *pk_ralm, HNO almno )
{
    Cyg_Timer *p;
    cyg_tick_count t;

    CYG_UITRON_CHECK_AND_GETHDLR( ALARMS, almno, p );
    CYG_UIT_PARAMCHECK_PTR( pk_ralm );
    CYG_UIT_PARAMCHECK( p->is_initialized(), E_NOEXS);

    Cyg_Scheduler::lock();
    t = p->get_trigger() - Cyg_Clock::real_time_clock->current_value();
    Cyg_Scheduler::unlock();
    pk_ralm->exinf  = (VP)p->get_data();
    pk_ralm->lfttim = t;
    return E_OK;
}
#endif // 0 < CYG_UITRON_NUM( ALARMS )
#endif // CYGPKG_UITRON_ALARMS

#endif // CYGVAR_KERNEL_COUNTERS_CLOCK
        
// - System Management Functions
        
CYG_UIT_FUNC_INLINE
ER
get_ver ( T_VER *pk_ver )
{
    CYG_UIT_PARAMCHECK_PTR( pk_ver );

    pk_ver->maker       = CYGNUM_UITRON_VER_MAKER;
    pk_ver->id          = CYGNUM_UITRON_VER_ID;
    pk_ver->spver       = CYGNUM_UITRON_VER_SPVER;
    pk_ver->prver       = CYGNUM_UITRON_VER_PRVER;
    pk_ver->prno[0]     = CYGNUM_UITRON_VER_PRNO_0;
    pk_ver->prno[1]     = CYGNUM_UITRON_VER_PRNO_1;
    pk_ver->prno[2]     = CYGNUM_UITRON_VER_PRNO_2;
    pk_ver->prno[3]     = CYGNUM_UITRON_VER_PRNO_3;
    pk_ver->cpu         = CYGNUM_UITRON_VER_CPU;
    pk_ver->var         = CYGNUM_UITRON_VER_VAR;
   
    return E_OK;
}

CYG_UIT_FUNC_INLINE
ER
ref_sys ( T_RSYS *pk_rsys )
{
    CYG_UIT_PARAMCHECK_PTR( pk_rsys );
    if ( ! Cyg_Interrupt::interrupts_enabled() )
        // CPU is locked
        pk_rsys->sysstat = TSS_LOC;
    else
        pk_rsys->sysstat =
            (0 == cyg_uitron_dis_dsp_old_priority) ? TSS_TSK : TSS_DDSP;
    return E_OK;
}

CYG_UIT_FUNC_INLINE
ER
ref_cfg ( T_RCFG *pk_rcfg )
{
    CYG_UIT_PARAMCHECK_PTR( pk_rcfg );
    // no details here yet
    return E_OK;
}

#if 0 // NOT SUPPORTED
ER      def_svc ( FN s_fncd, T_DSVC *pk_dsvc );
ER      def_exc ( UINT exckind, T_DEXC *pk_dexc );
#endif
        
// - Network Support Functions
        
#if 0 // NOT SUPPORTED
ER      nrea_dat ( INT *p_reasz, VP dstadr, NODE srcnode, VP srcadr,
               INT datsz );
ER      nwri_dat ( INT *p_wrisz, NODE dstnode, VP dstadr, VP srcadr,
               INT datsz );
ER      nget_nod ( NODE *p_node );
ER      nget_ver ( T_VER *pk_ver, NODE node );
#endif

// ========================================================================

#endif // CYGPKG_UITRON

#endif // CYGPRI_UITRON_FUNCS_HERE_AND_NOW

#endif // CYGONCE_COMPAT_UITRON_UIT_FUNC_INL
//EOF uit_func.inl
