static void _Timer_server_Insert_timer( Timer_server_Control *ts, Timer_Control *timer ) { if ( timer->the_class == TIMER_INTERVAL_ON_TASK ) { _Watchdog_Insert( &ts->Interval_watchdogs.Chain, &timer->Ticker ); } else if ( timer->the_class == TIMER_TIME_OF_DAY_ON_TASK ) { _Watchdog_Insert( &ts->TOD_watchdogs.Chain, &timer->Ticker ); } }
rtems_status_code rtems_timer_reset( rtems_id id ) { Timer_Control *the_timer; ISR_lock_Context lock_context; the_timer = _Timer_Get( id, &lock_context ); if ( the_timer != NULL ) { Per_CPU_Control *cpu; rtems_status_code status; cpu = _Timer_Acquire_critical( the_timer, &lock_context ); if ( _Timer_Is_interval_class( the_timer->the_class ) ) { _Timer_Cancel( cpu, the_timer ); _Watchdog_Insert( &cpu->Watchdog.Header[ PER_CPU_WATCHDOG_MONOTONIC ], &the_timer->Ticker, cpu->Watchdog.ticks + the_timer->initial ); status = RTEMS_SUCCESSFUL; } else { status = RTEMS_NOT_DEFINED; } _Timer_Release( cpu, &lock_context ); return status; } return RTEMS_INVALID_ID; }
rtems_status_code _Timer_Fire( rtems_id id, rtems_interval interval, rtems_timer_service_routine_entry routine, void *user_data, Timer_Classes the_class, Watchdog_Service_routine_entry adaptor ) { Timer_Control *the_timer; ISR_lock_Context lock_context; the_timer = _Timer_Get( id, &lock_context ); if ( the_timer != NULL ) { Per_CPU_Control *cpu; cpu = _Timer_Acquire_critical( the_timer, &lock_context ); _Timer_Cancel( cpu, the_timer ); _Watchdog_Initialize( &the_timer->Ticker, adaptor ); the_timer->the_class = the_class; the_timer->routine = routine; the_timer->user_data = user_data; the_timer->initial = interval; the_timer->start_time = _Timer_Get_CPU_ticks( cpu ); if ( _Timer_Is_interval_class( the_class ) ) { _Watchdog_Insert( &cpu->Watchdog.Header[ PER_CPU_WATCHDOG_MONOTONIC ], &the_timer->Ticker, cpu->Watchdog.ticks + interval ); } else { _Watchdog_Insert( &cpu->Watchdog.Header[ PER_CPU_WATCHDOG_REALTIME ], &the_timer->Ticker, _Watchdog_Realtime_from_seconds( interval ) ); } _Timer_Release( cpu, &lock_context ); return RTEMS_SUCCESSFUL; } return RTEMS_INVALID_ID; }
rtems_status_code rtems_timer_reset( rtems_id id ) { Timer_Control *the_timer; Objects_Locations location; rtems_status_code status = RTEMS_SUCCESSFUL; the_timer = _Timer_Get( id, &location ); switch ( location ) { case OBJECTS_LOCAL: if ( the_timer->the_class == TIMER_INTERVAL ) { _Watchdog_Remove( &the_timer->Ticker ); _Watchdog_Insert( &_Watchdog_Ticks_chain, &the_timer->Ticker ); } else if ( the_timer->the_class == TIMER_INTERVAL_ON_TASK ) { Timer_server_Control *timer_server = _Timer_server; /* * There is no way for a timer to have this class unless * it was scheduled as a server fire. That requires that * the Timer Server be initiated. So this error cannot * occur unless something is internally wrong. */ #if defined(RTEMS_DEBUG) if ( !timer_server ) { _Thread_Enable_dispatch(); return RTEMS_INCORRECT_STATE; } #endif _Watchdog_Remove( &the_timer->Ticker ); (*timer_server->schedule_operation)( timer_server, the_timer ); } else { /* * Must be dormant or time of day timer (e.g. TIMER_DORMANT, * TIMER_TIME_OF_DAY, or TIMER_TIME_OF_DAY_ON_TASK). We * can only reset active interval timers. */ status = RTEMS_NOT_DEFINED; } _Thread_Enable_dispatch(); return status; #if defined(RTEMS_MULTIPROCESSING) case OBJECTS_REMOTE: /* should never return this */ #endif case OBJECTS_ERROR: break; } return RTEMS_INVALID_ID; }
unsigned int alarm( unsigned int seconds ) { unsigned int remaining; Watchdog_Control *the_watchdog; ISR_lock_Context lock_context; ISR_lock_Context lock_context2; Per_CPU_Control *cpu; uint64_t now; uint32_t ticks_per_second; uint32_t ticks; the_watchdog = &_POSIX_signals_Alarm_watchdog; ticks_per_second = TOD_TICKS_PER_SECOND; ticks = seconds * ticks_per_second; _ISR_lock_ISR_disable_and_acquire( &_POSIX_signals_Alarm_lock, &lock_context ); cpu = _Watchdog_Get_CPU( the_watchdog ); _Watchdog_Per_CPU_acquire_critical( cpu, &lock_context2 ); now = cpu->Watchdog.ticks; remaining = (unsigned long) _Watchdog_Cancel( &cpu->Watchdog.Header[ PER_CPU_WATCHDOG_RELATIVE ], the_watchdog, now ); if ( ticks != 0 ) { cpu = _Per_CPU_Get(); _Watchdog_Set_CPU( the_watchdog, cpu ); _Watchdog_Insert( &cpu->Watchdog.Header[ PER_CPU_WATCHDOG_RELATIVE ], the_watchdog, now + ticks ); } _Watchdog_Per_CPU_release_critical( cpu, &lock_context2 ); _ISR_lock_Release_and_ISR_enable( &_POSIX_signals_Alarm_lock, &lock_context ); return ( remaining + ticks_per_second - 1 ) / ticks_per_second; }
static void _POSIX_Timer_Insert( POSIX_Timer_Control *ptimer, Per_CPU_Control *cpu, Watchdog_Interval ticks ) { ptimer->ticks = ticks; /* The state really did not change but just to be safe */ ptimer->state = POSIX_TIMER_STATE_CREATE_RUN; /* Store the time when the timer was started again */ _TOD_Get_as_timespec( &ptimer->time ); _Watchdog_Insert( &cpu->Watchdog.Header[ PER_CPU_WATCHDOG_RELATIVE ], &ptimer->Timer, cpu->Watchdog.ticks + ticks ); }
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 */ }
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(); }