Beispiel #1
0
void _TOD_Get(
  struct timespec *time
)
{
  ISR_Level         level;
  Timestamp_Control offset;
  Timestamp_Control now;
  long              nanoseconds;

  /* assume time checked for NULL by caller */

  /* _TOD_Now is the native current time */
  nanoseconds = 0;
  _ISR_Disable( level );
    now = _TOD_Now;
    if ( _Watchdog_Nanoseconds_since_tick_handler )
      nanoseconds = (*_Watchdog_Nanoseconds_since_tick_handler)();
  _ISR_Enable( level );

  _Timestamp_Set( &offset, 0, nanoseconds );
  _Timestamp_Add_to( &now, &offset );
  _Timestamp_To_timespec( &now, time );
}
void _Scheduler_priority_Yield( Thread_Control *thread )
{
  Scheduler_priority_Per_thread *sched_info;
  ISR_Level                      level;
  Chain_Control                 *ready;

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

      _ISR_Flash( level );

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

  _ISR_Enable( level );
}
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);
}
Beispiel #4
0
unsigned int sh_set_irq_priority(
  unsigned int irq,
  unsigned int prio )
{
  uint32_t   shiftcount;
  uint32_t   prioreg;
  uint16_t   temp16;
  ISR_Level  level;

  /*
   * first check for valid interrupt
   */
  if (( irq > 156) || (irq < 64) || (_Hardware_isr_Table[irq] == _dummy_isp))
    return -1;
  /*
   * check for valid irq priority
   */
  if ( prio > 15 )
    return -1;

  /*
   * look up appropriate interrupt priority register
   */
  if ( irq > 71)
    {
      irq = irq - 72;
      shiftcount = 12 - ((irq & ~0x03) % 16);

      switch( irq / 16)
	{
	case 0: { prioreg = INTC_IPRC; break;}
	case 1: { prioreg = INTC_IPRD; break;}
	case 2: { prioreg = INTC_IPRE; break;}
	case 3: { prioreg = INTC_IPRF; break;}
	case 4: { prioreg = INTC_IPRG; break;}
	case 5: { prioreg = INTC_IPRH; break;}
	default: return -1;
	}
    }
  else
    {
      shiftcount = 12 - 4 * ( irq % 4);
      if ( irq > 67)
	prioreg = INTC_IPRB;
      else
	prioreg = INTC_IPRA;
    }

  /*
   * Set the interrupt priority register
   */
  _ISR_Disable( level );

    temp16 = read16( prioreg);
    temp16 &= ~( 15 << shiftcount);
    temp16 |= prio << shiftcount;
    write16( temp16, prioreg);

  _ISR_Enable( level );

  return 0;
}
rtems_status_code rtems_timer_server_fire_after(
  Objects_Id                         id,
  rtems_interval                     ticks,
  rtems_timer_service_routine_entry  routine,
  void                              *user_data
)
{
  Timer_Control        *the_timer;
  Objects_Locations     location;
  ISR_Level             level;

  if ( !_Timer_Server )
    return RTEMS_INCORRECT_STATE;

  if ( !routine )
    return RTEMS_INVALID_ADDRESS;

  if ( ticks == 0 )
    return RTEMS_INVALID_NUMBER;

  the_timer = _Timer_Get( id, &location );
  switch ( location ) {
    case OBJECTS_REMOTE:            /* should never return this */
      return RTEMS_INTERNAL_ERROR;

    case OBJECTS_ERROR:
      return RTEMS_INVALID_ID;

    case OBJECTS_LOCAL:
      (void) _Watchdog_Remove( &the_timer->Ticker );

      _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_timer->Ticker.state != WATCHDOG_INACTIVE ) {
          _ISR_Enable( level );
          _Thread_Enable_dispatch();
          return RTEMS_SUCCESSFUL;
        }

        /*
         *  OK.  Now we now the timer was not rescheduled by an interrupt
         *  so we can atomically initialize it as in use.
         */

        the_timer->the_class = TIMER_INTERVAL_ON_TASK;
        _Watchdog_Initialize( &the_timer->Ticker, routine, id, user_data );
        the_timer->Ticker.initial = ticks;
      _ISR_Enable( level );

      _Timer_Server_stop_ticks_timer();
      _Timer_Server_process_ticks_chain();
      _Watchdog_Insert( &_Timer_Ticks_chain, &the_timer->Ticker );
       _Timer_Server_reset_ticks_timer();

      _Thread_Enable_dispatch();
      return RTEMS_SUCCESSFUL;
  }

  return RTEMS_INTERNAL_ERROR;   /* unreached - only to remove warnings */
}
Beispiel #6
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 );
}
Beispiel #7
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 );
}
Beispiel #8
0
void _Event_Seize(
  rtems_event_set  event_in,
  rtems_option     option_set,
  rtems_interval   ticks,
  rtems_event_set *event_out
)
{
  Thread_Control                   *executing;
  rtems_event_set                   seized_events;
  rtems_event_set                   pending_events;
  ISR_Level                         level;
  RTEMS_API_Control                *api;
  Thread_blocking_operation_States  sync_state;

  executing = _Thread_Executing;
  executing->Wait.return_code = RTEMS_SUCCESSFUL;

  api = executing->API_Extensions[ THREAD_API_RTEMS ];

  _ISR_Disable( level );
  pending_events = api->pending_events;
  seized_events  = _Event_sets_Get( pending_events, event_in );

  if ( !_Event_sets_Is_empty( seized_events ) &&
       (seized_events == event_in || _Options_Is_any( option_set )) ) {
    api->pending_events =
      _Event_sets_Clear( pending_events, seized_events );
    _ISR_Enable( level );
    *event_out = seized_events;
    return;
  }

  if ( _Options_Is_no_wait( option_set ) ) {
    _ISR_Enable( level );
    executing->Wait.return_code = RTEMS_UNSATISFIED;
    *event_out = seized_events;
    return;
  }

  /*
   *  Note what we are waiting for BEFORE we enter the critical section.
   *  The interrupt critical section management code needs this to be
   *  set properly when we are marked as in the event critical section.
   *
   *  NOTE: Since interrupts are disabled, this isn't that much of an
   *        issue but better safe than sorry.
   */
  executing->Wait.option            = (uint32_t) option_set;
  executing->Wait.count             = (uint32_t) event_in;
  executing->Wait.return_argument   = event_out;

  _Event_Sync_state = THREAD_BLOCKING_OPERATION_NOTHING_HAPPENED;

  _ISR_Enable( level );

  if ( ticks ) {
    _Watchdog_Initialize(
      &executing->Timer,
      _Event_Timeout,
      executing->Object.id,
      NULL
    );
    _Watchdog_Insert_ticks( &executing->Timer, ticks );
  }

  _Thread_Set_state( executing, STATES_WAITING_FOR_EVENT );

  _ISR_Disable( level );

  sync_state = _Event_Sync_state;
  _Event_Sync_state = THREAD_BLOCKING_OPERATION_SYNCHRONIZED;
  if ( sync_state == THREAD_BLOCKING_OPERATION_NOTHING_HAPPENED ) {
    _ISR_Enable( level );
    return;
  }

  /*
   *  An interrupt completed the thread's blocking request.
   *  The blocking thread was satisfied by an ISR or timed out.
   *
   *  WARNING! Returning with interrupts disabled!
   */
  _Thread_blocking_operation_Cancel( sync_state, executing, 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 );
}
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 );
}
Beispiel #11
0
bool _POSIX_signals_Clear_signals(
  POSIX_API_Control  *api,
  int                 signo,
  siginfo_t          *info,
  bool                is_global,
  bool                check_blocked
)
{
  sigset_t                    mask;
  sigset_t                    signals_blocked;
  ISR_Level                   level;
  bool                        do_callout;
  POSIX_signals_Siginfo_node *psiginfo;

  mask = signo_to_mask( signo );

  do_callout = false;

  /* set blocked signals based on if checking for them, SIGNAL_ALL_MASK
   * insures that no signals are blocked and all are checked.
   */

  if ( check_blocked )
    signals_blocked = ~api->signals_blocked;
  else
    signals_blocked = SIGNAL_ALL_MASK;

  /* XXX is this right for siginfo type signals? */
  /* XXX are we sure they can be cleared the same way? */

  _ISR_Disable( level );
    if ( is_global ) {
       if ( mask & (_POSIX_signals_Pending & signals_blocked) ) {
         if ( _POSIX_signals_Vectors[ signo ].sa_flags == SA_SIGINFO ) {
           psiginfo = (POSIX_signals_Siginfo_node *)
             _Chain_Get_unprotected( &_POSIX_signals_Siginfo[ signo ] );
           _POSIX_signals_Clear_process_signals( signo );
           /*
            *  It may be impossible to get here with an empty chain
            *  BUT until that is proven we need to be defensive and
            *  protect against it.
            */
           if ( psiginfo ) {
             *info = psiginfo->Info;
             _Chain_Append_unprotected(
               &_POSIX_signals_Inactive_siginfo,
               &psiginfo->Node
             );
           } else
             do_callout = false;
         }
         _POSIX_signals_Clear_process_signals( signo );
         do_callout = true;
       }
    } else {
      if ( mask & (api->signals_pending & signals_blocked) ) {
        api->signals_pending &= ~mask;
        do_callout = true;
      }
    }
  _ISR_Enable( level );
  return do_callout;
}
Beispiel #12
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();
}
Beispiel #13
0
/**
 *  @brief Timer server body.
 *
 *  This is the server for task based timers.  This task executes whenever a
 *  task-based timer should fire.  It services both "after" and "when" timers.
 *  It is not created automatically but must be created explicitly by the
 *  application before task-based timers may be initiated.  The parameter
 *  @a arg points to the corresponding timer server control block.
 */
