Logo Search packages:      
Sourcecode: u++ version File versions

uAlarm.cc

//                              -*- Mode: C++ -*- 
// 
// uC++ Version 5.0.1, Copyright (C) Philipp E. Lim and Ashif S. Harji 1995, 1997
// 
// uAlarm.cc -- 
// 
// Author           : Philipp E. Lim
// Created On       : Thu Jan  4 17:34:00 1996
// Last Modified By : Peter A. Buhr
// Last Modified On : Wed Aug 25 23:57:11 2004
// Update Count     : 182
//
// This  library is free  software; you  can redistribute  it and/or  modify it
// under the terms of the GNU Lesser General Public License as published by the
// Free Software  Foundation; either  version 2.1 of  the License, or  (at your
// option) any later version.
// 
// This library is distributed in the  hope that it will be useful, but WITHOUT
// ANY  WARRANTY;  without even  the  implied  warranty  of MERCHANTABILITY  or
// FITNESS FOR A PARTICULAR PURPOSE.  See the GNU Lesser General Public License
// for more details.
// 
// You should  have received a  copy of the  GNU Lesser General  Public License
// along  with this library.
// 


#define __U_KERNEL__
#include <uC++.h>
#include <uProfiler.h>
//#include <uDebug.h>


//######################### uEventNode #########################


uEventNode::uEventNode( uBaseTask &t, uSignalHandler &sig, uTime tT, uDuration tD ) {
    timerT = tT;
    timerD = tD;
    SigHandler = &sig;
    uWho = &t;
    uExecuteLocked = false;
} // uEventNode::uEventNode

uEventNode::uEventNode( uSignalHandler &sig ) {
    timerT = 0;
    timerD = 0;
    SigHandler = &sig;
    uWho = NULL;
    uExecuteLocked = false;
} // uEventNode::uEventNode

uEventNode::uEventNode() {
    timerT = 0;
    timerD = 0;
    SigHandler = NULL;
    uWho = NULL;
    uExecuteLocked = false;
} // uEventNode::uEventNode


//######################### uEventList #########################


void *uEventList::operator new( size_t, void *storage ) {
    return storage;
} // uEventList::operator new

void *uEventList::operator new( size_t size ) {
    return ::operator new( size );
} // uEventList::operator new


void uEventList::uAddEvent( uEventNode &newAlarm, uProcessor &processor, bool block ) {
#ifdef __U_DEBUG_H__
    uDebugPrt( "(uEventList &)0x%p.uAddEvent, newAlarm:0x%p, processor:0x%p\n", this, &newAlarm, &processor );
#endif // __U_DEBUG_H__
    uAcquireEventLock();

    uSeqGen<uEventNode> gen(uL);
    uEventNode *node, *prev = NULL;
    int i;

    for ( i = 0; gen >> node && node->timerT <= newAlarm.timerT; prev = node, i += 1 );
    if ( prev && (uSignalHandler *)(uThisProcessor().uContextSwitchHandler) == prev->SigHandler && prev->timerT == newAlarm.timerT) {
        i -= 1;
      node = prev;
    } // if

    uL.uInsertBef( &newAlarm, node );                 // insert in list

    if ( i == 0 ) {                             // insert at the front ?
      if ( this == uThisProcessor().uEvents ) { // same processor as event list ?
          uActiveProcessorKernel->uSetTimer( newAlarm.timerT ); // reset alarm
      } else {
          uThisCluster().uWakeProcessor( processor.uGetPid() );
      } // if
    } // if

    if ( block ) {
      uSCHEDULE( &uEventLock );
    } else {
      uReleaseEventLock();
    } // if
} // uEventList::uAddEvent


// No yield after a uRemoveEvent. This is handled by whatever code calls
// uRemoveEvent.

