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); }
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 */ }
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 ); }
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 _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 ); }
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; }
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(); }
/** * @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 ); } } }
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 ); }
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 */ }
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; }
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 ); }
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 ); } }
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); }
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; }
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; }
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 }
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 ); }
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; }
void rtems_interrupt_enable( rtems_interrupt_level previous_level ) { _ISR_Enable( previous_level ); }