static rtems_task _Timer_server_Body(
  rtems_task_argument arg
)
{
  Timer_server_Control *ts = (Timer_server_Control *) arg;
  Chain_Control insert_chain;
  Chain_Control fire_chain;

  _Chain_Initialize_empty( &insert_chain );
  _Chain_Initialize_empty( &fire_chain );

  while ( true ) {
    _Timer_server_Get_watchdogs_that_fire_now( ts, &insert_chain, &fire_chain );

    if ( !_Chain_Is_empty( &fire_chain ) ) {
      /*
       *  Fire the watchdogs.
       */
      while ( true ) {
        Watchdog_Control *watchdog;
        ISR_Level level;

        /*
         *  It is essential that interrupts are disable here since an interrupt
         *  service routine may remove a watchdog from the chain.
         */
        _ISR_Disable( level );
        watchdog = (Watchdog_Control *) _Chain_Get_unprotected( &fire_chain );
        if ( watchdog != NULL ) {
          watchdog->state = WATCHDOG_INACTIVE;
          _ISR_Enable( level );
        } else {
          _ISR_Enable( level );

          break;
        }

        /*
         *  The timer server may block here and wait for resources or time.
         *  The system watchdogs are inactive and will remain inactive since
         *  the active flag of the timer server is true.
         */
        (*watchdog->routine)( watchdog->id, watchdog->user_data );
      }
    } else {
      ts->active = false;

      /*
       *  Block until there is something to do.
       */
      _Thread_Disable_dispatch();
        _Thread_Set_state( ts->thread, STATES_DELAYING );
        _Timer_server_Reset_interval_system_watchdog( ts );
        _Timer_server_Reset_tod_system_watchdog( ts );
      _Thread_Enable_dispatch();

      ts->active = true;

      /*
       *  Maybe an interrupt did reset the system timers, so we have to stop
       *  them here.  Since we are active now, there will be no more resets
       *  until we are inactive again.
       */
      _Timer_server_Stop_interval_system_watchdog( ts );
      _Timer_server_Stop_tod_system_watchdog( ts );
    }
  }
}
Beispiel #14
0
void _Thread_Dispatch( void )
{
  Per_CPU_Control  *cpu_self;
  Thread_Control   *executing;
  ISR_Level         level;

#if defined( RTEMS_SMP )
  /*
   * On SMP the complete context switch must be atomic with respect to one
   * processor.  See also _Thread_Handler() since _Context_switch() may branch
   * to this function.
   */
  _ISR_Disable_without_giant( level );
#endif

  cpu_self = _Per_CPU_Get();
  _Assert( cpu_self->thread_dispatch_disable_level == 0 );
  _Profiling_Thread_dispatch_disable( cpu_self, 0 );
  cpu_self->thread_dispatch_disable_level = 1;

  /*
   *  Now determine if we need to perform a dispatch on the current CPU.
   */
  executing = cpu_self->executing;

#if !defined( RTEMS_SMP )
  _ISR_Disable( level );
#endif

#if defined( RTEMS_SMP )
  if ( cpu_self->dispatch_necessary ) {
#else
  while ( cpu_self->dispatch_necessary ) {
#endif
    Thread_Control *heir = _Thread_Get_heir_and_make_it_executing( cpu_self );

    /*
     *  When the heir and executing are the same, then we are being
     *  requested to do the post switch dispatching.  This is normally
     *  done to dispatch signals.
     */
    if ( heir == executing )
      goto post_switch;

    /*
     *  Since heir and executing are not the same, we need to do a real
     *  context switch.
     */
#if __RTEMS_ADA__
    executing->rtems_ada_self = rtems_ada_self;
    rtems_ada_self = heir->rtems_ada_self;
#endif
    if ( heir->budget_algorithm == THREAD_CPU_BUDGET_ALGORITHM_RESET_TIMESLICE )
      heir->cpu_time_budget = rtems_configuration_get_ticks_per_timeslice();

#if !defined( RTEMS_SMP )
    _ISR_Enable( level );
#endif

    #ifndef __RTEMS_USE_TICKS_FOR_STATISTICS__
      _Thread_Update_cpu_time_used(
        executing,
        &cpu_self->time_of_last_context_switch
      );
    #else
      {
        _TOD_Get_uptime( &cpu_self->time_of_last_context_switch );
        heir->cpu_time_used++;
      }
    #endif

#if !defined(__DYNAMIC_REENT__)
    /*
     * Switch libc's task specific data.
     */
    if ( _Thread_libc_reent ) {
      executing->libc_reent = *_Thread_libc_reent;
      *_Thread_libc_reent = heir->libc_reent;
    }
#endif

    _User_extensions_Thread_switch( executing, heir );

    /*
     *  If the CPU has hardware floating point, then we must address saving
     *  and restoring it as part of the context switch.
     *
     *  The second conditional compilation section selects the algorithm used
     *  to context switch between floating point tasks.  The deferred algorithm
     *  can be significantly better in a system with few floating point tasks
     *  because it reduces the total number of save and restore FP context
     *  operations.  However, this algorithm can not be used on all CPUs due
     *  to unpredictable use of FP registers by some compilers for integer
     *  operations.
     */

#if ( CPU_HARDWARE_FP == TRUE ) || ( CPU_SOFTWARE_FP == TRUE )
#if ( CPU_USE_DEFERRED_FP_SWITCH != TRUE )
    if ( executing->fp_context != NULL )
      _Context_Save_fp( &executing->fp_context );
#endif
#endif

    _Context_Switch( &executing->Registers, &heir->Registers );

#if ( CPU_HARDWARE_FP == TRUE ) || ( CPU_SOFTWARE_FP == TRUE )
#if ( CPU_USE_DEFERRED_FP_SWITCH == TRUE )
    if ( (executing->fp_context != NULL) &&
         !_Thread_Is_allocated_fp( executing ) ) {
      if ( _Thread_Allocated_fp != NULL )
        _Context_Save_fp( &_Thread_Allocated_fp->fp_context );
      _Context_Restore_fp( &executing->fp_context );
      _Thread_Allocated_fp = executing;
    }
#else
    if ( executing->fp_context != NULL )
      _Context_Restore_fp( &executing->fp_context );
#endif
#endif

    /*
     * We have to obtain this value again after the context switch since the
     * heir thread may have migrated from another processor.  Values from the
     * stack or non-volatile registers reflect the old execution environment.
     */
    cpu_self = _Per_CPU_Get();

    _Thread_Debug_set_real_processor( executing, cpu_self );

#if !defined( RTEMS_SMP )
    _ISR_Disable( level );
#endif
  }

post_switch:
  _Assert( cpu_self->thread_dispatch_disable_level == 1 );
  cpu_self->thread_dispatch_disable_level = 0;
  _Profiling_Thread_dispatch_enable( cpu_self, 0 );

  _ISR_Enable_without_giant( level );

  _Thread_Run_post_switch_actions( executing );
}
void _Thread_Dispatch( void )
{
  Thread_Control   *executing;
  Thread_Control   *heir;
  ISR_Level         level;

  #if defined(RTEMS_SMP)
    /*
     * WARNING: The SMP sequence has severe defects regarding the real-time
     * performance.
     *
     * Consider the following scenario.  We have three tasks L (lowest
     * priority), M (middle priority), and H (highest priority).  Now let a
     * thread dispatch from M to L happen.  An interrupt occurs in
     * _Thread_Dispatch() here:
     *
     * void _Thread_Dispatch( void )
     * {
     *   [...]
     *
     * post_switch:
     *
     *   _ISR_Enable( level );
     *
     *   <-- INTERRUPT
     *   <-- AFTER INTERRUPT
     *
     *   _Thread_Unnest_dispatch();
     *
     *   _API_extensions_Run_post_switch();
     * }
     *
     * The interrupt event makes task H ready.  The interrupt code will see
     * _Thread_Dispatch_disable_level > 0 and thus doesn't perform a
     * _Thread_Dispatch().  Now we return to position "AFTER INTERRUPT".  This
     * means task L executes now although task H is ready!  Task H will execute
     * once someone calls _Thread_Dispatch().
     */
    _Thread_Disable_dispatch();

    /*
     *  If necessary, send dispatch request to other cores.
     */
    _SMP_Request_other_cores_to_dispatch();
  #endif

  /*
   *  Now determine if we need to perform a dispatch on the current CPU.
   */
  executing   = _Thread_Executing;
  _ISR_Disable( level );
  while ( _Thread_Dispatch_necessary == true ) {
    heir = _Thread_Heir;
    #ifndef RTEMS_SMP
      _Thread_Dispatch_set_disable_level( 1 );
    #endif
    _Thread_Dispatch_necessary = false;
    _Thread_Executing = heir;

    /*
     *  When the heir and executing are the same, then we are being
     *  requested to do the post switch dispatching.  This is normally
     *  done to dispatch signals.
     */
    if ( heir == executing )
      goto post_switch;

    /*
     *  Since heir and executing are not the same, we need to do a real
     *  context switch.
     */
#if __RTEMS_ADA__
    executing->rtems_ada_self = rtems_ada_self;
    rtems_ada_self = heir->rtems_ada_self;
#endif
    if ( heir->budget_algorithm == THREAD_CPU_BUDGET_ALGORITHM_RESET_TIMESLICE )
      heir->cpu_time_budget = _Thread_Ticks_per_timeslice;

    _ISR_Enable( level );

    #ifndef __RTEMS_USE_TICKS_FOR_STATISTICS__
      {
        Timestamp_Control uptime, ran;
        _TOD_Get_uptime( &uptime );
        _Timestamp_Subtract(
          &_Thread_Time_of_last_context_switch,
          &uptime,
          &ran
        );
        _Timestamp_Add_to( &executing->cpu_time_used, &ran );
        _Thread_Time_of_last_context_switch = uptime;
      }
    #else
      {
        _TOD_Get_uptime( &_Thread_Time_of_last_context_switch );
        heir->cpu_time_used++;
      }
    #endif

    /*
     * Switch libc's task specific data.
     */
    if ( _Thread_libc_reent ) {
      executing->libc_reent = *_Thread_libc_reent;
      *_Thread_libc_reent = heir->libc_reent;
    }

    _User_extensions_Thread_switch( executing, heir );

    /*
     *  If the CPU has hardware floating point, then we must address saving
     *  and restoring it as part of the context switch.
     *
     *  The second conditional compilation section selects the algorithm used
     *  to context switch between floating point tasks.  The deferred algorithm
     *  can be significantly better in a system with few floating point tasks
     *  because it reduces the total number of save and restore FP context
     *  operations.  However, this algorithm can not be used on all CPUs due
     *  to unpredictable use of FP registers by some compilers for integer
     *  operations.
     */

#if ( CPU_HARDWARE_FP == TRUE ) || ( CPU_SOFTWARE_FP == TRUE )
#if ( CPU_USE_DEFERRED_FP_SWITCH != TRUE )
    if ( executing->fp_context != NULL )
      _Context_Save_fp( &executing->fp_context );
#endif
#endif

    _Context_Switch( &executing->Registers, &heir->Registers );

#if ( CPU_HARDWARE_FP == TRUE ) || ( CPU_SOFTWARE_FP == TRUE )
#if ( CPU_USE_DEFERRED_FP_SWITCH == TRUE )
    if ( (executing->fp_context != NULL) &&
         !_Thread_Is_allocated_fp( executing ) ) {
      if ( _Thread_Allocated_fp != NULL )
        _Context_Save_fp( &_Thread_Allocated_fp->fp_context );
      _Context_Restore_fp( &executing->fp_context );
      _Thread_Allocated_fp = executing;
    }
#else
    if ( executing->fp_context != NULL )
      _Context_Restore_fp( &executing->fp_context );
#endif
#endif

    executing = _Thread_Executing;

    _ISR_Disable( level );
  }

post_switch:
  #ifndef RTEMS_SMP
    _Thread_Dispatch_set_disable_level( 0 );
  #endif

  _ISR_Enable( level );

  #ifdef RTEMS_SMP
    _Thread_Unnest_dispatch();
  #endif

  _API_extensions_Run_post_switch( executing );
}
Beispiel #16
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 );
}
void _CORE_RWLock_Obtain_for_writing(
  CORE_RWLock_Control                 *the_rwlock,
  Objects_Id                           id,
  bool                                 wait,
  Watchdog_Interval                    timeout,
  CORE_RWLock_API_mp_support_callout   api_rwlock_mp_support
)
{
  ISR_Level       level;
  Thread_Control *executing = _Thread_Executing;

  /*
   *  If unlocked, then OK to read.
   *  Otherwise, we have to block.
   *  If locked for reading and no waiters, then OK to read.
   *  If any thread is waiting, then we wait.
   */

  _ISR_Disable( level );
    switch ( the_rwlock->current_state ) {
      case CORE_RWLOCK_UNLOCKED:
	the_rwlock->current_state = CORE_RWLOCK_LOCKED_FOR_WRITING;
	_ISR_Enable( level );
	executing->Wait.return_code = CORE_RWLOCK_SUCCESSFUL;
	return;

      case CORE_RWLOCK_LOCKED_FOR_READING:
      case CORE_RWLOCK_LOCKED_FOR_WRITING:
        break;
    }

    /*
     *  If the thread is not willing to wait, then return immediately.
     */

    if ( !wait ) {
      _ISR_Enable( level );
      executing->Wait.return_code = CORE_RWLOCK_UNAVAILABLE;
      return;
    }

    /*
     *  We need to wait to enter this critical section
     */

    _Thread_queue_Enter_critical_section( &the_rwlock->Wait_queue );
    executing->Wait.queue       = &the_rwlock->Wait_queue;
    executing->Wait.id          = id;
    executing->Wait.option      = CORE_RWLOCK_THREAD_WAITING_FOR_WRITE;
    executing->Wait.return_code = CORE_RWLOCK_SUCCESSFUL;
    _ISR_Enable( level );

    _Thread_queue_Enqueue_with_handler(
       &the_rwlock->Wait_queue,
       timeout,
       _CORE_RWLock_Timeout
    );


    /* return to API level so it can dispatch and we block */
}
Beispiel #18
0
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;
}
Beispiel #19
0
void _CORE_message_queue_Seize(
  CORE_message_queue_Control      *the_message_queue,
  Thread_Control                  *executing,
  Objects_Id                       id,
  void                            *buffer,
  size_t                          *size_p,
  bool                             wait,
  Watchdog_Interval                timeout
)
{
  ISR_Level                          level;
  CORE_message_queue_Buffer_control *the_message;

  executing->Wait.return_code = CORE_MESSAGE_QUEUE_STATUS_SUCCESSFUL;
  _ISR_Disable( level );
  the_message = _CORE_message_queue_Get_pending_message( the_message_queue );
  if ( the_message != NULL ) {
    the_message_queue->number_of_pending_messages -= 1;
    _ISR_Enable( level );

    *size_p = the_message->Contents.size;
    executing->Wait.count =
      _CORE_message_queue_Get_message_priority( the_message );
    _CORE_message_queue_Copy_buffer(
      the_message->Contents.buffer,
      buffer,
      *size_p
    );

    #if !defined(RTEMS_SCORE_COREMSG_ENABLE_BLOCKING_SEND)
      /*
       *  There is not an API with blocking sends enabled.
       *  So return immediately.
       */
      _CORE_message_queue_Free_message_buffer(the_message_queue, the_message);
      return;
    #else
    {
      Thread_Control   *the_thread;

      /*
       *  There could be a thread waiting to send a message.  If there
       *  is not, then we can go ahead and free the buffer.
       *
       *  NOTE: If we note that the queue was not full before this receive,
       *  then we can avoid this dequeue.
       */
      the_thread = _Thread_queue_Dequeue( &the_message_queue->Wait_queue );
      if ( !the_thread ) {
        _CORE_message_queue_Free_message_buffer(
          the_message_queue,
          the_message
        );
        return;
      }

      /*
       *  There was a thread waiting to send a message.  This code
       *  puts the messages in the message queue on behalf of the
       *  waiting task.
       */
      _CORE_message_queue_Set_message_priority(
        the_message,
        the_thread->Wait.count
      );
      the_message->Contents.size = (size_t) the_thread->Wait.option;
      _CORE_message_queue_Copy_buffer(
        the_thread->Wait.return_argument_second.immutable_object,
        the_message->Contents.buffer,
        the_message->Contents.size
      );

      _CORE_message_queue_Insert_message(
         the_message_queue,
         the_message,
         _CORE_message_queue_Get_message_priority( the_message )
      );
      return;
    }
    #endif
  }

  if ( !wait ) {
    _ISR_Enable( level );
    executing->Wait.return_code = CORE_MESSAGE_QUEUE_STATUS_UNSATISFIED_NOWAIT;
    return;
  }

  _Thread_queue_Enter_critical_section( &the_message_queue->Wait_queue );
  executing->Wait.queue = &the_message_queue->Wait_queue;
  executing->Wait.id = id;
  executing->Wait.return_argument_second.mutable_object = buffer;
  executing->Wait.return_argument = size_p;
  /* Wait.count will be filled in with the message priority */
  _ISR_Enable( level );

  _Thread_queue_Enqueue(
    &the_message_queue->Wait_queue,
    executing,
    STATES_WAITING_FOR_MESSAGE,
    timeout
  );
}
Beispiel #20
0
CORE_spinlock_Status _CORE_spinlock_Wait(
  CORE_spinlock_Control  *the_spinlock,
  bool                    wait,
  Watchdog_Interval       timeout
)
{
  ISR_Level level;
  #if defined(FUNCTIONALITY_NOT_CURRENTLY_USED_BY_ANY_API)
    Watchdog_Interval       limit = _Watchdog_Ticks_since_boot + timeout;
  #endif

  _ISR_Disable( level );
    if ( (the_spinlock->lock == CORE_SPINLOCK_LOCKED) &&
         (the_spinlock->holder == _Thread_Executing->Object.id) ) {
      _ISR_Enable( level );
      return CORE_SPINLOCK_HOLDER_RELOCKING;
    }
    the_spinlock->users += 1;
    for ( ;; ) {
      if ( the_spinlock->lock == CORE_SPINLOCK_UNLOCKED ) {
        the_spinlock->lock = CORE_SPINLOCK_LOCKED;
        the_spinlock->holder = _Thread_Executing->Object.id;
        _ISR_Enable( level );
        return CORE_SPINLOCK_SUCCESSFUL;
      }

      /*
       *  Spinlock is unavailable.  If not willing to wait, return.
       */
      if ( !wait ) {
        the_spinlock->users -= 1;
        _ISR_Enable( level );
        return CORE_SPINLOCK_UNAVAILABLE;
      }

      #if defined(FUNCTIONALITY_NOT_CURRENTLY_USED_BY_ANY_API)
        /*
         *  They are willing to wait but there could be a timeout.
         */
        if ( timeout && (limit <= _Watchdog_Ticks_since_boot) ) {
          the_spinlock->users -= 1;
          _ISR_Enable( level );
          return CORE_SPINLOCK_TIMEOUT;
        }
      #endif

      /*
       *  The thread is willing to spin so let's set things up so
       *  another thread has a chance of running.  This spinlock has
       *  to be released by either another thread or an ISR.  Since
       *  POSIX does not say anything about ISRs, that implies that
       *  another thread must be able to run while spinning.  We are
       *  not blocking so that implies we are at least preemptible
       *  and possibly time-sliced.
       *
       *  So first, we will enable interrpts to allow for them to happen.
       *  Then we will "flash" the thread dispatching critical section
       *  so other threads have a chance to run.
       *
       *  A spinlock cannot be deleted while it is being used so we are
       *  safe from deletion.
       */

       _ISR_Enable( level );
       /* An ISR could occur here */

       _Thread_Enable_dispatch();
       /* Another thread could get dispatched here */

       /* Reenter the critical sections so we can attempt the lock again. */
       _Thread_Disable_dispatch();

       _ISR_Disable( level );
    }

}
Beispiel #21
0
void _Objects_Extend_information(
  Objects_Information *information
)
{
  Objects_Control  *the_object;
  Chain_Control     Inactive;
  uint32_t          block_count;
  uint32_t          block;
  uint32_t          index_base;
  uint32_t          minimum_index;
  uint32_t          index;
  uint32_t          maximum;
  size_t            block_size;
  void             *new_object_block;
  bool              do_extend;

  /*
   *  Search for a free block of indexes. If we do NOT need to allocate or
   *  extend the block table, then we will change do_extend.
   */
  do_extend     = true;
  minimum_index = _Objects_Get_index( information->minimum_id );
  index_base    = minimum_index;
  block         = 0;

  /* if ( information->maximum < minimum_index ) */
  if ( information->object_blocks == NULL )
    block_count = 0;
  else {
    block_count = information->maximum / information->allocation_size;

    for ( ; block < block_count; block++ ) {
      if ( information->object_blocks[ block ] == NULL ) {
        do_extend = false;
        break;
      } else
        index_base += information->allocation_size;
    }
  }

  maximum = (uint32_t) information->maximum + information->allocation_size;

  /*
   *  We need to limit the number of objects to the maximum number
   *  representable in the index portion of the object Id.  In the
   *  case of 16-bit Ids, this is only 256 object instances.
   */
  if ( maximum > OBJECTS_ID_FINAL_INDEX ) {
    return;
  }

  /*
   * Allocate the name table, and the objects and if it fails either return or
   * generate a fatal error depending on auto-extending being active.
   */
  block_size = information->allocation_size * information->size;
  if ( information->auto_extend ) {
    new_object_block = _Workspace_Allocate( block_size );
    if ( !new_object_block )
      return;
  } else {
    new_object_block = _Workspace_Allocate_or_fatal_error( block_size );
  }

  /*
   *  Do we need to grow the tables?
   */
  if ( do_extend ) {
    ISR_Level         level;
    void            **object_blocks;
    uint32_t         *inactive_per_block;
    Objects_Control **local_table;
    void             *old_tables;
    size_t            block_size;

    /*
     *  Growing the tables means allocating a new area, doing a copy and
     *  updating the information table.
     *
     *  If the maximum is minimum we do not have a table to copy. First
     *  time through.
     *
     *  The allocation has :
     *
     *      void            *objects[block_count];
     *      uint32_t         inactive_count[block_count];
     *      Objects_Control *local_table[maximum];
     *
     *  This is the order in memory. Watch changing the order. See the memcpy
     *  below.
     */

    /*
     *  Up the block count and maximum
     */
    block_count++;

    /*
     *  Allocate the tables and break it up.
     */
    block_size = block_count *
           (sizeof(void *) + sizeof(uint32_t) + sizeof(Objects_Name *)) +
          ((maximum + minimum_index) * sizeof(Objects_Control *));
    object_blocks = (void**) _Workspace_Allocate( block_size );

    if ( !object_blocks ) {
      _Workspace_Free( new_object_block );
      return;
    }

    /*
     *  Break the block into the various sections.
     */
    inactive_per_block = (uint32_t *) _Addresses_Add_offset(
        object_blocks, block_count * sizeof(void*) );
    local_table = (Objects_Control **) _Addresses_Add_offset(
        inactive_per_block, block_count * sizeof(uint32_t) );

    /*
     *  Take the block count down. Saves all the (block_count - 1)
     *  in the copies.
     */
    block_count--;

    if ( information->maximum > minimum_index ) {

      /*
       *  Copy each section of the table over. This has to be performed as
       *  separate parts as size of each block has changed.
       */

      memcpy( object_blocks,
              information->object_blocks,
              block_count * sizeof(void*) );
      memcpy( inactive_per_block,
              information->inactive_per_block,
              block_count * sizeof(uint32_t) );
      memcpy( local_table,
              information->local_table,
              (information->maximum + minimum_index) * sizeof(Objects_Control *) );
    } else {

      /*
       *  Deal with the special case of the 0 to minimum_index
       */
      for ( index = 0; index < minimum_index; index++ ) {
        local_table[ index ] = NULL;
      }
    }

    /*
     *  Initialise the new entries in the table.
     */
    object_blocks[block_count] = NULL;
    inactive_per_block[block_count] = 0;

    for ( index=index_base ;
          index < ( information->allocation_size + index_base );
          index++ ) {
      local_table[ index ] = NULL;
    }

    _ISR_Disable( level );

    old_tables = information->object_blocks;

    information->object_blocks = object_blocks;
    information->inactive_per_block = inactive_per_block;
    information->local_table = local_table;
    information->maximum = (Objects_Maximum) maximum;
    information->maximum_id = _Objects_Build_id(
        information->the_api,
        information->the_class,
        _Objects_Local_node,
        information->maximum
      );

    _ISR_Enable( level );

    _Workspace_Free( old_tables );

    block_count++;
  }

  /*
   *  Assign the new object block to the object block table.
   */
  information->object_blocks[ block ] = new_object_block;

  /*
   *  Initialize objects .. add to a local chain first.
   */
  _Chain_Initialize(
    &Inactive,
    information->object_blocks[ block ],
    information->allocation_size,
    information->size
  );

  /*
   *  Move from the local chain, initialise, then append to the inactive chain
   */
  index = index_base;

  while ((the_object = (Objects_Control *) _Chain_Get( &Inactive )) != NULL ) {

    the_object->id = _Objects_Build_id(
        information->the_api,
        information->the_class,
        _Objects_Local_node,
        index
      );

    _Chain_Append( &information->Inactive, &the_object->Node );

    index++;
  }

  information->inactive_per_block[ block ] = information->allocation_size;
  information->inactive =
    (Objects_Maximum)(information->inactive + information->allocation_size);
}
Beispiel #22
0
rtems_status_code rtems_semaphore_obtain(
  rtems_id        id,
  rtems_option    option_set,
  rtems_interval  timeout
)
{
  Semaphore_Control              *the_semaphore;
  Objects_Locations               location;
  ISR_Level                       level;
  Thread_Control                 *executing;
  rtems_attribute                 attribute_set;
  bool                            wait;

  the_semaphore = _Semaphore_Get_interrupt_disable( id, &location, &level );
  switch ( location ) {

    case OBJECTS_LOCAL:
      executing = _Thread_Executing;
      attribute_set = the_semaphore->attribute_set;
      wait = !_Options_Is_no_wait( option_set );
#if defined(RTEMS_SMP)
      if ( _Attributes_Is_multiprocessor_resource_sharing( attribute_set ) ) {
        MRSP_Status mrsp_status;

        _ISR_Enable( level );
        mrsp_status = _MRSP_Obtain(
          &the_semaphore->Core_control.mrsp,
          executing,
          wait,
          timeout
        );
        _Objects_Put_for_get_isr_disable( &the_semaphore->Object );
        return _Semaphore_Translate_MRSP_status_code( mrsp_status );
      } else
#endif
      if ( !_Attributes_Is_counting_semaphore( attribute_set ) ) {
        _CORE_mutex_Seize(
          &the_semaphore->Core_control.mutex,
          executing,
          id,
          wait,
          timeout,
          level
        );
        _Objects_Put_for_get_isr_disable( &the_semaphore->Object );
        return _Semaphore_Translate_core_mutex_return_code(
                  executing->Wait.return_code );
      }

      /* must be a counting semaphore */
      _CORE_semaphore_Seize_isr_disable(
        &the_semaphore->Core_control.semaphore,
        executing,
        id,
        wait,
        timeout,
        level
      );
      _Objects_Put_for_get_isr_disable( &the_semaphore->Object );
      return _Semaphore_Translate_core_semaphore_return_code(
                  executing->Wait.return_code );

#if defined(RTEMS_MULTIPROCESSING)
    case OBJECTS_REMOTE:
      return _Semaphore_MP_Send_request_packet(
          SEMAPHORE_MP_OBTAIN_REQUEST,
          id,
          option_set,
          timeout
      );
#endif

    case OBJECTS_ERROR:
      break;

  }

  return RTEMS_INVALID_ID;
}
Beispiel #23
0
rtems_status_code rtems_rate_monotonic_period(
  rtems_id       id,
  rtems_interval length
)
{
  Rate_monotonic_Control              *the_period;
  Objects_Locations                    location;
  rtems_status_code                    return_value;
  rtems_rate_monotonic_period_states   local_state;
  ISR_Level                            level;

  the_period = _Rate_monotonic_Get( id, &location );

  switch ( location ) {
    case OBJECTS_LOCAL:
      if ( !_Thread_Is_executing( the_period->owner ) ) {
        _Thread_Enable_dispatch();
        return RTEMS_NOT_OWNER_OF_RESOURCE;
      }

      if ( length == RTEMS_PERIOD_STATUS ) {
        switch ( the_period->state ) {
          case RATE_MONOTONIC_INACTIVE:
            return_value = RTEMS_NOT_DEFINED;
            break;
          case RATE_MONOTONIC_EXPIRED:
          case RATE_MONOTONIC_EXPIRED_WHILE_BLOCKING:
            return_value = RTEMS_TIMEOUT;
            break;
          case RATE_MONOTONIC_ACTIVE:
          default:              /* unreached -- only to remove warnings */
            return_value = RTEMS_SUCCESSFUL;
            break;
        }
        _Thread_Enable_dispatch();
        return( return_value );
      }

      _ISR_Disable( level );
      if ( the_period->state == RATE_MONOTONIC_INACTIVE ) {
        _ISR_Enable( level );

        the_period->next_length = length;

        /*
         *  Baseline statistics information for the beginning of a period.
         */
        _Rate_monotonic_Initiate_statistics( the_period );

        the_period->state = RATE_MONOTONIC_ACTIVE;
        _Watchdog_Initialize(
          &the_period->Timer,
          _Rate_monotonic_Timeout,
          id,
          NULL
        );

        _Watchdog_Insert_ticks( &the_period->Timer, length );
        _Thread_Enable_dispatch();
        return RTEMS_SUCCESSFUL;
      }

      if ( the_period->state == RATE_MONOTONIC_ACTIVE ) {
        /*
         *  Update statistics from the concluding period.
         */
        _Rate_monotonic_Update_statistics( the_period );

        /*
         *  This tells the _Rate_monotonic_Timeout that this task is
         *  in the process of blocking on the period and that we
         *  may be changing the length of the next period.
         */
        the_period->state = RATE_MONOTONIC_OWNER_IS_BLOCKING;
        the_period->next_length = length;

        _ISR_Enable( level );

        _Thread_Executing->Wait.id = the_period->Object.id;
        _Thread_Set_state( _Thread_Executing, STATES_WAITING_FOR_PERIOD );

        /*
         *  Did the watchdog timer expire while we were actually blocking
         *  on it?
         */
        _ISR_Disable( level );
          local_state = the_period->state;
          the_period->state = RATE_MONOTONIC_ACTIVE;
        _ISR_Enable( level );

        /*
         *  If it did, then we want to unblock ourself and continue as
         *  if nothing happen.  The period was reset in the timeout routine.
         */
        if ( local_state == RATE_MONOTONIC_EXPIRED_WHILE_BLOCKING )
          _Thread_Clear_state( _Thread_Executing, STATES_WAITING_FOR_PERIOD );

        _Thread_Enable_dispatch();
        return RTEMS_SUCCESSFUL;
      }

      if ( the_period->state == RATE_MONOTONIC_EXPIRED ) {
        /*
         *  Update statistics from the concluding period
         */
        _Rate_monotonic_Update_statistics( the_period );

        _ISR_Enable( level );

        the_period->state = RATE_MONOTONIC_ACTIVE;
        the_period->next_length = length;

        _Watchdog_Insert_ticks( &the_period->Timer, length );
        _Scheduler_Release_job(the_period->owner, the_period->next_length);
        _Thread_Enable_dispatch();
        return RTEMS_TIMEOUT;
      }

      /*
       *  These should never happen so just return invalid Id.
       *    - RATE_MONOTONIC_OWNER_IS_BLOCKING:
       *    - RATE_MONOTONIC_EXPIRED_WHILE_BLOCKING:
       */
#if defined(RTEMS_MULTIPROCESSING)
    case OBJECTS_REMOTE:            /* should never return this */
#endif
    case OBJECTS_ERROR:
      break;
  }

  return RTEMS_INVALID_ID;
}
CORE_message_queue_Status _CORE_message_queue_Submit(
  CORE_message_queue_Control                *the_message_queue,
  void                                      *buffer,
  size_t                                     size,
  Objects_Id                                 id,
  CORE_message_queue_API_mp_support_callout  api_message_queue_mp_support,
  CORE_message_queue_Submit_types            submit_type,
  boolean                                    wait,
  Watchdog_Interval                          timeout
)
{
  ISR_Level                            level;
  CORE_message_queue_Buffer_control   *the_message;
  Thread_Control                      *the_thread;

  if ( size > the_message_queue->maximum_message_size ) {
    return CORE_MESSAGE_QUEUE_STATUS_INVALID_SIZE;
  }

  /*
   *  Is there a thread currently waiting on this message queue?
   */

  if ( the_message_queue->number_of_pending_messages == 0 ) {
    the_thread = _Thread_queue_Dequeue( &the_message_queue->Wait_queue );
    if ( the_thread ) {
      _CORE_message_queue_Copy_buffer(
        buffer,
        the_thread->Wait.return_argument,
        size
      );
      *(size_t *)the_thread->Wait.return_argument_1 = size;
      the_thread->Wait.count = submit_type;

#if defined(RTEMS_MULTIPROCESSING)
      if ( !_Objects_Is_local_id( the_thread->Object.id ) )
        (*api_message_queue_mp_support) ( the_thread, id );
#endif
      return CORE_MESSAGE_QUEUE_STATUS_SUCCESSFUL;
    }
  }

  /*
   *  No one waiting on the message queue at this time, so attempt to
   *  queue the message up for a future receive.
   */

  if ( the_message_queue->number_of_pending_messages <
       the_message_queue->maximum_pending_messages ) {

    the_message =
        _CORE_message_queue_Allocate_message_buffer( the_message_queue );

    /*
     *  NOTE: If the system is consistent, this error should never occur.
     */

    if ( !the_message ) {
      return CORE_MESSAGE_QUEUE_STATUS_UNSATISFIED;
    }

    _CORE_message_queue_Copy_buffer(
      buffer,
      the_message->Contents.buffer,
      size
    );
    the_message->Contents.size = size;
    the_message->priority  = submit_type;

    _CORE_message_queue_Insert_message(
       the_message_queue,
       the_message,
       submit_type
    );
    return CORE_MESSAGE_QUEUE_STATUS_SUCCESSFUL;
  }

  /*
   *  No message buffers were available so we may need to return an
   *  overflow error or block the sender until the message is placed
   *  on the queue.
   */

  if ( !wait ) {
    return CORE_MESSAGE_QUEUE_STATUS_TOO_MANY;
  }

  /*
   *  Do NOT block on a send if the caller is in an ISR.  It is
   *  deadly to block in an ISR.
   */

  if ( _ISR_Is_in_progress() ) {
    return CORE_MESSAGE_QUEUE_STATUS_UNSATISFIED;
  }

  /*
   *  WARNING!! executing should NOT be used prior to this point.
   *  Thus the unusual choice to open a new scope and declare
   *  it as a variable.  Doing this emphasizes how dangerous it
   *  would be to use this variable prior to here.
   */

  {
    Thread_Control  *executing = _Thread_Executing;

    _ISR_Disable( level );
    _Thread_queue_Enter_critical_section( &the_message_queue->Wait_queue );
    executing->Wait.queue              = &the_message_queue->Wait_queue;
    executing->Wait.id                 = id;
    executing->Wait.return_argument    = buffer;
    executing->Wait.option             = size;
    executing->Wait.count              = submit_type;
    _ISR_Enable( level );

    _Thread_queue_Enqueue( &the_message_queue->Wait_queue, timeout );
  }

  return CORE_MESSAGE_QUEUE_STATUS_UNSATISFIED_WAIT;
}
Beispiel #25
0
void _CORE_message_queue_Insert_message(
  CORE_message_queue_Control        *the_message_queue,
  CORE_message_queue_Buffer_control *the_message,
  CORE_message_queue_Submit_types    submit_type
)
{
  ISR_Level  level;
  #if defined(RTEMS_SCORE_COREMSG_ENABLE_NOTIFICATION)
    bool    notify = false;
    #define SET_NOTIFY() \
      do { \
        if ( the_message_queue->number_of_pending_messages == 0 ) \
          notify = true; \
      } while (0)
  #else
    #define SET_NOTIFY()
  #endif

  _CORE_message_queue_Set_message_priority( the_message, submit_type );

  #if !defined(RTEMS_SCORE_COREMSG_ENABLE_MESSAGE_PRIORITY)
    _ISR_Disable( level );
      SET_NOTIFY();
      the_message_queue->number_of_pending_messages++;
      if ( submit_type == CORE_MESSAGE_QUEUE_SEND_REQUEST )
        _CORE_message_queue_Append_unprotected(the_message_queue, the_message);
      else
        _CORE_message_queue_Prepend_unprotected(the_message_queue, the_message);
    _ISR_Enable( level );
  #else
    if ( submit_type == CORE_MESSAGE_QUEUE_SEND_REQUEST ) {
      _ISR_Disable( level );
        SET_NOTIFY();
        the_message_queue->number_of_pending_messages++;
        _CORE_message_queue_Append_unprotected(the_message_queue, the_message);
      _ISR_Enable( level );
    } else if ( submit_type == CORE_MESSAGE_QUEUE_URGENT_REQUEST ) {
      _ISR_Disable( level );
        SET_NOTIFY();
        the_message_queue->number_of_pending_messages++;
        _CORE_message_queue_Prepend_unprotected(the_message_queue, the_message);
      _ISR_Enable( level );
    } else {
      CORE_message_queue_Buffer_control *this_message;
      Chain_Node                        *the_node;
      Chain_Control                     *the_header;
      int                                the_priority;

      the_priority = _CORE_message_queue_Get_message_priority(the_message);
      the_header = &the_message_queue->Pending_messages;
      the_node = _Chain_First( the_header );
      while ( !_Chain_Is_tail( the_header, the_node ) ) {
        int this_priority;

        this_message = (CORE_message_queue_Buffer_control *) the_node;

        this_priority = _CORE_message_queue_Get_message_priority(this_message);

        if ( this_priority <= the_priority ) {
          the_node = the_node->next;
          continue;
        }
        break;
      }
      _ISR_Disable( level );
        SET_NOTIFY();
        the_message_queue->number_of_pending_messages++;
        _Chain_Insert_unprotected( the_node->previous, &the_message->Node );
      _ISR_Enable( level );
    }
  #endif

  #if defined(RTEMS_SCORE_COREMSG_ENABLE_NOTIFICATION)
    /*
     *  According to POSIX, does this happen before or after the message
     *  is actually enqueued.  It is logical to think afterwards, because
     *  the message is actually in the queue at this point.
     */
    if ( notify && the_message_queue->notify_handler )
      (*the_message_queue->notify_handler)(the_message_queue->notify_argument);
  #endif
}
Beispiel #26
0
Thread_Control *_Thread_queue_Dequeue_priority(
    Thread_queue_Control *the_thread_queue
)
{
    uint32_t        index;
    ISR_Level       level;
    Thread_Control *the_thread = NULL;  /* just to remove warnings */
    Thread_Control *new_first_thread;
    Chain_Node     *head;
    Chain_Node     *tail;
    Chain_Node     *new_first_node;
    Chain_Node     *new_second_node;
    Chain_Node     *last_node;
    Chain_Node     *next_node;
    Chain_Node     *previous_node;

    _ISR_Disable( level );
    for( index=0 ;
            index < TASK_QUEUE_DATA_NUMBER_OF_PRIORITY_HEADERS ;
            index++ ) {
        if ( !_Chain_Is_empty( &the_thread_queue->Queues.Priority[ index ] ) ) {
            the_thread = (Thread_Control *) _Chain_First(
                             &the_thread_queue->Queues.Priority[ index ]
                         );
            goto dequeue;
        }
    }

    /*
     * We did not find a thread to unblock.
     */
    _ISR_Enable( level );
    return NULL;

dequeue:
    the_thread->Wait.queue = NULL;
    new_first_node   = _Chain_First( &the_thread->Wait.Block2n );
    new_first_thread = (Thread_Control *) new_first_node;
    next_node        = the_thread->Object.Node.next;
    previous_node    = the_thread->Object.Node.previous;

    if ( !_Chain_Is_empty( &the_thread->Wait.Block2n ) ) {
        last_node       = _Chain_Last( &the_thread->Wait.Block2n );
        new_second_node = new_first_node->next;

        previous_node->next      = new_first_node;
        next_node->previous      = new_first_node;
        new_first_node->next     = next_node;
        new_first_node->previous = previous_node;

        if ( !_Chain_Has_only_one_node( &the_thread->Wait.Block2n ) ) {
            /* > two threads on 2-n */
            head = _Chain_Head( &new_first_thread->Wait.Block2n );
            tail = _Chain_Tail( &new_first_thread->Wait.Block2n );

            new_second_node->previous = head;
            head->next = new_second_node;
            tail->previous = last_node;
            last_node->next = tail;
        }
    } else {
        previous_node->next = next_node;
        next_node->previous = previous_node;
    }

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

#if defined(RTEMS_MULTIPROCESSING)
    if ( !_Objects_Is_local_id( the_thread->Object.id ) )
        _Thread_MP_Free_proxy( the_thread );
#endif
    return( the_thread );
}
Beispiel #27
0
void _Event_Timeout(
  Objects_Id  id,
  void       *arg
)
{
  Thread_Control                   *the_thread;
  Objects_Locations                 location;
  ISR_Level                         level;
  Thread_blocking_operation_States *sync_state;

  sync_state = arg;

  the_thread = _Thread_Get( id, &location );
  switch ( location ) {

    case OBJECTS_LOCAL:

      /*
       *  If the event manager is not synchronized, then it is either
       *  "nothing happened", "timeout", or "satisfied".   If the_thread
       *  is the executing thread, then it is in the process of blocking
       *  and it is the thread which is responsible for the synchronization
       *  process.
       *
       *  If it is not satisfied, then it is "nothing happened" and
       *  this is the "timeout" transition.  After a request is satisfied,
       *  a timeout is not allowed to occur.
       */
      _ISR_Disable( level );
        /*
         * Verify that the thread is still waiting for the event condition.
         * This test is necessary to avoid state corruption if the timeout
         * happens after the event condition is satisfied in
         * _Event_Surrender().  A satisfied event condition is indicated with
         * count set to zero.
         */
        if ( !the_thread->Wait.count ) {
          _ISR_Enable( level );
          _Objects_Put_without_thread_dispatch( &the_thread->Object );
          return;
        }

        the_thread->Wait.count = 0;
        if ( _Thread_Is_executing( the_thread ) ) {
          if ( *sync_state == THREAD_BLOCKING_OPERATION_NOTHING_HAPPENED )
            *sync_state = THREAD_BLOCKING_OPERATION_TIMEOUT;
        }

        the_thread->Wait.return_code = RTEMS_TIMEOUT;
      _ISR_Enable( level );
      _Thread_Unblock( the_thread );
      _Objects_Put_without_thread_dispatch( &the_thread->Object );
      break;

#if defined(RTEMS_MULTIPROCESSING)
    case OBJECTS_REMOTE:  /* impossible */
#endif
    case OBJECTS_ERROR:
      break;
  }
}
epos_status_code epos_timer_server_fire_after(
  epos_id                           id,
  epos_interval                     ticks,
  epos_timer_service_routine_entry  routine,
  void                              *user_data
)
{
  Timer_Control        *the_timer;
  Objects_Locations     location;
  ISR_Level             level;
  Timer_server_Control *timer_server = _Timer_server;

  if ( !timer_server )
    return RTEMS_INCORRECT_STATE;

  if ( !routine )
    return RTEMS_INVALID_ADDRESS;

  if ( ticks == 0 )
    return RTEMS_INVALID_NUMBER;

  the_timer = _Timer_Get( id, &location );
  switch ( location ) {

    case OBJECTS_LOCAL:
      (void) _Watchdog_Remove( &the_timer->Ticker );

      _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_timer->Ticker.state != WATCHDOG_INACTIVE ) {
          _ISR_Enable( level );
          _Thread_Enable_dispatch();
          return RTEMS_SUCCESSFUL;
        }

        /*
         *  OK.  Now we now the timer was not rescheduled by an interrupt
         *  so we can atomically initialize it as in use.
         */

        the_timer->the_class = TIMER_INTERVAL_ON_TASK;
        _Watchdog_Initialize( &the_timer->Ticker, routine, id, user_data );
        the_timer->Ticker.initial = ticks;
      _ISR_Enable( level );

      (*timer_server->schedule_operation)( timer_server, the_timer );

      _Thread_Enable_dispatch();
      return RTEMS_SUCCESSFUL;

#if defined(RTEMS_MULTIPROCESSING)
    case OBJECTS_REMOTE:            /* should never return this */
#endif
    case OBJECTS_ERROR:
      break;
  }

  return RTEMS_INVALID_ID;
}
int sigtimedwait(
  const sigset_t         *set,
  siginfo_t              *info,
  const struct timespec  *timeout
)
{
  Thread_Control    *the_thread;
  POSIX_API_Control *api;
  Watchdog_Interval  interval;
  siginfo_t          signal_information;
  siginfo_t         *the_info;
  int                signo;
  ISR_Level          level;

  /*
   *  Error check parameters before disabling interrupts.
   */
  if ( !set )
    rtems_set_errno_and_return_minus_one( EINVAL );

  /*  NOTE: This is very specifically a RELATIVE not ABSOLUTE time
   *        in the Open Group specification.
   */

  interval = 0;
  if ( timeout ) {

    if ( !_Timespec_Is_valid( timeout ) )
      rtems_set_errno_and_return_minus_one( EINVAL );

    interval = _Timespec_To_ticks( timeout );

    if ( !interval )
      rtems_set_errno_and_return_minus_one( EINVAL );
  }

  /*
   *  Initialize local variables.
   */

  the_info = ( info ) ? info : &signal_information;

  the_thread = _Thread_Executing;

  api = the_thread->API_Extensions[ THREAD_API_POSIX ];

  /*
   *  What if they are already pending?
   */

  /* API signals pending? */

  _ISR_Disable( level );
  if ( *set & api->signals_pending ) {
    /* XXX real info later */
    the_info->si_signo = _POSIX_signals_Get_highest( api->signals_pending );
    _POSIX_signals_Clear_signals(
      api,
      the_info->si_signo,
      the_info,
      false,
      false
    );
    _ISR_Enable( level );

    the_info->si_code = SI_USER;
    the_info->si_value.sival_int = 0;
    return the_info->si_signo;
  }

  /* Process pending signals? */

  if ( *set & _POSIX_signals_Pending ) {
    signo = _POSIX_signals_Get_highest( _POSIX_signals_Pending );
    _POSIX_signals_Clear_signals( api, signo, the_info, true, false );
    _ISR_Enable( level );

    the_info->si_signo = signo;
    the_info->si_code = SI_USER;
    the_info->si_value.sival_int = 0;
    return signo;
  }

  the_info->si_signo = -1;

  _Thread_Disable_dispatch();
    the_thread->Wait.queue           = &_POSIX_signals_Wait_queue;
    the_thread->Wait.return_code     = EINTR;
    the_thread->Wait.option          = *set;
    the_thread->Wait.return_argument = the_info;
    _Thread_queue_Enter_critical_section( &_POSIX_signals_Wait_queue );
    _ISR_Enable( level );
    _Thread_queue_Enqueue( &_POSIX_signals_Wait_queue, interval );
  _Thread_Enable_dispatch();

  /*
   * When the thread is set free by a signal, it is need to eliminate
   * the signal.
   */

  _POSIX_signals_Clear_signals( api, the_info->si_signo, the_info, false, false );
  errno = _Thread_Executing->Wait.return_code;
  return the_info->si_signo;
}
Beispiel #30
0
void rtems_interrupt_enable(
  rtems_interrupt_level previous_level
)
{
  _ISR_Enable( previous_level );
}