void uEventList::uRemoveEvent( uEventNode &oldNode, uProcessor &processor ) {
#ifdef __U_DEBUG_H__
    uDebugPrt( "(uEventList &)0x%p.uRemoveEvent, newAlarm:0x%p, processor:0x%p\n", this, &oldNode, &processor );
#endif // __U_DEBUG_H__
    uAcquireEventLock();

    uEventNode *headNode;

    if ( ! oldNode.uListed() ) {                // node already removed ?
      uReleaseEventLock();
      return;
    } // if
    headNode = uL.uHead();
    uL.uRemove( &oldNode );

    if ( headNode == &oldNode ) {               // removing at head ?  reset alarm
      if ( this == uThisProcessor().uEvents ) { // same processor as event list ?
          headNode = uL.uHead();
          if ( ! headNode ) {                   // list empty ?
            uActiveProcessorKernel->uSetTimer( uDuration( 0 ) ); // cancel alarm
          } else {
            uActiveProcessorKernel->uSetTimer( headNode->timerT ); // reset alarm
          } // if
      } else {
          uThisCluster().uWakeProcessor( processor.uGetPid() ); // send SIGALRM to reset alarm on other processor
      } // if
    } // if
    uReleaseEventLock();
} // uEventList::uRemoveEvent


void uEventList::uPauseEvents() {
    uAcquireEventLock();
    
    uActiveProcessorKernel->uSetTimer( uDuration ( 0 ) );
} // uEventList::uAddEvent


void uEventList::uRestartEvents() {
    uEventNode *headNode = uL.uHead();
    if ( headNode != NULL ) {
      uActiveProcessorKernel->uSetTimer( headNode->timerT );
    } // if 
   
    uReleaseEventLock();
} // uEventList::uAddEvent


uEventNode *uEventList::uNextEvent( ) {
#ifdef __U_DEBUG_H__
    uDebugPrt( "(uEventList &)0x%p.uNextEvent\n", this );
#endif // __U_DEBUG_H__
    uAcquireEventLock();

    uEventNode *noder;
    uSeqGen<uEventNode> gen(uL);

    // loop executes at most 2 iterations
    for ( ; gen >> noder && noder->SigHandler == (uSignalHandler *)(uThisProcessor().uContextSwitchHandler); );
    uReleaseEventLock();

    return noder;
} // uEventList::uNextEvent


uTime uEventList::uNextAlarm( ) {
#ifdef __U_DEBUG_H__
    uDebugPrt( "(uEventList &)0x%p.uNextAlarm\n", this );
#endif // __U_DEBUG_H__
    uEventNode *noder = uNextEvent();

    if ( noder ) {
      return noder->timerT;
    } else {
      return uTime( 0L );
    } // if
} // uEventList::uNextAlarm


void uEventList::uAcquireEventLock() {
    uEventLock.acquire();
} // uEventList::uAcquireEventLock

void uEventList::uReleaseEventLock() {
    uEventLock.release();
} // uEventList::uReleaseEventLock 

void uEventList::uAcquireEventLockNoRF() {
    uEventLock.uAcquireNoRF();
} // uEventList::uAcquireEventLockNoRF

void uEventList::uReleaseEventLockNoRF() {
    uEventLock.uReleaseNoRF();
} // uEventList::uReleaseEventLockNoRF


bool uEventList::uUserEventPresent() {
    uAcquireEventLock();

    uEventNode *noder;
    uSeqGen<uEventNode> gen(uL);

    // loop executes at most 3 iterations
    for ( ; gen >> noder && ( noder->SigHandler == (uSignalHandler *)(uThisProcessor().uContextSwitchHandler) // ignore context switch event
                       || noder->uWho == (uBaseTask *)uKernelModule::uTaskSystem );             // ignore system task
       );
    uReleaseEventLock();

    return noder != NULL;
} // uEventList::uUserEventPresent


//######################### uEventListPop #########################


uEventListPop::uEventListPop( uEventList &e, bool inKernel ) : uEL( &e ), uInKernel( inKernel ) {
    THREAD_SETMEM( uInKernelRF, 1 );                  // detect if subsequent interrupts occur
    curTime = uActiveProcessorKernel->uKernelClock.uGetTime();
    uCxtSwHandler = NULL;
} // uEventListPop::uEventListPop

