Ejemplo n.º 1
0
void _Watchdog_Adjust(
  Chain_Control               *header,
  Watchdog_Adjust_directions   direction,
  Watchdog_Interval            units
)
{
  ISR_Level level;

  _ISR_Disable( level );

  /*
   * NOTE: It is safe NOT to make 'header' a pointer
   *       to volatile data (contrast this with watchdoginsert.c)
   *       because we call _Watchdog_Tickle() below and
   *       hence the compiler must not assume *header to remain
   *       unmodified across that call.
   *
   *       Till Straumann, 7/2003
   */
  if ( !_Chain_Is_empty( header ) ) {
    switch ( direction ) {
      case WATCHDOG_BACKWARD:
        _Watchdog_First( header )->delta_interval += units;
        break;
      case WATCHDOG_FORWARD:
        while ( units ) {
          if ( units < _Watchdog_First( header )->delta_interval ) {
            _Watchdog_First( header )->delta_interval -= units;
            break;
          } else {
            units -= _Watchdog_First( header )->delta_interval;
            _Watchdog_First( header )->delta_interval = 1;

            _ISR_Enable( level );

            _Watchdog_Tickle( header );

            _ISR_Disable( level );

            if ( _Chain_Is_empty( header ) )
              break;
          }
        }
        break;
    }
  }

  _ISR_Enable( level );

}
Ejemplo n.º 2
0
static rtems_timer_service_routine test_release_from_isr(
  rtems_id  timer,
  void     *arg
)
{
  Watchdog_Header *header = &_Watchdog_Ticks_header;

  if ( !_Watchdog_Is_empty( header ) ) {
    Watchdog_Control *watchdog = _Watchdog_First( header );

    if (
      watchdog->delta_interval == 0
        && watchdog->routine == _Rate_monotonic_Timeout
    ) {
      Watchdog_States state = _Watchdog_Remove_ticks( watchdog );

      rtems_test_assert( state == WATCHDOG_ACTIVE );
      (*watchdog->routine)( watchdog->id, watchdog->user_data );

      if ( getState() == RATE_MONOTONIC_EXPIRED_WHILE_BLOCKING ) {
        case_hit = true;
      }
    }
  }
}
Ejemplo n.º 3
0
static rtems_timer_service_routine test_release_from_isr(
    rtems_id  timer,
    void     *arg
)
{
    Watchdog_Header *header = &_Watchdog_Ticks_header;

    if ( !_Watchdog_Is_empty( header ) ) {
        Watchdog_Control *watchdog = _Watchdog_First( header );

        if (
            watchdog->delta_interval == 0
            && watchdog->routine == _Thread_queue_Timeout
        ) {
            Watchdog_States state = _Watchdog_Remove( watchdog );

            rtems_test_assert( state == WATCHDOG_ACTIVE );
            (*watchdog->routine)( watchdog->id, watchdog->user_data );

            if ( getState() == THREAD_BLOCKING_OPERATION_TIMEOUT ) {
                case_hit = true;
            }
        }
    }
}
Ejemplo n.º 4
0
static void _Timer_server_Reset_tod_system_watchdog(
  Timer_server_Control *ts
)
{
  ISR_Level level;

  _Timer_server_Stop_tod_system_watchdog( ts );

  _ISR_Disable( level );
  if ( !_Chain_Is_empty( &ts->TOD_watchdogs.Chain ) ) {
    Watchdog_Interval delta_interval =
      _Watchdog_First( &ts->TOD_watchdogs.Chain )->delta_interval;
    _ISR_Enable( level );

    /*
     *  The unit is SECONDS here.
     */
    _Watchdog_Insert_seconds(
      &ts->TOD_watchdogs.System_watchdog,
      delta_interval
    );
  } else {
    _ISR_Enable( level );
  }
}
Ejemplo n.º 5
0
static rtems_timer_service_routine test_release_from_isr(
  rtems_id  timer,
  void     *arg
)
{
  Watchdog_Header *header = &_Watchdog_Ticks_header;

  if ( !_Watchdog_Is_empty( header ) ) {
    Watchdog_Control *watchdog = _Watchdog_First( header );

    if (
      watchdog->delta_interval == 0
        && watchdog->routine == _Thread_Timeout
    ) {
      Watchdog_States state = _Watchdog_Remove_ticks( watchdog );

      rtems_test_assert( state == WATCHDOG_ACTIVE );
      (*watchdog->routine)( watchdog->id, watchdog->user_data );

      if ( is_interrupt_timeout() ) {
        case_hit = true;
      }
    }
  }
}
void _Watchdog_Tickle(
  Chain_Control *header
)
{
  ISR_Level level;
  Watchdog_Control *the_watchdog;
  Watchdog_States  watchdog_state;

  /*
   * See the comment in watchdoginsert.c and watchdogadjust.c
   * about why it's safe not to declare header a pointer to
   * volatile data - till, 2003/7
   */

  _ISR_Disable( level );

  if ( _Chain_Is_empty( header ) )
    goto leave;

  the_watchdog = _Watchdog_First( header );
  
  /*
   * For some reason, on rare occasions the_watchdog->delta_interval
   * of the head of the watchdog chain is 0.  Before this test was
   * added, on these occasions an event (which usually was supposed
   * to have a timeout of 1 tick would have a delta_interval of 0, which
   * would be decremented to 0xFFFFFFFF by the unprotected 
   * "the_watchdog->delta_interval--;" operation.
   * This would mean the event would not timeout, and also the chain would
   * be blocked, because a timeout with a very high number would be at the
   * head, rather than at the end.
   * The test "if (the_watchdog->delta_interval != 0)"
   * here prevents this from occuring. 
   * 
   * We were not able to categorically identify the situation that causes 
   * this, but proved it to be true empirically.  So this check causes 
   * correct behaviour in this circumstance.
   * 
   * The belief is that a race condition exists whereby an event at the head
   * of the chain is removed (by a pending ISR or higher priority task)
   * during the _ISR_Flash( level ); in _Watchdog_Insert, but the watchdog 
   * to be inserted has already had its delta_interval adjusted to 0, and 
   * so is added to the head of the chain with a delta_interval of 0.  
   * 
   * Steven Johnson - 12/2005 (gcc-3.2.3 -O3 on powerpc)
   */
  if (the_watchdog->delta_interval != 0) {
    the_watchdog->delta_interval--;
    if ( the_watchdog->delta_interval != 0 )
      goto leave;
  }      

  do {
     watchdog_state = _Watchdog_Remove( the_watchdog );

     _ISR_Enable( level );

     switch( watchdog_state ) {
       case WATCHDOG_ACTIVE:
         (*the_watchdog->routine)(
           the_watchdog->id,
           the_watchdog->user_data
         );
         break;

       case WATCHDOG_INACTIVE:
         /*
          *  This state indicates that the watchdog is not on any chain.
          *  Thus, it is NOT on a chain being tickled.  This case should
          *  never occur.
          */
         break;

       case WATCHDOG_BEING_INSERTED:
         /*
          *  This state indicates that the watchdog is in the process of
          *  BEING inserted on the chain.  Thus, it can NOT be on a chain
          *  being tickled.  This case should never occur.
          */
         break;

       case WATCHDOG_REMOVE_IT:
         break;
     }

	 _ISR_Disable( level );

     the_watchdog = _Watchdog_First( header );
   } while ( !_Chain_Is_empty( header ) &&
             (the_watchdog->delta_interval == 0) );

leave:
   _ISR_Enable(level);
}
Ejemplo n.º 7
0
void _Watchdog_Tickle(
  Watchdog_Header *header
)
{
  ISR_lock_Context lock_context;

  _Watchdog_Acquire( header, &lock_context );

  if ( !_Watchdog_Is_empty( header ) ) {
    Watchdog_Control  *first;
    Watchdog_Interval  delta;

    first = _Watchdog_First( header );
    delta = first->delta_interval;

    /*
     * Although it is forbidden to insert watchdogs with a delta interval of
     * zero it is possible to observe watchdogs with a delta interval of zero
     * at this point.  For example lets have a watchdog chain of one watchdog
     * with a delta interval of one and insert a new one with an initial value
     * of one.  At the start of the insert procedure it will advance one step
     * and reduce its delta interval by one yielding zero.  Now a tick happens.
     * This will remove the watchdog on the chain and update the insert
     * iterator.  Now the insert operation continues and will insert the new
     * watchdog with a delta interval of zero.
     */
    if ( delta > 0 ) {
      --delta;
      first->delta_interval = delta;
    }

    while ( delta == 0 ) {
      bool                            run;
      Watchdog_Service_routine_entry  routine;
      Objects_Id                      id;
      void                           *user_data;

      run = ( first->state == WATCHDOG_ACTIVE );

      _Watchdog_Remove_it( header, first );

      routine = first->routine;
      id = first->id;
      user_data = first->user_data;

      _Watchdog_Release( header, &lock_context );

      if ( run ) {
        (*routine)( id, user_data );
      }

      _Watchdog_Acquire( header, &lock_context );

      if ( _Watchdog_Is_empty( header ) ) {
        break;
      }

      first = _Watchdog_First( header );
      delta = first->delta_interval;
    }
  }

  _Watchdog_Release( header, &lock_context );
}
Ejemplo n.º 8
0
static void _Timer_server_Insert_timer_and_make_snapshot(
  Timer_server_Control *ts,
  Timer_Control *timer
)
{
  Watchdog_Control *first_watchdog;
  Watchdog_Interval delta_interval;
  Watchdog_Interval last_snapshot;
  Watchdog_Interval snapshot;
  Watchdog_Interval delta;
  ISR_Level level;

  /*
   *  We have to update the time snapshots here, because otherwise we may have
   *  problems with the integer range of the delta values.  The time delta DT
   *  from the last snapshot to now may be arbitrarily long.  The last snapshot
   *  is the reference point for the delta chain.  Thus if we do not update the
   *  reference point we have to add DT to the initial delta of the watchdog
   *  being inserted.  This could result in an integer overflow.
   */

  _Thread_Disable_dispatch();

  if ( timer->the_class == TIMER_INTERVAL_ON_TASK ) {
    /*
     *  We have to advance the last known ticks value of the server and update
     *  the watchdog chain accordingly.
     */
    _ISR_Disable( level );
    snapshot = _Watchdog_Ticks_since_boot;
    last_snapshot = ts->Interval_watchdogs.last_snapshot;
    if ( !_Chain_Is_empty( &ts->Interval_watchdogs.Chain ) ) {
      first_watchdog = _Watchdog_First( &ts->Interval_watchdogs.Chain );

      /*
       *  We assume adequate unsigned arithmetic here.
       */
      delta = snapshot - last_snapshot;

      delta_interval = first_watchdog->delta_interval;
      if (delta_interval > delta) {
        delta_interval -= delta;
      } else {
        delta_interval = 0;
      }
      first_watchdog->delta_interval = delta_interval;
    }
    ts->Interval_watchdogs.last_snapshot = snapshot;
    _ISR_Enable( level );

    _Watchdog_Insert( &ts->Interval_watchdogs.Chain, &timer->Ticker );

    if ( !ts->active ) {
      _Timer_server_Reset_interval_system_watchdog( ts );
    }
  } else if ( timer->the_class == TIMER_TIME_OF_DAY_ON_TASK ) {
    /*
     *  We have to advance the last known seconds value of the server and update
     *  the watchdog chain accordingly.
     */
    _ISR_Disable( level );
    snapshot = (Watchdog_Interval) _TOD_Seconds_since_epoch();
    last_snapshot = ts->TOD_watchdogs.last_snapshot;
    if ( !_Chain_Is_empty( &ts->TOD_watchdogs.Chain ) ) {
      first_watchdog = _Watchdog_First( &ts->TOD_watchdogs.Chain );
      delta_interval = first_watchdog->delta_interval;
      if ( snapshot > last_snapshot ) {
        /*
         *  We advanced in time.
         */
        delta = snapshot - last_snapshot;
        if (delta_interval > delta) {
          delta_interval -= delta;
        } else {
          delta_interval = 0;
        }
      } else {
        /*
         *  Someone put us in the past.
         */
        delta = last_snapshot - snapshot;
        delta_interval += delta;
      }
      first_watchdog->delta_interval = delta_interval;
    }
    ts->TOD_watchdogs.last_snapshot = snapshot;
    _ISR_Enable( level );

    _Watchdog_Insert( &ts->TOD_watchdogs.Chain, &timer->Ticker );

    if ( !ts->active ) {
      _Timer_server_Reset_tod_system_watchdog( ts );
    }
  }

  _Thread_Enable_dispatch();
}
Ejemplo n.º 9
0
void _Watchdog_Insert(
  Watchdog_Header       *header,
  Watchdog_Control      *the_watchdog
)
{
  ISR_Level          level;
  Watchdog_Control  *after;
  uint32_t           insert_isr_nest_level;
  Watchdog_Interval  delta_interval;


  insert_isr_nest_level   = _ISR_Nest_level;

  _ISR_Disable( level );

  /*
   *  Check to see if the watchdog has just been inserted by a
   *  higher priority interrupt.  If so, abandon this insert.
   */

  if ( the_watchdog->state != WATCHDOG_INACTIVE ) {
    _ISR_Enable( level );
    return;
  }

  the_watchdog->state = WATCHDOG_BEING_INSERTED;
  _Watchdog_Sync_count++;

restart:
  delta_interval = the_watchdog->initial;

  for ( after = _Watchdog_First( header ) ;
        ;
        after = _Watchdog_Next( after ) ) {

     if ( delta_interval == 0 || !_Watchdog_Next( after ) )
       break;

     if ( delta_interval < after->delta_interval ) {
       after->delta_interval -= delta_interval;
       break;
     }

     delta_interval -= after->delta_interval;

     _ISR_Flash( level );

     if ( the_watchdog->state != WATCHDOG_BEING_INSERTED ) {
       goto exit_insert;
     }

     if ( _Watchdog_Sync_level > insert_isr_nest_level ) {
       _Watchdog_Sync_level = insert_isr_nest_level;
       goto restart;
     }
  }

  _Watchdog_Activate( the_watchdog );

  the_watchdog->delta_interval = delta_interval;

  _Chain_Insert_unprotected( after->Node.previous, &the_watchdog->Node );

  the_watchdog->start_time = _Watchdog_Ticks_since_boot;

exit_insert:
  _Watchdog_Sync_level = insert_isr_nest_level;
  _Watchdog_Sync_count--;
  _ISR_Enable( level );
}