void _Thread_Reset_timeslice( void )
{
  ISR_Level       level;
  Thread_Control *executing;
  Chain_Control  *ready;

  executing = _Thread_Executing;
  ready     = executing->ready;
  _ISR_Disable( level );
    if ( _Chain_Has_only_one_node( ready ) ) {
      _ISR_Enable( level );
      return;
    }
    _Chain_Extract_unprotected( &executing->Object.Node );
    _Chain_Append_unprotected( ready, &executing->Object.Node );

  _ISR_Flash( level );

    if ( _Thread_Is_heir( executing ) )
      _Thread_Heir = (Thread_Control *) ready->first;

    _Context_Switch_necessary = true;

  _ISR_Enable( level );
}
void _Scheduler_priority_Yield(void)
{
  Scheduler_priority_Per_thread *sched_info;
  ISR_Level                      level;
  Thread_Control                *executing;
  Chain_Control                 *ready;

  executing  = _Thread_Executing;
  sched_info = (Scheduler_priority_Per_thread *) executing->scheduler_info;
  ready      = sched_info->ready_chain;
  _ISR_Disable( level );
    if ( !_Chain_Has_only_one_node( ready ) ) {
      _Chain_Extract_unprotected( &executing->Object.Node );
      _Chain_Append_unprotected( ready, &executing->Object.Node );

      _ISR_Flash( level );

      if ( _Thread_Is_heir( executing ) )
        _Thread_Heir = (Thread_Control *) _Chain_First( ready );
      _Thread_Dispatch_necessary = true;
    }
    else if ( !_Thread_Is_heir( executing ) )
      _Thread_Dispatch_necessary = true;

  _ISR_Enable( level );
}
Exemple #3
0
Thread_Control *_Thread_MP_Find_proxy (
  Objects_Id  the_id
)
{

  Chain_Node           *proxy_node;
  Thread_Control       *the_thread;
  ISR_Level             level;

restart:

  _ISR_Disable( level );

    for (  proxy_node = _Chain_First( &_Thread_MP_Active_proxies );
           !_Chain_Is_tail( &_Thread_MP_Active_proxies, proxy_node ) ;
        ) {

      the_thread = (Thread_Control *) _Addresses_Subtract_offset(
                     proxy_node,
                     _Thread_MP_Proxy_Active_offset
                   );

      if ( _Objects_Are_ids_equal( the_thread->Object.id, the_id ) ) {
        _ISR_Enable( level );
        return the_thread;
      }

      _ISR_Flash( level );

      proxy_node = _Chain_Next( proxy_node );

      /*
       *  A proxy which is only dormant is not in a blocking state.
       *  Therefore, we are looking at proxy which has been moved from
       *  active to inactive chain (by an ISR) and need to restart
       *  the search.
       */

      if ( _States_Is_only_dormant( the_thread->current_state ) ) {
        _ISR_Enable( level );
        goto restart;
      }
    }

  _ISR_Enable( level );
  return NULL;
}
Exemple #4
0
void _Thread_Resume(
  Thread_Control   *the_thread,
  bool              force
)
{

  ISR_Level       level;
  States_Control  current_state;

  _ISR_Disable( level );

  #if defined(RTEMS_ITRON_API)
    if ( force == true )
      the_thread->suspend_count = 0;
    else
      the_thread->suspend_count--;

    if ( the_thread->suspend_count > 0 ) {
      _ISR_Enable( level );
      return;
    }
  #endif

  current_state = the_thread->current_state;
  if ( current_state & STATES_SUSPENDED ) {
    current_state =
    the_thread->current_state = _States_Clear(STATES_SUSPENDED, current_state);

    if ( _States_Is_ready( current_state ) ) {

      _Priority_Add_to_bit_map( &the_thread->Priority_map );

      _Chain_Append_unprotected(the_thread->ready, &the_thread->Object.Node);

      _ISR_Flash( level );

      if ( the_thread->current_priority < _Thread_Heir->current_priority ) {
        _Thread_Heir = the_thread;
        if ( _Thread_Executing->is_preemptible ||
             the_thread->current_priority == 0 )
          _Context_Switch_necessary = true;
      }
    }
  }

  _ISR_Enable( level );
}
void _Thread_Clear_state(
  Thread_Control *the_thread,
  States_Control  state
)
{
  ISR_Level       level;
  States_Control  current_state;

  _ISR_Disable( level );
    current_state = the_thread->current_state;

    if ( current_state & state ) {
      current_state =
      the_thread->current_state = _States_Clear( state, current_state );

      if ( _States_Is_ready( current_state ) ) {

        _Priority_Add_to_bit_map( &the_thread->Priority_map );

        _Chain_Append_unprotected(the_thread->ready, &the_thread->Object.Node);

        _ISR_Flash( level );

        /*
         *  If the thread that was unblocked is more important than the heir,
         *  then we have a new heir.  This may or may not result in a
         *  context switch.
         *
         *  Normal case:
         *    If the current thread is preemptible, then we need to do
         *    a context switch.
         *  Pseudo-ISR case:
         *    Even if the thread isn't preemptible, if the new heir is
         *    a pseudo-ISR system task, we need to do a context switch.
         */
        if ( the_thread->current_priority < _Thread_Heir->current_priority ) {
          _Thread_Heir = the_thread;
          if ( _Thread_Executing->is_preemptible ||
               the_thread->current_priority == 0 )
            _Context_Switch_necessary = true;
        }
      }
  }
  _ISR_Enable( level );
}
void _Scheduler_simple_Yield( void )
{
  ISR_Level       level;
  Thread_Control *executing;

  executing = _Thread_Executing;
  _ISR_Disable( level );

    _Scheduler_simple_Ready_queue_requeue(&_Scheduler, executing);

    _ISR_Flash( level );

    _Scheduler_simple_Schedule();

    if ( !_Thread_Is_heir( executing ) )
      _Thread_Dispatch_necessary = true;

  _ISR_Enable( level );
}
Exemple #7
0
void _Scheduler_simple_Yield(
  const Scheduler_Control *scheduler,
  Thread_Control          *the_thread
)
{
  Scheduler_simple_Context *context =
    _Scheduler_simple_Get_context( scheduler );
  ISR_Level       level;

  _ISR_Disable( level );

    _Chain_Extract_unprotected( &the_thread->Object.Node );
    _Scheduler_simple_Insert_priority_fifo( &context->Ready, the_thread );

    _ISR_Flash( level );

    _Scheduler_simple_Schedule_body( scheduler, the_thread, false );

  _ISR_Enable( level );
}
void _Thread_Ready(
  Thread_Control *the_thread
)
{
  ISR_Level              level;
  Thread_Control *heir;

  _ISR_Disable( level );

  the_thread->current_state = STATES_READY;

  _Priority_Add_to_bit_map( &the_thread->Priority_map );

  _Chain_Append_unprotected( the_thread->ready, &the_thread->Object.Node );

  _ISR_Flash( level );

 _Thread_Calculate_heir();
/*  Priority_Bit_map_control minor;
  Priority_Bit_map_control major;

  _Bitfield_Find_first_bit( _Priority_Major_bit_map, major );
  _Bitfield_Find_first_bit( _Priority_Bit_map[major], minor );
  Priority_Control My_Pri=(major<< 4) +minor ;
//  My_Pri=My_Pri+0x100;
  Chain_Control *xx;
  *xx=_Thread_Ready_chain[ My_Pri ];

  _Thread_Heir=(Thread_Control *)(xx->first);
 
//  _Thread_Heir = (Thread_Control *)_Thread_Ready_chain[ My_Pri ].first;
*/

  heir = _Thread_Heir;

  if ( !_Thread_Is_executing( heir ) && _Thread_Executing->is_preemptible )
    _Context_Switch_necessary = true;

  _ISR_Enable( level );
}
void _Thread_Suspend(
  Thread_Control   *the_thread
)
{
  ISR_Level      level;
  Chain_Control *ready;

  ready = the_thread->ready;
  _ISR_Disable( level );
  #if defined(RTEMS_ITRON_API)
    the_thread->suspend_count++;
  #endif
  if ( !_States_Is_ready( the_thread->current_state ) ) {
    the_thread->current_state =
       _States_Set( STATES_SUSPENDED, the_thread->current_state );
    _ISR_Enable( level );
    return;
  }

  the_thread->current_state = STATES_SUSPENDED;

  if ( _Chain_Has_only_one_node( ready ) ) {

    _Chain_Initialize_empty( ready );
    _Priority_Remove_from_bit_map( &the_thread->Priority_map );

  } else
    _Chain_Extract_unprotected( &the_thread->Object.Node );

  _ISR_Flash( level );

  if ( _Thread_Is_heir( the_thread ) )
     _Thread_Calculate_heir();

  if ( _Thread_Is_executing( the_thread ) )
    _Context_Switch_necessary = true;

  _ISR_Enable( level );
}
void _Thread_Set_state(
  Thread_Control *the_thread,
  States_Control  state
)
{
  ISR_Level      level;
  Chain_Control *ready;

  ready = the_thread->ready;
  _ISR_Disable( level );
  if ( !_States_Is_ready( the_thread->current_state ) ) {
    the_thread->current_state =
       _States_Set( state, the_thread->current_state );
    _ISR_Enable( level );
    return;
  }

  the_thread->current_state = state;

  if ( _Chain_Has_only_one_node( ready ) ) {

    _Chain_Initialize_empty( ready );
    _Priority_Remove_from_bit_map( &the_thread->Priority_map );

  } else
    _Chain_Extract_unprotected( &the_thread->Object.Node );

  _ISR_Flash( level );

  if ( _Thread_Is_heir( the_thread ) )
     _Thread_Calculate_heir();

  if ( _Thread_Is_executing( the_thread ) )
    _Context_Switch_necessary = TRUE;

  _ISR_Enable( level );
}
void _Thread_Change_priority(
  Thread_Control   *the_thread,
  Priority_Control  new_priority,
  bool              prepend_it
)
{
  ISR_Level      level;
  States_Control state, original_state;

  /*
   * Save original state
   */
  original_state = the_thread->current_state;

  /*
   * Set a transient state for the thread so it is pulled off the Ready chains.
   * This will prevent it from being scheduled no matter what happens in an
   * ISR.
   */
  _Thread_Set_transient( the_thread );

  /*
   *  Do not bother recomputing all the priority related information if
   *  we are not REALLY changing priority.
   */
 if ( the_thread->current_priority != new_priority )
    _Thread_Set_priority( the_thread, new_priority );

  _ISR_Disable( level );

  /*
   *  If the thread has more than STATES_TRANSIENT set, then it is blocked,
   *  If it is blocked on a thread queue, then we need to requeue it.
   */
  state = the_thread->current_state;
  if ( state != STATES_TRANSIENT ) {
    /* Only clear the transient state if it wasn't set already */
    if ( ! _States_Is_transient( original_state ) )
      the_thread->current_state = _States_Clear( STATES_TRANSIENT, state );
    _ISR_Enable( level );
    if ( _States_Is_waiting_on_thread_queue( state ) ) {
      _Thread_queue_Requeue( the_thread->Wait.queue, the_thread );
    }
    return;
  }

  /* Only clear the transient state if it wasn't set already */
  if ( ! _States_Is_transient( original_state ) ) {
    /*
     *  Interrupts are STILL disabled.
     *  We now know the thread will be in the READY state when we remove
     *  the TRANSIENT state.  So we have to place it on the appropriate
     *  Ready Queue with interrupts off.
     */
    the_thread->current_state = _States_Clear( STATES_TRANSIENT, state );

    if ( prepend_it )
      _Scheduler_Enqueue_first( the_thread );
    else
      _Scheduler_Enqueue( the_thread );
  }

  _ISR_Flash( level );

  /*
   *  We altered the set of thread priorities.  So let's figure out
   *  who is the heir and if we need to switch to them.
   */
  _Scheduler_Schedule();

  if ( !_Thread_Is_executing_also_the_heir() &&
       _Thread_Executing->is_preemptible )
    _Thread_Dispatch_necessary = true;
  _ISR_Enable( level );
}
Exemple #12
0
void rtems_interrupt_flash(
  rtems_interrupt_level previous_level
)
{
  _ISR_Flash( previous_level );
}
Thread_blocking_operation_States _Thread_queue_Enqueue_priority (
    Thread_queue_Control *the_thread_queue,
    Thread_Control       *the_thread,
    ISR_Level            *level_p
)
{
    Priority_Control     search_priority;
    Thread_Control      *search_thread;
    ISR_Level            level;
    Chain_Control       *header;
    uint32_t             header_index;
    Chain_Node          *the_node;
    Chain_Node          *next_node;
    Chain_Node          *previous_node;
    Chain_Node          *search_node;
    Priority_Control     priority;
    States_Control       block_state;

    _Chain_Initialize_empty( &the_thread->Wait.Block2n );

    priority     = the_thread->current_priority;
    header_index = _Thread_queue_Header_number( priority );
    header       = &the_thread_queue->Queues.Priority[ header_index ];
    block_state  = the_thread_queue->state;

    if ( _Thread_queue_Is_reverse_search( priority ) )
        goto restart_reverse_search;

restart_forward_search:
    search_priority = PRIORITY_MINIMUM - 1;
    _ISR_Disable( level );
    search_thread = (Thread_Control *) header->first;
    while ( !_Chain_Is_tail( header, (Chain_Node *)search_thread ) ) {
        search_priority = search_thread->current_priority;
        if ( priority <= search_priority )
            break;

#if ( CPU_UNROLL_ENQUEUE_PRIORITY == TRUE )
        search_thread = (Thread_Control *) search_thread->Object.Node.next;
        if ( _Chain_Is_tail( header, (Chain_Node *)search_thread ) )
            break;
        search_priority = search_thread->current_priority;
        if ( priority <= search_priority )
            break;
#endif
        _ISR_Flash( level );
        if ( !_States_Are_set( search_thread->current_state, block_state) ) {
            _ISR_Enable( level );
            goto restart_forward_search;
        }
        search_thread =
            (Thread_Control *)search_thread->Object.Node.next;
    }

    if ( the_thread_queue->sync_state !=
            THREAD_BLOCKING_OPERATION_NOTHING_HAPPENED )
        goto synchronize;

    the_thread_queue->sync_state = THREAD_BLOCKING_OPERATION_SYNCHRONIZED;

    if ( priority == search_priority )
        goto equal_priority;

    search_node   = (Chain_Node *) search_thread;
    previous_node = search_node->previous;
    the_node      = (Chain_Node *) the_thread;

    the_node->next         = search_node;
    the_node->previous     = previous_node;
    previous_node->next    = the_node;
    search_node->previous  = the_node;
    the_thread->Wait.queue = the_thread_queue;
    _ISR_Enable( level );
    return THREAD_BLOCKING_OPERATION_NOTHING_HAPPENED;

restart_reverse_search:
    search_priority     = PRIORITY_MAXIMUM + 1;

    _ISR_Disable( level );
    search_thread = (Thread_Control *) header->last;
    while ( !_Chain_Is_head( header, (Chain_Node *)search_thread ) ) {
        search_priority = search_thread->current_priority;
        if ( priority >= search_priority )
            break;
#if ( CPU_UNROLL_ENQUEUE_PRIORITY == TRUE )
        search_thread = (Thread_Control *) search_thread->Object.Node.previous;
        if ( _Chain_Is_head( header, (Chain_Node *)search_thread ) )
            break;
        search_priority = search_thread->current_priority;
        if ( priority >= search_priority )
            break;
#endif
        _ISR_Flash( level );
        if ( !_States_Are_set( search_thread->current_state, block_state) ) {
            _ISR_Enable( level );
            goto restart_reverse_search;
        }
        search_thread = (Thread_Control *)
                        search_thread->Object.Node.previous;
    }

    if ( the_thread_queue->sync_state !=
            THREAD_BLOCKING_OPERATION_NOTHING_HAPPENED )
        goto synchronize;

    the_thread_queue->sync_state = THREAD_BLOCKING_OPERATION_SYNCHRONIZED;

    if ( priority == search_priority )
        goto equal_priority;

    search_node = (Chain_Node *) search_thread;
    next_node   = search_node->next;
    the_node    = (Chain_Node *) the_thread;

    the_node->next          = next_node;
    the_node->previous      = search_node;
    search_node->next       = the_node;
    next_node->previous    = the_node;
    the_thread->Wait.queue = the_thread_queue;
    _ISR_Enable( level );
    return THREAD_BLOCKING_OPERATION_NOTHING_HAPPENED;

equal_priority:               /* add at end of priority group */
    search_node   = _Chain_Tail( &search_thread->Wait.Block2n );
    previous_node = search_node->previous;
    the_node      = (Chain_Node *) the_thread;

    the_node->next         = search_node;
    the_node->previous     = previous_node;
    previous_node->next    = the_node;
    search_node->previous  = the_node;
    the_thread->Wait.queue = the_thread_queue;
    _ISR_Enable( level );
    return THREAD_BLOCKING_OPERATION_NOTHING_HAPPENED;

synchronize:
    /*
     *  An interrupt completed the thread's blocking request.
     *  For example, the blocking thread could have been given
     *  the mutex by an ISR or timed out.
     *
     *  WARNING! Returning with interrupts disabled!
     */
    *level_p = level;
    return the_thread_queue->sync_state;
}
Exemple #14
0
void _Thread_Change_priority(
  Thread_Control   *the_thread,
  Priority_Control  new_priority,
  bool              prepend_it
)
{
  ISR_Level      level;
  States_Control state, original_state;

  /*
   *  If this is a case where prepending the task to its priority is
   *  potentially desired, then we need to consider whether to do it.
   *  This usually occurs when a task lowers its priority implcitly as
   *  the result of losing inherited priority.  Normal explicit priority
   *  change calls (e.g. rtems_task_set_priority) should always do an
   *  append not a prepend.
   */
/*
  if ( prepend_it &&
       _Thread_Is_executing( the_thread ) &&
       new_priority >= the_thread->current_priority )
    prepend_it = true;
*/

  /*
   * Save original state
   */
  original_state = the_thread->current_state;

  /*
   * Set a transient state for the thread so it is pulled off the Ready chains.
   * This will prevent it from being scheduled no matter what happens in an
   * ISR.
   */
  _Thread_Set_transient( the_thread );

  /*
   *  Do not bother recomputing all the priority related information if
   *  we are not REALLY changing priority.
   */
 if ( the_thread->current_priority != new_priority )
    _Thread_Set_priority( the_thread, new_priority );

  _ISR_Disable( level );

  /*
   *  If the thread has more than STATES_TRANSIENT set, then it is blocked,
   *  If it is blocked on a thread queue, then we need to requeue it.
   */
  state = the_thread->current_state;
  if ( state != STATES_TRANSIENT ) {
    /* Only clear the transient state if it wasn't set already */
    if ( ! _States_Is_transient( original_state ) )
      the_thread->current_state = _States_Clear( STATES_TRANSIENT, state );
    _ISR_Enable( level );
    if ( _States_Is_waiting_on_thread_queue( state ) ) {
      _Thread_queue_Requeue( the_thread->Wait.queue, the_thread );
    }
    return;
  }

  /* Only clear the transient state if it wasn't set already */
  if ( ! _States_Is_transient( original_state ) ) {
    /*
     *  Interrupts are STILL disabled.
     *  We now know the thread will be in the READY state when we remove
     *  the TRANSIENT state.  So we have to place it on the appropriate
     *  Ready Queue with interrupts off.
     */
    the_thread->current_state = _States_Clear( STATES_TRANSIENT, state );

    _Priority_Add_to_bit_map( &the_thread->Priority_map );
    if ( prepend_it )
      _Chain_Prepend_unprotected( the_thread->ready, &the_thread->Object.Node );
    else
      _Chain_Append_unprotected( the_thread->ready, &the_thread->Object.Node );
  }

  _ISR_Flash( level );

  /*
   *  We altered the set of thread priorities.  So let's figure out
   *  who is the heir and if we need to switch to them.
   */
  _Thread_Calculate_heir();

  if ( !_Thread_Is_executing_also_the_heir() &&
       _Thread_Executing->is_preemptible )
    _Context_Switch_necessary = true;
  _ISR_Enable( level );
}
Exemple #15
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 );
}
Exemple #16
0
void _Event_Surrender(
  Thread_Control *the_thread
)
{
  ISR_Level           level;
  rtems_event_set     pending_events;
  rtems_event_set     event_condition;
  rtems_event_set     seized_events;
  rtems_option        option_set;
  RTEMS_API_Control  *api;

  api = the_thread->API_Extensions[ THREAD_API_RTEMS ];

  option_set = (rtems_option) the_thread->Wait.option;

  _ISR_Disable( level );
  pending_events  = api->pending_events;
  event_condition = (rtems_event_set) the_thread->Wait.count;

  seized_events = _Event_sets_Get( pending_events, event_condition );

  /*
   *  No events were seized in this operation
   */
  if ( _Event_sets_Is_empty( seized_events ) ) {
    _ISR_Enable( level );
    return;
  }

  /*
   *  If we are in an ISR and sending to the current thread, then
   *  we have a critical section issue to deal with.
   */
  if ( _ISR_Is_in_progress() &&
       _Thread_Is_executing( the_thread ) &&
       ((_Event_Sync_state == THREAD_BLOCKING_OPERATION_TIMEOUT) ||
        (_Event_Sync_state == THREAD_BLOCKING_OPERATION_NOTHING_HAPPENED)) ) {
    if ( seized_events == event_condition || _Options_Is_any(option_set) ) {
      api->pending_events = _Event_sets_Clear( pending_events,seized_events );
      the_thread->Wait.count = 0;
      *(rtems_event_set *)the_thread->Wait.return_argument = seized_events;
      _Event_Sync_state = THREAD_BLOCKING_OPERATION_SATISFIED;
    }
    _ISR_Enable( level );
    return;
  }

  /*
   *  Otherwise, this is a normal send to another thread
   */
  if ( _States_Is_waiting_for_event( the_thread->current_state ) ) {
    if ( seized_events == event_condition || _Options_Is_any( option_set ) ) {
      api->pending_events = _Event_sets_Clear( pending_events, seized_events );
      the_thread->Wait.count = 0;
      *(rtems_event_set *)the_thread->Wait.return_argument = seized_events;

      _ISR_Flash( level );

      if ( !_Watchdog_Is_active( &the_thread->Timer ) ) {
        _ISR_Enable( level );
        _Thread_Unblock( the_thread );
      } else {
        _Watchdog_Deactivate( &the_thread->Timer );
        _ISR_Enable( level );
        (void) _Watchdog_Remove( &the_thread->Timer );
        _Thread_Unblock( the_thread );
      }
      return;
    }
  }
  _ISR_Enable( level );
}
void _Watchdog_Insert(
  Chain_Control         *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;

  /*
   * We CANT use _Watchdog_First() here, because a TICK interrupt
   * could modify the chain during the _ISR_Flash() below. Hence,
   * the header is pointing to volatile data. The _Watchdog_First()
   * INLINE routine (but not the macro - note the subtle difference)
   * casts away the 'volatile'...
   *
   * Also, this is only necessary because we call no other routine
   * from this piece of code, hence the compiler thinks it's safe to
   * cache *header!!
   *
   *  Till Straumann, 7/2003 (gcc-3.2.2 -O4 on powerpc)
   *
   */
  for ( after = (Watchdog_Control *) ((volatile Chain_Control *)header)->first ;
        ;
        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;

     /*
      *  If you experience problems comment out the _ISR_Flash line.
      *  3.2.0 was the first release with this critical section redesigned.
      *  Under certain circumstances, the PREVIOUS critical section algorithm
      *  used around this flash point allowed interrupts to execute
      *  which violated the design assumptions.  The critical section
      *  mechanism used here WAS redesigned to address this.
      */

     _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 );
}