uEventListPop::~uEventListPop() {
#ifdef __U_DEBUG_H__
    uDebugPrt( "(uEventListPop &)0x%p.~uEventListPop\n", this );
#endif // __U_DEBUG_H__
    uEL->uAcquireEventLockNoRF();
    // only reset the roll forward flag if no other interrupts occurred during
    // roll forward
    if ( THREAD_GETMEM( uInKernelRF ) == 1 ) {
      THREAD_SETMEM( uInKernelRF, 0 );
    } // if

    if ( ! uEL->uL.uEmpty() ) {
      uActiveProcessorKernel->uSetTimer( uEL->uL.uHead()->timerT );
    } // if
    uEL->uReleaseEventLock();

    if ( ! uInKernel ) {                        // not in kernel ?
      if ( uCxtSwHandler ) {                    // context-switch event ?
          uCxtSwHandler->uHandler();                  // should do a yield
      } else {
          // Force a reschedule as a higher priority task may have become
          // ready and is now at the front of the ready queue. Note,
          // rescheduling can occur even if a lower priority task unblocks.
          // As a side effect, if the current task has the same priority as
          // the task on the front of the ready queue, the current task is
          // preempted even if it has only just started execution.

          uThisTask().uYieldInvoluntary();
      } // if
    } else {
      // roll-forward is only called from the kernel, after waking up from
      // sleeping, or an alarm occurred while in the process of going to
      // sleep.  Therefore, yielding is unnecessary, if going to sleep (or
      // have slept).  There were no tasks to execute or context switch from
      // in the first place.

      // A preemption event may be ignored because a reschedule is just about
      // to occur, anyway, when the kernel reschedules the next task.

      uAssert( THREAD_GETMEM( uDisableInt ) && THREAD_GETMEM( uDisableIntCnt ) > 0 );
    } // if
} // uEventListPop::~uEventListPop

void uEventListPop::uOver( uEventList &e, bool inKernel ) {
    uEL = &e;
    uInKernel = inKernel;
    curTime = uActiveProcessorKernel->uKernelClock.uGetTime();
    uCxtSwHandler = NULL;
} // uEventListPop::uOver

bool uEventListPop::operator>>( uEventNode *&node ) {
#ifdef __U_DEBUG_H__
    uDebugPrt( "(uEventListPop &)0x%p.>>, node:0x%p\n", this, node );
#endif // __U_DEBUG_H__
    uEL->uAcquireEventLockNoRF();

    node = uEL->uL.uHead();                     // get event at the start of the list with the shortest time delay

  if ( ! node ) {                         // no events ?
      uEL->uReleaseEventLockNoRF();
      return false;
    } // if

  if ( node->timerT > curTime ) {               // event time delay greater than the start time for the iteration
      uEL->uReleaseEventLockNoRF();
      return false;
    } // if

    uEL->uL.uRemove( node );

    // Now see if the popped event is periodic.  If it is, insert another event
    // for next period.

    if ( node->timerD != 0 ) {
      node->timerT = curTime + node->timerD;          // Reset timerT value in clock object
      uSeqGen<uEventNode> i( uEL->uL );
      uEventNode *prev;
      uEventNode *noder;

      // May have to order identical timed elements by priority (to keep up
      // the real-time spirit)

      for ( prev = NULL; i >> noder && noder->timerT <= node->timerT; prev = noder );
      if ( prev && (uSignalHandler *)(uThisProcessor().uContextSwitchHandler) == prev->SigHandler && prev->timerT == node->timerT) {
          noder = prev;
      } // if

      uEL->uL.uInsertBef( node, noder );        // insert into list
    } // if

    if ( node->SigHandler == (uSignalHandler *)(uThisProcessor().uContextSwitchHandler) ) {
      uCxtSwHandler = node->SigHandler;         // remember the context switch event
      uEL->uReleaseEventLockNoRF();
    } else {                                            // not a ContextSwitch event
      if ( node->uExecuteLocked ) {             // should handler be called with lock
          node->SigHandler->uHandler();         // invoke the handler code for the event
          uEL->uReleaseEventLockNoRF();
      } else {
          uEL->uReleaseEventLockNoRF();
          node->SigHandler->uHandler();         // invoke the handler code for the event
      } // if
    } // if

    return true;
} // uEventListPop::operator>>


// Local Variables: //
// compile-command: "gmake install" //
// End: //

Generated by  Doxygen 1.6.0   Back to index