diff options
92 files changed, 2363 insertions, 2588 deletions
diff --git a/cpukit/posix/Makefile.am b/cpukit/posix/Makefile.am index 40bc15339d..62a2a5aa3f 100644 --- a/cpukit/posix/Makefile.am +++ b/cpukit/posix/Makefile.am @@ -196,8 +196,7 @@ libposix_a_SOURCES += src/adjtime.c src/clockgetcpuclockid.c ## TIMER_C_FILES libposix_a_SOURCES += src/ptimer.c src/timercreate.c src/timerdelete.c \ - src/timergetoverrun.c src/timergettime.c src/timersettime.c \ - src/timertsr.c src/timerinserthelper.c + src/timergetoverrun.c src/timergettime.c src/timersettime.c ## ITIMER_C_FILES libposix_a_SOURCES += src/getitimer.c src/setitimer.c diff --git a/cpukit/posix/include/rtems/posix/pthreadimpl.h b/cpukit/posix/include/rtems/posix/pthreadimpl.h index 870b5f9460..16b0163384 100644 --- a/cpukit/posix/include/rtems/posix/pthreadimpl.h +++ b/cpukit/posix/include/rtems/posix/pthreadimpl.h @@ -114,10 +114,7 @@ void _POSIX_Threads_Sporadic_budget_callout( * @param[in] argument is a pointer to the Thread_Control structure * for the thread being replenished. */ -void _POSIX_Threads_Sporadic_budget_TSR( - Objects_Id id, - void *argument -); +void _POSIX_Threads_Sporadic_budget_TSR( Watchdog_Control *watchdog ); /** * @brief Translate sched_param into SuperCore terms. diff --git a/cpukit/posix/include/rtems/posix/threadsup.h b/cpukit/posix/include/rtems/posix/threadsup.h index 55db35ddbd..7cd235409c 100644 --- a/cpukit/posix/include/rtems/posix/threadsup.h +++ b/cpukit/posix/include/rtems/posix/threadsup.h @@ -42,6 +42,8 @@ extern "C" { * each thread in a system with POSIX configured. */ typedef struct { + /** Back pointer to thread of this POSIX API control. */ + Thread_Control *thread; /** This is the POSIX threads attribute set. */ pthread_attr_t Attributes; /** This indicates whether the thread is attached or detached. */ diff --git a/cpukit/posix/include/rtems/posix/timerimpl.h b/cpukit/posix/include/rtems/posix/timerimpl.h index 8b5b42e98a..2eefd7063c 100644 --- a/cpukit/posix/include/rtems/posix/timerimpl.h +++ b/cpukit/posix/include/rtems/posix/timerimpl.h @@ -21,6 +21,7 @@ #include <rtems/posix/timer.h> #include <rtems/score/objectimpl.h> +#include <rtems/score/watchdogimpl.h> #ifdef __cplusplus extern "C" { @@ -51,24 +52,6 @@ extern "C" { #endif /** - * @brief POSIX Timer Manager Timer Service Routine Helper - * - * This is the operation that is run when a timer expires. - */ -void _POSIX_Timer_TSR(Objects_Id timer, void *data); - -/** - * @brief POSIX Timer Watchdog Insertion Helper - */ -bool _POSIX_Timer_Insert_helper( - Watchdog_Control *timer, - Watchdog_Interval ticks, - Objects_Id id, - Watchdog_Service_routine_entry TSR, - void *arg -); - -/** * The following defines the information control block used to manage * this class of objects. */ @@ -98,6 +81,8 @@ RTEMS_INLINE_ROUTINE void _POSIX_Timer_Free ( _Objects_Free( &_POSIX_Timer_Information, &the_timer->Object ); } +void _POSIX_Timer_TSR( Watchdog_Control *the_watchdog ); + /** * @brief POSIX Timer Get * @@ -109,11 +94,38 @@ RTEMS_INLINE_ROUTINE void _POSIX_Timer_Free ( */ RTEMS_INLINE_ROUTINE POSIX_Timer_Control *_POSIX_Timer_Get ( timer_t id, - Objects_Locations *location + Objects_Locations *location, + ISR_lock_Context *lock_context +) +{ + return (POSIX_Timer_Control *) _Objects_Get_isr_disable( + &_POSIX_Timer_Information, + (Objects_Id) id, + location, + lock_context + ); +} + +RTEMS_INLINE_ROUTINE Per_CPU_Control *_POSIX_Timer_Acquire_critical( + POSIX_Timer_Control *ptimer, + ISR_lock_Context *lock_context +) +{ + Per_CPU_Control *cpu; + + cpu = _Watchdog_Get_CPU( &ptimer->Timer ); + _Watchdog_Per_CPU_acquire_critical( cpu, lock_context ); + + return cpu; +} + +RTEMS_INLINE_ROUTINE void _POSIX_Timer_Release( + Per_CPU_Control *cpu, + ISR_lock_Context *lock_context ) { - return (POSIX_Timer_Control *) - _Objects_Get( &_POSIX_Timer_Information, (Objects_Id) id, location ); + _Watchdog_Per_CPU_release_critical( cpu, lock_context ); + _ISR_lock_ISR_enable( lock_context ); } #ifdef __cplusplus diff --git a/cpukit/posix/src/alarm.c b/cpukit/posix/src/alarm.c index e85622fdf1..10443e4760 100644 --- a/cpukit/posix/src/alarm.c +++ b/cpukit/posix/src/alarm.c @@ -22,29 +22,18 @@ #endif #include <unistd.h> +#include <signal.h> -#include <rtems/posix/pthreadimpl.h> -#include <rtems/posix/psignalimpl.h> -#include <rtems/score/threaddispatch.h> #include <rtems/score/todimpl.h> #include <rtems/score/watchdogimpl.h> -/* - * _POSIX_signals_Alarm_TSR - */ -static void _POSIX_signals_Alarm_TSR( - Objects_Id id RTEMS_UNUSED, - void *argument RTEMS_UNUSED -) +ISR_LOCK_DEFINE( static, _POSIX_signals_Alarm_lock, "POSIX Alarm" ) + +static void _POSIX_signals_Alarm_TSR( Watchdog_Control *the_watchdog ) { - #if defined(RTEMS_DEBUG) - int status; - #define KILL_STATUS status = - #else - #define KILL_STATUS (void) - #endif + int status; - KILL_STATUS kill( getpid(), SIGALRM ); + status = kill( getpid(), SIGALRM ); #if defined(RTEMS_DEBUG) /* @@ -52,43 +41,62 @@ static void _POSIX_signals_Alarm_TSR( * cautious. */ _Assert(status == 0); + #else + (void) status; #endif } -static Watchdog_Control _POSIX_signals_Alarm_timer = WATCHDOG_INITIALIZER( - _POSIX_signals_Alarm_TSR, - 0, - NULL +static Watchdog_Control _POSIX_signals_Alarm_watchdog = WATCHDOG_INITIALIZER( + _POSIX_signals_Alarm_TSR ); unsigned int alarm( unsigned int seconds ) { - unsigned int remaining = 0; - Watchdog_Control *the_timer; - Watchdog_States state; - - the_timer = &_POSIX_signals_Alarm_timer; - - _Thread_Disable_dispatch(); - - state = _Watchdog_Remove_seconds( the_timer ); - if ( state == WATCHDOG_ACTIVE ) { - /* - * The stop_time and start_time fields are snapshots of ticks since - * boot. Since alarm() is dealing in seconds, we must account for - * this. - */ - - remaining = the_timer->initial - - ((the_timer->stop_time - the_timer->start_time) / TOD_TICKS_PER_SECOND); + 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 + ); } - if ( seconds ) - _Watchdog_Insert_seconds( the_timer, seconds ); - - _Thread_Enable_dispatch(); + _Watchdog_Per_CPU_release_critical( cpu, &lock_context2 ); + _ISR_lock_Release_and_ISR_enable( + &_POSIX_signals_Alarm_lock, + &lock_context + ); - return remaining; + return ( remaining + ticks_per_second - 1 ) / ticks_per_second; } diff --git a/cpukit/posix/src/nanosleep.c b/cpukit/posix/src/nanosleep.c index 46697ae8fc..21bdb986b6 100644 --- a/cpukit/posix/src/nanosleep.c +++ b/cpukit/posix/src/nanosleep.c @@ -46,6 +46,7 @@ int nanosleep( Per_CPU_Control *cpu_self; Watchdog_Interval ticks; + Watchdog_Interval start; Watchdog_Interval elapsed; @@ -81,6 +82,8 @@ int nanosleep( return 0; } + start = _Watchdog_Ticks_since_boot; + /* * Block for the desired amount of time */ @@ -96,7 +99,7 @@ int nanosleep( * Calculate the time that passed while we were sleeping and how * much remains from what we requested. */ - elapsed = executing->Timer.stop_time - executing->Timer.start_time; + elapsed = _Watchdog_Ticks_since_boot - start; if ( elapsed >= ticks ) ticks = 0; else diff --git a/cpukit/posix/src/pthread.c b/cpukit/posix/src/pthread.c index ac5fbe44bf..001ae7947a 100644 --- a/cpukit/posix/src/pthread.c +++ b/cpukit/posix/src/pthread.c @@ -104,18 +104,15 @@ static bool _POSIX_Threads_Sporadic_budget_TSR_filter( /* * _POSIX_Threads_Sporadic_budget_TSR */ -void _POSIX_Threads_Sporadic_budget_TSR( - Objects_Id id RTEMS_UNUSED, - void *argument -) +void _POSIX_Threads_Sporadic_budget_TSR( Watchdog_Control *watchdog ) { uint32_t ticks; - Thread_Control *the_thread; POSIX_API_Control *api; + Thread_Control *the_thread; + ISR_Level level; - the_thread = argument; - - api = the_thread->API_Extensions[ THREAD_API_POSIX ]; + api = RTEMS_CONTAINER_OF( watchdog, POSIX_API_Control, Sporadic_timer ); + the_thread = api->thread; /* ticks is guaranteed to be at least one */ ticks = _Timespec_To_ticks( &api->schedparam.sched_ss_init_budget ); @@ -133,7 +130,15 @@ void _POSIX_Threads_Sporadic_budget_TSR( /* ticks is guaranteed to be at least one */ ticks = _Timespec_To_ticks( &api->schedparam.sched_ss_repl_period ); - _Watchdog_Insert_ticks( &api->Sporadic_timer, ticks ); + _Thread_Disable_dispatch(); + _ISR_Disable( level ); + _Watchdog_Per_CPU_insert_relative( + &api->Sporadic_timer, + _Per_CPU_Get(), + ticks + ); + _ISR_Enable( level ); + _Thread_Unnest_dispatch(); } static bool _POSIX_Threads_Sporadic_budget_callout_filter( @@ -198,6 +203,7 @@ static bool _POSIX_Threads_Create_extension( api = created->API_Extensions[ THREAD_API_POSIX ]; /* XXX check all fields are touched */ + api->thread = created; _POSIX_Threads_Initialize_attributes( &api->Attributes ); api->detachstate = _POSIX_Threads_Default_attributes.detachstate; api->schedpolicy = _POSIX_Threads_Default_attributes.schedpolicy; @@ -229,11 +235,10 @@ static bool _POSIX_Threads_Create_extension( _Thread_queue_Initialize( &api->Join_List, THREAD_QUEUE_DISCIPLINE_FIFO ); + _Watchdog_Preinitialize( &api->Sporadic_timer, _Per_CPU_Get_by_index( 0 ) ); _Watchdog_Initialize( &api->Sporadic_timer, - _POSIX_Threads_Sporadic_budget_TSR, - created->Object.id, - created + _POSIX_Threads_Sporadic_budget_TSR ); return true; @@ -260,7 +265,7 @@ static void _POSIX_Threads_Terminate_extension( *(void **)the_thread->Wait.return_argument = value_ptr; if ( api->schedpolicy == SCHED_SPORADIC ) - _Watchdog_Remove_ticks( &api->Sporadic_timer ); + _Watchdog_Per_CPU_remove_relative( &api->Sporadic_timer ); _Thread_queue_Destroy( &api->Join_List ); diff --git a/cpukit/posix/src/pthreadcreate.c b/cpukit/posix/src/pthreadcreate.c index 3185ab6553..fc07b1f7e1 100644 --- a/cpukit/posix/src/pthreadcreate.c +++ b/cpukit/posix/src/pthreadcreate.c @@ -74,6 +74,7 @@ int pthread_create( struct sched_param schedparam; Objects_Name name; int rc; + ISR_Level level; if ( !start_routine ) return EFAULT; @@ -246,10 +247,13 @@ int pthread_create( #endif if ( schedpolicy == SCHED_SPORADIC ) { - _Watchdog_Insert_ticks( + _ISR_Disable( level ); + _Watchdog_Per_CPU_insert_relative( &api->Sporadic_timer, + _Per_CPU_Get(), _Timespec_To_ticks( &api->schedparam.sched_ss_repl_period ) ); + _ISR_Enable( level ); } _Thread_Enable_dispatch(); diff --git a/cpukit/posix/src/pthreadsetschedparam.c b/cpukit/posix/src/pthreadsetschedparam.c index c3be366818..c9560f59ac 100644 --- a/cpukit/posix/src/pthreadsetschedparam.c +++ b/cpukit/posix/src/pthreadsetschedparam.c @@ -44,6 +44,7 @@ int pthread_setschedparam( Objects_Locations location; int rc; Priority_Control unused; + ISR_Level level; /* * Check all the parameters @@ -69,8 +70,11 @@ int pthread_setschedparam( case OBJECTS_LOCAL: api = the_thread->API_Extensions[ THREAD_API_POSIX ]; - if ( api->schedpolicy == SCHED_SPORADIC ) - _Watchdog_Remove_ticks( &api->Sporadic_timer ); + if ( api->schedpolicy == SCHED_SPORADIC ) { + _ISR_Disable( level ); + _Watchdog_Per_CPU_remove_relative( &api->Sporadic_timer ); + _ISR_Enable( level ); + } api->schedpolicy = policy; api->schedparam = *param; @@ -97,8 +101,10 @@ int pthread_setschedparam( case SCHED_SPORADIC: api->ss_high_priority = api->schedparam.sched_priority; - _Watchdog_Remove_ticks( &api->Sporadic_timer ); - _POSIX_Threads_Sporadic_budget_TSR( 0, the_thread ); + _ISR_Disable( level ); + _Watchdog_Per_CPU_remove_relative( &api->Sporadic_timer ); + _ISR_Enable( level ); + _POSIX_Threads_Sporadic_budget_TSR( &api->Sporadic_timer ); break; } diff --git a/cpukit/posix/src/timercreate.c b/cpukit/posix/src/timercreate.c index 697f1ceee1..5123071d99 100644 --- a/cpukit/posix/src/timercreate.c +++ b/cpukit/posix/src/timercreate.c @@ -91,7 +91,8 @@ int timer_create( ptimer->timer_data.it_interval.tv_sec = 0; ptimer->timer_data.it_interval.tv_nsec = 0; - _Watchdog_Preinitialize( &ptimer->Timer ); + _Watchdog_Preinitialize( &ptimer->Timer, _Per_CPU_Get_snapshot() ); + _Watchdog_Initialize( &ptimer->Timer, _POSIX_Timer_TSR ); _Objects_Open_u32(&_POSIX_Timer_Information, &ptimer->Object, 0); *timerid = ptimer->Object.id; diff --git a/cpukit/posix/src/timerdelete.c b/cpukit/posix/src/timerdelete.c index 8438b0d5b0..c39de8e168 100644 --- a/cpukit/posix/src/timerdelete.c +++ b/cpukit/posix/src/timerdelete.c @@ -45,16 +45,22 @@ int timer_delete( */ POSIX_Timer_Control *ptimer; Objects_Locations location; + ISR_lock_Context lock_context; + Per_CPU_Control *cpu; _Objects_Allocator_lock(); - ptimer = _POSIX_Timer_Get( timerid, &location ); + ptimer = _POSIX_Timer_Get( timerid, &location, &lock_context ); switch ( location ) { case OBJECTS_LOCAL: _Objects_Close( &_POSIX_Timer_Information, &ptimer->Object ); + cpu = _POSIX_Timer_Acquire_critical( ptimer, &lock_context ); ptimer->state = POSIX_TIMER_STATE_FREE; - _Watchdog_Remove_ticks( &ptimer->Timer ); - _Objects_Put( &ptimer->Object ); + _Watchdog_Remove( + &cpu->Watchdog.Header[ PER_CPU_WATCHDOG_RELATIVE ], + &ptimer->Timer + ); + _POSIX_Timer_Release( cpu, &lock_context ); _POSIX_Timer_Free( ptimer ); _Objects_Allocator_unlock(); diff --git a/cpukit/posix/src/timergetoverrun.c b/cpukit/posix/src/timergetoverrun.c index dd7669ee89..0a28fa7b5f 100644 --- a/cpukit/posix/src/timergetoverrun.c +++ b/cpukit/posix/src/timergetoverrun.c @@ -33,14 +33,17 @@ int timer_getoverrun( int overrun; POSIX_Timer_Control *ptimer; Objects_Locations location; + ISR_lock_Context lock_context; + Per_CPU_Control *cpu; - ptimer = _POSIX_Timer_Get( timerid, &location ); + ptimer = _POSIX_Timer_Get( timerid, &location, &lock_context ); switch ( location ) { case OBJECTS_LOCAL: + cpu = _POSIX_Timer_Acquire_critical( ptimer, &lock_context ); overrun = ptimer->overrun; ptimer->overrun = 0; - _Objects_Put( &ptimer->Object ); + _POSIX_Timer_Release( cpu, &lock_context ); return overrun; #if defined(RTEMS_MULTIPROCESSING) diff --git a/cpukit/posix/src/timergettime.c b/cpukit/posix/src/timergettime.c index f065cc927c..7f0015bf5e 100644 --- a/cpukit/posix/src/timergettime.c +++ b/cpukit/posix/src/timergettime.c @@ -42,31 +42,32 @@ int timer_gettime( { POSIX_Timer_Control *ptimer; Objects_Locations location; - struct timespec current_time; - Watchdog_Interval left; + ISR_lock_Context lock_context; + Per_CPU_Control *cpu; + uint64_t now; + uint32_t remaining; if ( !value ) rtems_set_errno_and_return_minus_one( EINVAL ); - /* Reads the current time */ - _TOD_Get_as_timespec( ¤t_time ); - - ptimer = _POSIX_Timer_Get( timerid, &location ); + ptimer = _POSIX_Timer_Get( timerid, &location, &lock_context ); switch ( location ) { case OBJECTS_LOCAL: - /* Calculates the time left before the timer finishes */ - - left = - (ptimer->Timer.start_time + ptimer->Timer.initial) - /* expire */ - _Watchdog_Ticks_since_boot; /* now */ + cpu = _POSIX_Timer_Acquire_critical( ptimer, &lock_context ); + now = cpu->Watchdog.ticks; - _Timespec_From_ticks( left, &value->it_value ); + if ( now < ptimer->Timer.expire ) { + remaining = (uint32_t) ( ptimer->Timer.expire - now ); + } else { + remaining = 0; + } - value->it_interval = ptimer->timer_data.it_interval; + _Timespec_From_ticks( remaining, &value->it_value ); + value->it_interval = ptimer->timer_data.it_interval; - _Objects_Put( &ptimer->Object ); + _POSIX_Timer_Release( cpu, &lock_context ); return 0; #if defined(RTEMS_MULTIPROCESSING) diff --git a/cpukit/posix/src/timerinserthelper.c b/cpukit/posix/src/timerinserthelper.c deleted file mode 100644 index b1f3373e06..0000000000 --- a/cpukit/posix/src/timerinserthelper.c +++ /dev/null @@ -1,66 +0,0 @@ -/** - * @file - * - * @brief Helper Routine for POSIX TIMERS - * @ingroup POSIXAPI - */ - -/* - * Helper routine for POSIX timers - * - * COPYRIGHT (c) 1989-2007. - * On-Line Applications Research Corporation (OAR). - * - * The license and distribution terms for this file may be - * found in the file LICENSE in this distribution or at - * http://www.rtems.org/license/LICENSE. - */ - -#if HAVE_CONFIG_H -#include "config.h" -#endif - -#include <time.h> - -#include <rtems/system.h> -#include <rtems/seterr.h> -#include <rtems/score/isr.h> -#include <rtems/score/watchdogimpl.h> -#include <rtems/posix/timerimpl.h> -#include <rtems/posix/ptimer.h> - -bool _POSIX_Timer_Insert_helper( - Watchdog_Control *timer, - Watchdog_Interval ticks, - Objects_Id id, - Watchdog_Service_routine_entry TSR, - void *arg -) -{ - ISR_lock_Context lock_context; - Watchdog_Header *header; - - _Watchdog_Remove_ticks( timer ); - - header = &_Watchdog_Ticks_header; - _Watchdog_Acquire( header, &lock_context ); - - /* - * Check to see if the watchdog has just been inserted by a - * higher priority interrupt. If so, abandon this insert. - */ - if ( timer->state != WATCHDOG_INACTIVE ) { - _Watchdog_Release( header, &lock_context ); - return false; - } - - /* - * OK. Now we now the timer was not rescheduled by an interrupt - * so we can atomically initialize it as in use. - */ - _Watchdog_Initialize( timer, TSR, id, arg ); - timer->initial = ticks; - _Watchdog_Insert_locked( header, timer, &lock_context ); - _Watchdog_Release( header, &lock_context ); - return true; -} diff --git a/cpukit/posix/src/timersettime.c b/cpukit/posix/src/timersettime.c index fe54ff95c1..ac5c258eda 100644 --- a/cpukit/posix/src/timersettime.c +++ b/cpukit/posix/src/timersettime.c @@ -29,6 +29,76 @@ #include <rtems/score/watchdogimpl.h> #include <rtems/seterr.h> +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 + ); +} + +/* + * This is the operation that is run when a timer expires + */ +void _POSIX_Timer_TSR( Watchdog_Control *the_watchdog ) +{ + POSIX_Timer_Control *ptimer; + ISR_lock_Context lock_context; + Per_CPU_Control *cpu; + + ptimer = RTEMS_CONTAINER_OF( the_watchdog, POSIX_Timer_Control, Timer ); + _ISR_lock_ISR_disable( &lock_context ); + cpu = _POSIX_Timer_Acquire_critical( ptimer, &lock_context ); + + /* Increment the number of expirations. */ + ptimer->overrun = ptimer->overrun + 1; + + /* The timer must be reprogrammed */ + if ( ( ptimer->timer_data.it_interval.tv_sec != 0 ) || + ( ptimer->timer_data.it_interval.tv_nsec != 0 ) ) { + _POSIX_Timer_Insert( ptimer, cpu, ptimer->ticks ); + } else { + /* Indicates that the timer is stopped */ + ptimer->state = POSIX_TIMER_STATE_CREATE_STOP; + } + + _POSIX_Timer_Release( cpu, &lock_context ); + + /* + * The sending of the signal to the process running the handling function + * specified for that signal is simulated + */ + + if ( pthread_kill ( ptimer->thread_id, ptimer->inf.sigev_signo ) ) { + _Assert( FALSE ); + /* + * TODO: What if an error happens at run-time? This should never + * occur because the timer should be canceled if the thread + * is deleted. This method is being invoked from the Clock + * Tick ISR so even if we decide to take action on an error, + * we don't have many options. We shouldn't shut the system down. + */ + } + + /* After the signal handler returns, the count of expirations of the + * timer must be set to 0. + */ + ptimer->overrun = 0; +} + int timer_settime( timer_t timerid, int flags, @@ -38,7 +108,8 @@ int timer_settime( { POSIX_Timer_Control *ptimer; Objects_Locations location; - bool activated; + ISR_lock_Context lock_context; + Per_CPU_Control *cpu; uint32_t initial_period; struct itimerspec normalize; @@ -77,56 +148,47 @@ int timer_settime( * or start it again */ - ptimer = _POSIX_Timer_Get( timerid, &location ); + ptimer = _POSIX_Timer_Get( timerid, &location, &lock_context ); switch ( location ) { case OBJECTS_LOCAL: + cpu = _POSIX_Timer_Acquire_critical( ptimer, &lock_context ); + + /* Stop the timer */ + _Watchdog_Remove( + &cpu->Watchdog.Header[ PER_CPU_WATCHDOG_RELATIVE ], + &ptimer->Timer + ); + /* First, it verifies if the timer must be stopped */ if ( normalize.it_value.tv_sec == 0 && normalize.it_value.tv_nsec == 0 ) { - /* Stop the timer */ - _Watchdog_Remove_ticks( &ptimer->Timer ); - /* The old data of the timer are returned */ - if ( ovalue ) - *ovalue = ptimer->timer_data; - /* The new data are set */ - ptimer->timer_data = normalize; - /* Indicates that the timer is created and stopped */ - ptimer->state = POSIX_TIMER_STATE_CREATE_STOP; - /* Returns with success */ - _Objects_Put( &ptimer->Object ); + /* The old data of the timer are returned */ + if ( ovalue ) + *ovalue = ptimer->timer_data; + /* The new data are set */ + ptimer->timer_data = normalize; + /* Indicates that the timer is created and stopped */ + ptimer->state = POSIX_TIMER_STATE_CREATE_STOP; + /* Returns with success */ + _POSIX_Timer_Release( cpu, &lock_context ); return 0; - } - - /* Convert from seconds and nanoseconds to ticks */ - ptimer->ticks = _Timespec_To_ticks( &value->it_interval ); - initial_period = _Timespec_To_ticks( &normalize.it_value ); - - - activated = _POSIX_Timer_Insert_helper( - &ptimer->Timer, - initial_period, - ptimer->Object.id, - _POSIX_Timer_TSR, - ptimer - ); - if ( !activated ) { - _Objects_Put( &ptimer->Object ); - return 0; - } - - /* - * The timer has been started and is running. So we return the - * old ones in "ovalue" - */ - if ( ovalue ) - *ovalue = ptimer->timer_data; - ptimer->timer_data = normalize; - - /* Indicate that the time is running */ - ptimer->state = POSIX_TIMER_STATE_CREATE_RUN; - _TOD_Get_as_timespec( &ptimer->time ); - _Objects_Put( &ptimer->Object ); - return 0; + } + + /* Convert from seconds and nanoseconds to ticks */ + ptimer->ticks = _Timespec_To_ticks( &value->it_interval ); + initial_period = _Timespec_To_ticks( &normalize.it_value ); + + _POSIX_Timer_Insert( ptimer, cpu, initial_period ); + + /* + * The timer has been started and is running. So we return the + * old ones in "ovalue" + */ + if ( ovalue ) + *ovalue = ptimer->timer_data; + ptimer->timer_data = normalize; + _POSIX_Timer_Release( cpu, &lock_context ); + return 0; #if defined(RTEMS_MULTIPROCESSING) case OBJECTS_REMOTE: diff --git a/cpukit/posix/src/timertsr.c b/cpukit/posix/src/timertsr.c deleted file mode 100644 index 092bf16aa3..0000000000 --- a/cpukit/posix/src/timertsr.c +++ /dev/null @@ -1,89 +0,0 @@ -/** - * @file - * - * @brief Operation that is run when a timer expires - * @ingroup POSIX_INTERNAL_TIMERS Timers - */ - -/* - * _POSIX_Timer_TSR - * - * COPYRIGHT (c) 1989-2007. - * On-Line Applications Research Corporation (OAR). - * - * The license and distribution terms for this file may be - * found in the file LICENSE in this distribution or at - * http://www.rtems.org/license/LICENSE. - */ - -#if HAVE_CONFIG_H -#include "config.h" -#endif - -#include <time.h> -#include <pthread.h> -#include <signal.h> - -#include <rtems/posix/ptimer.h> -#include <rtems/posix/timerimpl.h> -#include <rtems/score/todimpl.h> - -/* - * This is the operation that is run when a timer expires - */ -void _POSIX_Timer_TSR( - Objects_Id timer RTEMS_UNUSED, - void *data) -{ - POSIX_Timer_Control *ptimer; - bool activated; - - ptimer = (POSIX_Timer_Control *)data; - - /* Increment the number of expirations. */ - ptimer->overrun = ptimer->overrun + 1; - - /* The timer must be reprogrammed */ - if ( ( ptimer->timer_data.it_interval.tv_sec != 0 ) || - ( ptimer->timer_data.it_interval.tv_nsec != 0 ) ) { - activated = _POSIX_Timer_Insert_helper( - &ptimer->Timer, - ptimer->ticks, - ptimer->Object.id, - _POSIX_Timer_TSR, - ptimer - ); - if ( !activated ) - return; - - /* Store the time when the timer was started again */ - _TOD_Get_as_timespec( &ptimer->time ); - - /* The state really did not change but just to be safe */ - ptimer->state = POSIX_TIMER_STATE_CREATE_RUN; - } else { - /* Indicates that the timer is stopped */ - ptimer->state = POSIX_TIMER_STATE_CREATE_STOP; - } - - /* - * The sending of the signal to the process running the handling function - * specified for that signal is simulated - */ - - if ( pthread_kill ( ptimer->thread_id, ptimer->inf.sigev_signo ) ) { - _Assert( FALSE ); - /* - * TODO: What if an error happens at run-time? This should never - * occur because the timer should be canceled if the thread - * is deleted. This method is being invoked from the Clock - * Tick ISR so even if we decide to take action on an error, - * we don't have many options. We shouldn't shut the system down. - */ - } - - /* After the signal handler returns, the count of expirations of the - * timer must be set to 0. - */ - ptimer->overrun = 0; -} diff --git a/cpukit/posix/src/ualarm.c b/cpukit/posix/src/ualarm.c index 9607d3f62c..86fe1b05cc 100644 --- a/cpukit/posix/src/ualarm.c +++ b/cpukit/posix/src/ualarm.c @@ -21,39 +21,62 @@ #include <signal.h> #include <unistd.h> -#include <rtems/posix/pthreadimpl.h> -#include <rtems/posix/psignalimpl.h> -#include <rtems/score/threaddispatch.h> #include <rtems/score/todimpl.h> #include <rtems/score/watchdogimpl.h> +#include <rtems/config.h> -static void _POSIX_signals_Ualarm_TSR( Objects_Id id, void *argument ); +ISR_LOCK_DEFINE( static, _POSIX_signals_Ualarm_lock, "POSIX Ualarm" ) -static Watchdog_Control _POSIX_signals_Ualarm_timer = WATCHDOG_INITIALIZER( - _POSIX_signals_Ualarm_TSR, - 0, - NULL -); - -/* - * _POSIX_signals_Ualarm_TSR - */ +static uint32_t _POSIX_signals_Ualarm_interval; -static void _POSIX_signals_Ualarm_TSR( - Objects_Id id RTEMS_UNUSED, - void *argument RTEMS_UNUSED -) +static void _POSIX_signals_Ualarm_TSR( Watchdog_Control *the_watchdog ) { - /* - * Send a SIGALRM but if there is a problem, ignore it. - * It's OK, there isn't a way this should fail. - */ - (void) kill( getpid(), SIGALRM ); + int status; + ISR_lock_Context lock_context; + + status = kill( getpid(), SIGALRM ); + + #if defined(RTEMS_DEBUG) + /* + * There is no reason to think this might fail but we should be + * cautious. + */ + _Assert(status == 0); + #else + (void) status; + #endif + + _ISR_lock_ISR_disable_and_acquire( + &_POSIX_signals_Ualarm_lock, + &lock_context + ); /* * If the reset interval is non-zero, reschedule ourselves. */ - _Watchdog_Reset_ticks( &_POSIX_signals_Ualarm_timer ); + if ( _POSIX_signals_Ualarm_interval != 0 ) { + _Watchdog_Per_CPU_insert_relative( + the_watchdog, + _Per_CPU_Get(), + _POSIX_signals_Ualarm_interval + ); + } + + _ISR_lock_Release_and_ISR_enable( + &_POSIX_signals_Ualarm_lock, + &lock_context + ); +} + +static Watchdog_Control _POSIX_signals_Ualarm_watchdog = WATCHDOG_INITIALIZER( + _POSIX_signals_Ualarm_TSR +); + +static uint32_t _POSIX_signals_Ualarm_us_to_ticks( useconds_t us ) +{ + uint32_t us_per_tick = rtems_configuration_get_microseconds_per_tick(); + + return ( us + us_per_tick - 1 ) / us_per_tick; } useconds_t ualarm( @@ -61,51 +84,53 @@ useconds_t ualarm( useconds_t interval ) { - useconds_t remaining = 0; - Watchdog_Control *the_timer; - Watchdog_Interval ticks; - Watchdog_States state; - struct timespec tp; - - the_timer = &_POSIX_signals_Ualarm_timer; - - _Thread_Disable_dispatch(); - - state = _Watchdog_Remove_ticks( the_timer ); - if ( state == WATCHDOG_ACTIVE ) { - /* - * The stop_time and start_time fields are snapshots of ticks since - * boot. Since alarm() is dealing in seconds, we must account for - * this. - */ - - ticks = the_timer->initial; - ticks -= (the_timer->stop_time - the_timer->start_time); - /* remaining is now in ticks */ - - _Timespec_From_ticks( ticks, &tp ); - remaining = tp.tv_sec * TOD_MICROSECONDS_PER_SECOND; - remaining += tp.tv_nsec / 1000; + useconds_t 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_initial; + uint32_t ticks_interval; + + the_watchdog = &_POSIX_signals_Ualarm_watchdog; + ticks_initial = _POSIX_signals_Ualarm_us_to_ticks( useconds ); + ticks_interval = _POSIX_signals_Ualarm_us_to_ticks( interval ); + + _ISR_lock_ISR_disable_and_acquire( + &_POSIX_signals_Ualarm_lock, + &lock_context + ); + + cpu = _Watchdog_Get_CPU( the_watchdog ); + _Watchdog_Per_CPU_acquire_critical( cpu, &lock_context2 ); + now = cpu->Watchdog.ticks; + + remaining = (useconds_t) _Watchdog_Cancel( + &cpu->Watchdog.Header[ PER_CPU_WATCHDOG_RELATIVE ], + the_watchdog, + now + ); + + if ( ticks_initial != 0 ) { + _POSIX_signals_Ualarm_interval = ticks_interval; + + cpu = _Per_CPU_Get(); + _Watchdog_Set_CPU( the_watchdog, cpu ); + _Watchdog_Insert( + &cpu->Watchdog.Header[ PER_CPU_WATCHDOG_RELATIVE ], + the_watchdog, + now + ticks_initial + ); } - /* - * If useconds is non-zero, then the caller wants to schedule - * the alarm repeatedly at that interval. If the interval is - * less than a single clock tick, then fudge it to a clock tick. - */ - if ( useconds ) { - Watchdog_Interval ticks; - - tp.tv_sec = useconds / TOD_MICROSECONDS_PER_SECOND; - tp.tv_nsec = (useconds % TOD_MICROSECONDS_PER_SECOND) * 1000; - ticks = _Timespec_To_ticks( &tp ); - if ( ticks == 0 ) - ticks = 1; - - _Watchdog_Insert_ticks( the_timer, _Timespec_To_ticks( &tp ) ); - } + _Watchdog_Per_CPU_release_critical( cpu, &lock_context2 ); + _ISR_lock_Release_and_ISR_enable( + &_POSIX_signals_Ualarm_lock, + &lock_context + ); - _Thread_Enable_dispatch(); + remaining *= rtems_configuration_get_microseconds_per_tick(); return remaining; } diff --git a/cpukit/rtems/include/rtems/rtems/ratemonimpl.h b/cpukit/rtems/include/rtems/rtems/ratemonimpl.h index 490912eb21..f184c44ba9 100644 --- a/cpukit/rtems/include/rtems/rtems/ratemonimpl.h +++ b/cpukit/rtems/include/rtems/rtems/ratemonimpl.h @@ -129,19 +129,13 @@ RTEMS_INLINE_ROUTINE bool _Rate_monotonic_Is_expired ( /** * @brief Rate Monotonic Timeout * - * This routine is invoked when the period represented - * by ID expires. If the thread which owns this period is blocked - * waiting for the period to expire, then it is readied and the - * period is restarted. If the owning thread is not waiting for the - * period to expire, then the period is placed in the EXPIRED - * state and not restarted. - * - * @param[in] id is the period id - */ -void _Rate_monotonic_Timeout( - rtems_id id, - void *ignored -); + * This routine is invoked when the period represented by the watchdog expires. + * If the thread which owns this period is blocked waiting for the period to + * expire, then it is readied and the period is restarted. If the owning thread + * is not waiting for the period to expire, then the period is placed in the + * EXPIRED state and not restarted. + */ +void _Rate_monotonic_Timeout( Watchdog_Control *watchdog ); /** * @brief _Rate_monotonic_Get_status( @@ -165,7 +159,7 @@ bool _Rate_monotonic_Get_status( ); /** - * @brief Initiate Rate Monotonic Statistics + * @brief Restart Rate Monotonic Period * * This routine is invoked when a period is initiated via an explicit * call to rtems_rate_monotonic_period for the period's first iteration @@ -173,7 +167,7 @@ bool _Rate_monotonic_Get_status( * * @param[in] the_period points to the period being operated upon. */ -void _Rate_monotonic_Initiate_statistics( +void _Rate_monotonic_Restart( Rate_monotonic_Control *the_period ); diff --git a/cpukit/rtems/include/rtems/rtems/timer.h b/cpukit/rtems/include/rtems/rtems/timer.h index 7cc90511ca..032c49525a 100644 --- a/cpukit/rtems/include/rtems/rtems/timer.h +++ b/cpukit/rtems/include/rtems/rtems/timer.h @@ -31,7 +31,7 @@ * COPYRIGHT (c) 1989-2011. * On-Line Applications Research Corporation (OAR). * - * Copyright (c) 2009 embedded brains GmbH. + * Copyright (c) 2009, 2016 embedded brains GmbH. * * The license and distribution terms for this file may be * found in the file LICENSE in this distribution or at @@ -43,6 +43,7 @@ #include <rtems/rtems/attr.h> #include <rtems/rtems/status.h> +#include <rtems/rtems/tasks.h> #include <rtems/rtems/types.h> #ifdef __cplusplus @@ -63,39 +64,49 @@ extern "C" { */ /**@{*/ +#define TIMER_CLASS_BIT_TIME_OF_DAY 0x1 + +#define TIMER_CLASS_BIT_ON_TASK 0x2 + +#define TIMER_CLASS_BIT_NOT_DORMANT 0x4 + /** * The following enumerated type details the classes to which a timer * may belong. */ typedef enum { /** + * This value indicates the timer is currently not in use. + */ + TIMER_DORMANT, + + /** * This value indicates the timer is currently in use as an interval * timer which will fire in the clock tick ISR. */ - TIMER_INTERVAL, + TIMER_INTERVAL = TIMER_CLASS_BIT_NOT_DORMANT, /** * This value indicates the timer is currently in use as an interval * timer which will fire in the timer server task. */ - TIMER_INTERVAL_ON_TASK, + TIMER_INTERVAL_ON_TASK = + TIMER_CLASS_BIT_NOT_DORMANT | TIMER_CLASS_BIT_ON_TASK, /** * This value indicates the timer is currently in use as an time of day * timer which will fire in the clock tick ISR. */ - TIMER_TIME_OF_DAY, + TIMER_TIME_OF_DAY = + TIMER_CLASS_BIT_NOT_DORMANT | TIMER_CLASS_BIT_TIME_OF_DAY, /** * This value indicates the timer is currently in use as an time of day * timer which will fire in the timer server task. */ - TIMER_TIME_OF_DAY_ON_TASK, - - /** - * This value indicates the timer is currently not in use. - */ - TIMER_DORMANT + TIMER_TIME_OF_DAY_ON_TASK = + TIMER_CLASS_BIT_NOT_DORMANT | TIMER_CLASS_BIT_TIME_OF_DAY | + TIMER_CLASS_BIT_ON_TASK } Timer_Classes; /** @@ -124,6 +135,16 @@ typedef struct { Watchdog_Control Ticker; /** This field indicates what type of timer this currently is. */ Timer_Classes the_class; + /** This field is the timer service routine. */ + rtems_timer_service_routine_entry routine; + /** This field is the timer service routine user data. */ + void *user_data; + /** This field is the timer interval in ticks or seconds. */ + Watchdog_Interval initial; + /** This field is the timer start time point in ticks. */ + Watchdog_Interval start_time; + /** This field is the timer stop time point in ticks. */ + Watchdog_Interval stop_time; } Timer_Control; /** @@ -296,16 +317,22 @@ rtems_status_code rtems_timer_reset( ); /** - * @brief rtems_timer_initiate_server + * @brief Initiates the timer server. * - * This routine implements the rtems_timer_initiate_server directive. - * It creates and starts the server that executes task-based timers. + * This directive creates and starts the server for task-based timers. * It must be invoked before any task-based timers can be initiated. + * + * @param priority The timer server task priority. + * @param stack_size The stack size in bytes for the timer server task. + * @param attribute_set The timer server task attributes. + * + * @return This method returns RTEMS_SUCCESSFUL if successful and an + * error code otherwise. */ rtems_status_code rtems_timer_initiate_server( - uint32_t priority, - uint32_t stack_size, - rtems_attribute attribute_set + rtems_task_priority priority, + size_t stack_size, + rtems_attribute attribute_set ); /** diff --git a/cpukit/rtems/include/rtems/rtems/timerimpl.h b/cpukit/rtems/include/rtems/rtems/timerimpl.h index 55be6343c3..e4b4ca2ec4 100644 --- a/cpukit/rtems/include/rtems/rtems/timerimpl.h +++ b/cpukit/rtems/include/rtems/rtems/timerimpl.h @@ -10,6 +10,8 @@ * COPYRIGHT (c) 1989-2011. * On-Line Applications Research Corporation (OAR). * + * Copyright (c) 2016 embedded brains GmbH. + * * The license and distribution terms for this file may be * found in the file LICENSE in this distribution or at * http://www.rtems.org/license/LICENSE. @@ -35,81 +37,13 @@ extern "C" { * @{ */ -typedef struct Timer_server_Control Timer_server_Control; +typedef struct Timer_server_Control { + ISR_LOCK_MEMBER( Lock ) -/** - * @brief Method used for task based timers. - */ -typedef void (*Timer_server_Method)( - Timer_server_Control *timer_server, - Timer_Control *timer -); + Chain_Control Pending; -typedef struct { - /** - * @brief This watchdog that will be registered in the system tick mechanic - * for timer server wake-up. - */ - Watchdog_Control System_watchdog; - - /** - * @brief Remaining delta of the system watchdog. - */ - Watchdog_Interval system_watchdog_delta; - - /** - * @brief Unique identifier of the context which deals currently with the - * system watchdog. - */ - Thread_Control *system_watchdog_helper; - - /** - * @brief Each insert and tickle operation increases the generation count so - * that the system watchdog dealer notices updates of the watchdog chain. - */ - uint32_t generation; - - /** - * @brief Watchdog header managed by the timer server. - */ - Watchdog_Header Header; - - /** - * @brief Last time snapshot of the timer server. - * - * The units may be ticks or seconds. - */ - Watchdog_Interval last_snapshot; - - /** - * @brief Current time snapshot of the timer server. - * - * The units may be ticks or seconds. - */ - Watchdog_Interval current_snapshot; -} Timer_server_Watchdogs; - -struct Timer_server_Control { - /** - * @brief The cancel method of the timer server. - */ - Timer_server_Method cancel; - - /** - * @brief The schedule operation method of the timer server. - */ - Timer_server_Method schedule_operation; - - /** - * @brief Interval watchdogs triggered by the timer server. - */ - Timer_server_Watchdogs Interval_watchdogs; - - /** - * @brief TOD watchdogs triggered by the timer server. - */ - Timer_server_Watchdogs TOD_watchdogs; -}; + Objects_Id server_id; +} Timer_server_Control; /** * @brief Pointer to default timer server control block. @@ -148,64 +82,124 @@ RTEMS_INLINE_ROUTINE void _Timer_Free ( _Objects_Free( &_Timer_Information, &the_timer->Object ); } -/** - * @brief Timer_Get - * - * This function maps timer IDs to timer control blocks. - * If ID corresponds to a local timer, then it returns - * the timer control pointer which maps to ID and location - * is set to OBJECTS_LOCAL. Otherwise, location is set - * to OBJECTS_ERROR and the returned value is undefined. - */ -RTEMS_INLINE_ROUTINE Timer_Control *_Timer_Get ( +RTEMS_INLINE_ROUTINE Timer_Control *_Timer_Get( Objects_Id id, - Objects_Locations *location + Objects_Locations *location, + ISR_lock_Context *lock_context ) { - return (Timer_Control *) - _Objects_Get( &_Timer_Information, id, location ); + return (Timer_Control *) _Objects_Get_isr_disable( + &_Timer_Information, + id, + location, + lock_context + ); } -/** - * @brief Timer_Is_interval_class - * - * This function returns TRUE if the class is that of an INTERVAL - * timer, and FALSE otherwise. - */ -RTEMS_INLINE_ROUTINE bool _Timer_Is_interval_class ( +RTEMS_INLINE_ROUTINE Per_CPU_Control *_Timer_Acquire_critical( + Timer_Control *the_timer, + ISR_lock_Context *lock_context +) +{ + Per_CPU_Control *cpu; + + cpu = _Watchdog_Get_CPU( &the_timer->Ticker ); + _Watchdog_Per_CPU_acquire_critical( cpu, lock_context ); + + return cpu; +} + +RTEMS_INLINE_ROUTINE void _Timer_Release( + Per_CPU_Control *cpu, + ISR_lock_Context *lock_context +) +{ + _Watchdog_Per_CPU_release_critical( cpu, lock_context ); + _ISR_lock_ISR_enable( lock_context ); +} + +RTEMS_INLINE_ROUTINE bool _Timer_Is_interval_class( Timer_Classes the_class ) { - return (the_class == TIMER_INTERVAL) || (the_class == TIMER_INTERVAL_ON_TASK); + Timer_Classes mask = + TIMER_CLASS_BIT_NOT_DORMANT | TIMER_CLASS_BIT_TIME_OF_DAY; + + return ( the_class & mask ) == TIMER_CLASS_BIT_NOT_DORMANT; } -/** - * @brief Timer_Is_time_of_day_class - * - * This function returns TRUE if the class is that of an INTERVAL - * timer, and FALSE otherwise. - */ -RTEMS_INLINE_ROUTINE bool _Timer_Is_timer_of_day_class ( +RTEMS_INLINE_ROUTINE bool _Timer_Is_on_task_class( Timer_Classes the_class ) { - return ( the_class == TIMER_TIME_OF_DAY ); + Timer_Classes mask = + TIMER_CLASS_BIT_NOT_DORMANT | TIMER_CLASS_BIT_ON_TASK; + + return ( the_class & mask ) == mask; } -/** - * @brief Timer_Is_dormant_class - * - * This function returns TRUE if the class is that of a DORMANT - * timer, and FALSE otherwise. - */ -RTEMS_INLINE_ROUTINE bool _Timer_Is_dormant_class ( +RTEMS_INLINE_ROUTINE Per_CPU_Watchdog_index _Timer_Watchdog_header_index( Timer_Classes the_class ) { - return ( the_class == TIMER_DORMANT ); + return ( the_class & TIMER_CLASS_BIT_TIME_OF_DAY ); +} + +RTEMS_INLINE_ROUTINE Watchdog_Interval _Timer_Get_CPU_ticks( + const Per_CPU_Control *cpu +) +{ + return (Watchdog_Interval) cpu->Watchdog.ticks; } -void _Timer_Cancel( Timer_Control *the_timer ); +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 +); + +rtems_status_code _Timer_Fire_after( + rtems_id id, + rtems_interval ticks, + rtems_timer_service_routine_entry routine, + void *user_data, + Timer_Classes the_class, + Watchdog_Service_routine_entry adaptor +); + +rtems_status_code _Timer_Fire_when( + rtems_id id, + const rtems_time_of_day *wall_time, + rtems_timer_service_routine_entry routine, + void *user_data, + Timer_Classes the_class, + Watchdog_Service_routine_entry adaptor +); + +void _Timer_Cancel( Per_CPU_Control *cpu, Timer_Control *the_timer ); + +void _Timer_Routine_adaptor( Watchdog_Control *the_watchdog ); + +void _Timer_server_Routine_adaptor( Watchdog_Control *the_watchdog ); + +RTEMS_INLINE_ROUTINE void _Timer_server_Acquire_critical( + Timer_server_Control *timer_server, + ISR_lock_Context *lock_context +) +{ + _ISR_lock_Acquire( &timer_server->Lock, lock_context ); +} + +RTEMS_INLINE_ROUTINE void _Timer_server_Release_critical( + Timer_server_Control *timer_server, + ISR_lock_Context *lock_context +) +{ + _ISR_lock_Release( &timer_server->Lock, lock_context ); +} /**@}*/ diff --git a/cpukit/rtems/src/eventseize.c b/cpukit/rtems/src/eventseize.c index 3dc554f61b..0be6bd6f45 100644 --- a/cpukit/rtems/src/eventseize.c +++ b/cpukit/rtems/src/eventseize.c @@ -90,13 +90,12 @@ void _Event_Seize( if ( ticks ) { _Thread_Wait_set_timeout_code( executing, RTEMS_TIMEOUT ); - _Watchdog_Initialize( - &executing->Timer, + _Thread_Timer_insert_relative( + executing, + cpu_self, _Thread_Timeout, - 0, - executing + ticks ); - _Watchdog_Insert_ticks( &executing->Timer, ticks ); } _Thread_Set_state( executing, block_state ); @@ -113,7 +112,7 @@ void _Event_Seize( wait_class | THREAD_WAIT_STATE_BLOCKED ); if ( !success ) { - _Watchdog_Remove_ticks( &executing->Timer ); + _Thread_Timer_remove( executing ); _Thread_Unblock( executing ); } diff --git a/cpukit/rtems/src/eventsurrender.c b/cpukit/rtems/src/eventsurrender.c index 5726cc8d9d..7c4fe2e3f0 100644 --- a/cpukit/rtems/src/eventsurrender.c +++ b/cpukit/rtems/src/eventsurrender.c @@ -121,7 +121,7 @@ void _Event_Surrender( cpu_self = _Thread_Dispatch_disable_critical( lock_context ); _Thread_Lock_release_default( the_thread, lock_context ); - _Watchdog_Remove_ticks( &the_thread->Timer ); + _Thread_Timer_remove( the_thread ); _Thread_Unblock( the_thread ); _Thread_Dispatch_enable( cpu_self ); diff --git a/cpukit/rtems/src/ratemoncancel.c b/cpukit/rtems/src/ratemoncancel.c index 67b230fbfc..2e4d5322db 100644 --- a/cpukit/rtems/src/ratemoncancel.c +++ b/cpukit/rtems/src/ratemoncancel.c @@ -29,6 +29,7 @@ rtems_status_code rtems_rate_monotonic_cancel( { Rate_monotonic_Control *the_period; Objects_Locations location; + ISR_Level level; the_period = _Rate_monotonic_Get( id, &location ); switch ( location ) { @@ -38,7 +39,9 @@ rtems_status_code rtems_rate_monotonic_cancel( _Objects_Put( &the_period->Object ); return RTEMS_NOT_OWNER_OF_RESOURCE; } - _Watchdog_Remove_ticks( &the_period->Timer ); + _ISR_Disable( level ); + _Watchdog_Per_CPU_remove_relative( &the_period->Timer ); + _ISR_Enable( level ); the_period->state = RATE_MONOTONIC_INACTIVE; _Scheduler_Release_job( the_period->owner, 0 ); _Objects_Put( &the_period->Object ); diff --git a/cpukit/rtems/src/ratemoncreate.c b/cpukit/rtems/src/ratemoncreate.c index 1ac4a36b6e..1a5c9b2615 100644 --- a/cpukit/rtems/src/ratemoncreate.c +++ b/cpukit/rtems/src/ratemoncreate.c @@ -65,7 +65,8 @@ rtems_status_code rtems_rate_monotonic_create( the_period->owner = _Thread_Get_executing(); the_period->state = RATE_MONOTONIC_INACTIVE; - _Watchdog_Preinitialize( &the_period->Timer ); + _Watchdog_Preinitialize( &the_period->Timer, _Per_CPU_Get_by_index( 0 ) ); + _Watchdog_Initialize( &the_period->Timer, _Rate_monotonic_Timeout ); _Rate_monotonic_Reset_statistics( the_period ); diff --git a/cpukit/rtems/src/ratemondelete.c b/cpukit/rtems/src/ratemondelete.c index 77cf3fe306..09b9ab6712 100644 --- a/cpukit/rtems/src/ratemondelete.c +++ b/cpukit/rtems/src/ratemondelete.c @@ -29,6 +29,7 @@ rtems_status_code rtems_rate_monotonic_delete( { Rate_monotonic_Control *the_period; Objects_Locations location; + ISR_Level level; _Objects_Allocator_lock(); the_period = _Rate_monotonic_Get( id, &location ); @@ -37,7 +38,9 @@ rtems_status_code rtems_rate_monotonic_delete( case OBJECTS_LOCAL: _Scheduler_Release_job( the_period->owner, 0 ); _Objects_Close( &_Rate_monotonic_Information, &the_period->Object ); - _Watchdog_Remove_ticks( &the_period->Timer ); + _ISR_Disable( level ); + _Watchdog_Per_CPU_remove_relative( &the_period->Timer ); + _ISR_Enable( level ); the_period->state = RATE_MONOTONIC_INACTIVE; _Objects_Put( &the_period->Object ); _Rate_monotonic_Free( the_period ); diff --git a/cpukit/rtems/src/ratemonperiod.c b/cpukit/rtems/src/ratemonperiod.c index 6afe1016bf..58be148f19 100644 --- a/cpukit/rtems/src/ratemonperiod.c +++ b/cpukit/rtems/src/ratemonperiod.c @@ -77,12 +77,11 @@ bool _Rate_monotonic_Get_status( return true; } -void _Rate_monotonic_Initiate_statistics( - Rate_monotonic_Control *the_period -) +void _Rate_monotonic_Restart( Rate_monotonic_Control *the_period ) { Thread_Control *owning_thread = the_period->owner; Timestamp_Control uptime; + ISR_Level level; _TOD_Get_uptime( &uptime ); @@ -113,7 +112,15 @@ void _Rate_monotonic_Initiate_statistics( _Timestamp_Add_to( &the_period->cpu_usage_period_initiated, &ran ); } - _Scheduler_Release_job( the_period->owner, the_period->next_length ); + _Scheduler_Release_job( owning_thread, the_period->next_length ); + + _ISR_Disable( level ); + _Watchdog_Per_CPU_insert_relative( + &the_period->Timer, + _Per_CPU_Get(), + the_period->next_length + ); + _ISR_Enable( level ); } static void _Rate_monotonic_Update_statistics( @@ -238,22 +245,9 @@ rtems_status_code rtems_rate_monotonic_period( 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 ); + the_period->next_length = length; + _Rate_monotonic_Restart( the_period ); _Objects_Put( &the_period->Object ); return RTEMS_SUCCESSFUL; } @@ -308,7 +302,11 @@ rtems_status_code rtems_rate_monotonic_period( the_period->state = RATE_MONOTONIC_ACTIVE; the_period->next_length = length; - _Watchdog_Insert_ticks( &the_period->Timer, length ); + _Watchdog_Per_CPU_insert_relative( + &the_period->Timer, + _Per_CPU_Get(), + length + ); _Scheduler_Release_job( the_period->owner, the_period->next_length ); _Objects_Put( &the_period->Object ); return RTEMS_TIMEOUT; diff --git a/cpukit/rtems/src/ratemontimeout.c b/cpukit/rtems/src/ratemontimeout.c index 08f9bd17d7..7c25595a16 100644 --- a/cpukit/rtems/src/ratemontimeout.c +++ b/cpukit/rtems/src/ratemontimeout.c @@ -22,46 +22,30 @@ #include <rtems/score/threadimpl.h> #include <rtems/score/watchdogimpl.h> -void _Rate_monotonic_Timeout( - Objects_Id id, - void *ignored -) +void _Rate_monotonic_Timeout( Watchdog_Control *watchdog ) { Rate_monotonic_Control *the_period; - Objects_Locations location; Thread_Control *the_thread; /* * When we get here, the Timer is already off the chain so we do not * have to worry about that -- hence no _Watchdog_Remove(). */ - the_period = _Rate_monotonic_Get( id, &location ); - switch ( location ) { - - case OBJECTS_LOCAL: - the_thread = the_period->owner; - if ( _States_Is_waiting_for_period( the_thread->current_state ) && - the_thread->Wait.id == the_period->Object.id ) { - _Thread_Unblock( the_thread ); - - _Rate_monotonic_Initiate_statistics( the_period ); - - _Watchdog_Insert_ticks( &the_period->Timer, the_period->next_length ); - } else if ( the_period->state == RATE_MONOTONIC_OWNER_IS_BLOCKING ) { - the_period->state = RATE_MONOTONIC_EXPIRED_WHILE_BLOCKING; - - _Rate_monotonic_Initiate_statistics( the_period ); - - _Watchdog_Insert_ticks( &the_period->Timer, the_period->next_length ); - } else - the_period->state = RATE_MONOTONIC_EXPIRED; - _Objects_Put_without_thread_dispatch( &the_period->Object ); - break; - -#if defined(RTEMS_MULTIPROCESSING) - case OBJECTS_REMOTE: /* impossible */ -#endif - case OBJECTS_ERROR: - break; + the_period = RTEMS_CONTAINER_OF( watchdog, Rate_monotonic_Control, Timer ); + the_thread = the_period->owner; + + _Thread_Disable_dispatch(); + + if ( _States_Is_waiting_for_period( the_thread->current_state ) && + the_thread->Wait.id == the_period->Object.id ) { + _Thread_Unblock( the_thread ); + _Rate_monotonic_Restart( the_period ); + } else if ( the_period->state == RATE_MONOTONIC_OWNER_IS_BLOCKING ) { + the_period->state = RATE_MONOTONIC_EXPIRED_WHILE_BLOCKING; + _Rate_monotonic_Restart( the_period ); + } else { + the_period->state = RATE_MONOTONIC_EXPIRED; } + + _Thread_Unnest_dispatch(); } diff --git a/cpukit/rtems/src/taskwakeafter.c b/cpukit/rtems/src/taskwakeafter.c index b7f328f5bc..fa5f6f4eed 100644 --- a/cpukit/rtems/src/taskwakeafter.c +++ b/cpukit/rtems/src/taskwakeafter.c @@ -41,13 +41,12 @@ rtems_status_code rtems_task_wake_after( } else { _Thread_Set_state( executing, STATES_DELAYING ); _Thread_Wait_flags_set( executing, THREAD_WAIT_STATE_BLOCKED ); - _Watchdog_Initialize( - &executing->Timer, + _Thread_Timer_insert_relative( + executing, + cpu_self, _Thread_Timeout, - 0, - executing + ticks ); - _Watchdog_Insert_ticks( &executing->Timer, ticks ); } _Thread_Dispatch_enable( cpu_self ); return RTEMS_SUCCESSFUL; diff --git a/cpukit/rtems/src/taskwakewhen.c b/cpukit/rtems/src/taskwakewhen.c index cf0b303cd3..5d6d45afcf 100644 --- a/cpukit/rtems/src/taskwakewhen.c +++ b/cpukit/rtems/src/taskwakewhen.c @@ -28,9 +28,9 @@ rtems_status_code rtems_task_wake_when( rtems_time_of_day *time_buffer ) { - Watchdog_Interval seconds; - Thread_Control *executing; - Per_CPU_Control *cpu_self; + uint32_t seconds; + Thread_Control *executing; + Per_CPU_Control *cpu_self; if ( !_TOD_Is_set() ) return RTEMS_NOT_DEFINED; @@ -52,15 +52,11 @@ rtems_status_code rtems_task_wake_when( executing = _Thread_Executing; _Thread_Set_state( executing, STATES_WAITING_FOR_TIME ); _Thread_Wait_flags_set( executing, THREAD_WAIT_STATE_BLOCKED ); - _Watchdog_Initialize( - &executing->Timer, + _Thread_Timer_insert_absolute( + executing, + cpu_self, _Thread_Timeout, - 0, - executing - ); - _Watchdog_Insert_seconds( - &executing->Timer, - seconds - _TOD_Seconds_since_epoch() + _Watchdog_Ticks_from_seconds( seconds ) ); _Thread_Dispatch_enable( cpu_self ); return RTEMS_SUCCESSFUL; diff --git a/cpukit/rtems/src/timercancel.c b/cpukit/rtems/src/timercancel.c index 1e737a25bb..5d4343e776 100644 --- a/cpukit/rtems/src/timercancel.c +++ b/cpukit/rtems/src/timercancel.c @@ -14,39 +14,24 @@ #include "config.h" #endif -#include <rtems/system.h> -#include <rtems/rtems/status.h> -#include <rtems/rtems/support.h> -#include <rtems/score/thread.h> #include <rtems/rtems/timerimpl.h> -#include <rtems/score/watchdogimpl.h> - -/* - * rtems_timer_cancel - * - * This directive allows a thread to cancel a timer. - * - * Input parameters: - * id - timer id - * - * Output parameters: - * RTEMS_SUCCESSFUL - if successful - * error code - if unsuccessful - */ rtems_status_code rtems_timer_cancel( rtems_id id ) { - Timer_Control *the_timer; - Objects_Locations location; + Timer_Control *the_timer; + Objects_Locations location; + ISR_lock_Context lock_context; + Per_CPU_Control *cpu; - the_timer = _Timer_Get( id, &location ); + the_timer = _Timer_Get( id, &location, &lock_context ); switch ( location ) { case OBJECTS_LOCAL: - _Timer_Cancel( the_timer ); - _Objects_Put( &the_timer->Object ); + cpu = _Timer_Acquire_critical( the_timer, &lock_context ); + _Timer_Cancel( cpu, the_timer ); + _Timer_Release( cpu, &lock_context ); return RTEMS_SUCCESSFUL; #if defined(RTEMS_MULTIPROCESSING) diff --git a/cpukit/rtems/src/timercreate.c b/cpukit/rtems/src/timercreate.c index 5c718b94c9..80c1356278 100644 --- a/cpukit/rtems/src/timercreate.c +++ b/cpukit/rtems/src/timercreate.c @@ -18,40 +18,173 @@ #include "config.h" #endif -#include <rtems/system.h> +#include <rtems/rtems/timerimpl.h> +#include <rtems/rtems/clock.h> #include <rtems/rtems/status.h> #include <rtems/rtems/support.h> #include <rtems/score/assert.h> +#include <rtems/score/chainimpl.h> #include <rtems/score/thread.h> -#include <rtems/rtems/timerimpl.h> +#include <rtems/score/todimpl.h> #include <rtems/score/watchdogimpl.h> -void _Timer_Cancel( Timer_Control *the_timer ) +RTEMS_STATIC_ASSERT( + PER_CPU_WATCHDOG_ABSOLUTE == TIMER_CLASS_BIT_TIME_OF_DAY, + TIMER_CLASS_BIT_TIME_OF_DAY +); + +void _Timer_Routine_adaptor( Watchdog_Control *the_watchdog ) { - Timer_server_Control *timer_server; - ISR_Level level; + Timer_Control *the_timer; + Per_CPU_Control *cpu; - /* The timer class must not change during the cancel operation */ - _ISR_Disable( level ); + the_timer = RTEMS_CONTAINER_OF( the_watchdog, Timer_Control, Ticker ); + cpu = _Watchdog_Get_CPU( &the_timer->Ticker ); + the_timer->stop_time = _Timer_Get_CPU_ticks( cpu ); - switch ( the_timer->the_class ) { - case TIMER_INTERVAL: - _Watchdog_Remove_ticks( &the_timer->Ticker ); - break; - case TIMER_TIME_OF_DAY: - _Watchdog_Remove_seconds( &the_timer->Ticker ); - break; - case TIMER_INTERVAL_ON_TASK: - case TIMER_TIME_OF_DAY_ON_TASK: - timer_server = _Timer_server; - (*timer_server->cancel)( timer_server, the_timer ); - break; - default: - _Assert( the_timer->the_class == TIMER_DORMANT ); + ( *the_timer->routine )( the_timer->Object.id, the_timer->user_data ); +} + +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; + Objects_Locations location; + ISR_lock_Context lock_context; + Per_CPU_Control *cpu; + + the_timer = _Timer_Get( id, &location, &lock_context ); + switch ( location ) { + + case OBJECTS_LOCAL: + 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_RELATIVE ], + &the_timer->Ticker, + cpu->Watchdog.ticks + interval + ); + } else { + _Watchdog_Insert( + &cpu->Watchdog.Header[ PER_CPU_WATCHDOG_ABSOLUTE ], + &the_timer->Ticker, + _Watchdog_Ticks_from_seconds( interval ) + ); + } + + _Timer_Release( cpu, &lock_context ); + return RTEMS_SUCCESSFUL; + +#if defined(RTEMS_MULTIPROCESSING) + case OBJECTS_REMOTE: /* should never return this */ +#endif + case OBJECTS_ERROR: break; } - _ISR_Enable( level ); + return RTEMS_INVALID_ID; +} + +rtems_status_code _Timer_Fire_after( + rtems_id id, + rtems_interval ticks, + rtems_timer_service_routine_entry routine, + void *user_data, + Timer_Classes the_class, + Watchdog_Service_routine_entry adaptor +) +{ + if ( ticks == 0 ) + return RTEMS_INVALID_NUMBER; + + if ( !routine ) + return RTEMS_INVALID_ADDRESS; + + return _Timer_Fire( + id, + ticks, + routine, + user_data, + the_class, + adaptor + ); +} + +rtems_status_code _Timer_Fire_when( + rtems_id id, + const rtems_time_of_day *wall_time, + rtems_timer_service_routine_entry routine, + void *user_data, + Timer_Classes the_class, + Watchdog_Service_routine_entry adaptor +) +{ + rtems_interval seconds; + + if ( !_TOD_Is_set() ) + return RTEMS_NOT_DEFINED; + + if ( !routine ) + return RTEMS_INVALID_ADDRESS; + + if ( !_TOD_Validate( wall_time ) ) + return RTEMS_INVALID_CLOCK; + + seconds = _TOD_To_seconds( wall_time ); + if ( seconds <= _TOD_Seconds_since_epoch() ) + return RTEMS_INVALID_CLOCK; + + return _Timer_Fire( + id, + seconds, + routine, + user_data, + the_class, + adaptor + ); +} + +void _Timer_Cancel( Per_CPU_Control *cpu, Timer_Control *the_timer ) +{ + Timer_Classes the_class; + + the_class = the_timer->the_class; + + if ( _Watchdog_Is_scheduled( &the_timer->Ticker ) ) { + the_timer->stop_time = _Timer_Get_CPU_ticks( cpu ); + _Watchdog_Remove( + &cpu->Watchdog.Header[ _Timer_Watchdog_header_index( the_class ) ], + &the_timer->Ticker + ); + } else if ( _Timer_Is_on_task_class( the_class ) ) { + Timer_server_Control *timer_server; + ISR_lock_Context lock_context; + + timer_server = _Timer_server; + _Assert( timer_server != NULL ); + _Timer_server_Acquire_critical( timer_server, &lock_context ); + + if ( _Watchdog_Get_state( &the_timer->Ticker ) == WATCHDOG_PENDING ) { + _Watchdog_Set_state( &the_timer->Ticker, WATCHDOG_INACTIVE ); + _Chain_Extract_unprotected( &the_timer->Ticker.Node.Chain ); + } + + _Timer_server_Release_critical( timer_server, &lock_context ); + } } rtems_status_code rtems_timer_create( @@ -75,7 +208,7 @@ rtems_status_code rtems_timer_create( } the_timer->the_class = TIMER_DORMANT; - _Watchdog_Preinitialize( &the_timer->Ticker ); + _Watchdog_Preinitialize( &the_timer->Ticker, _Per_CPU_Get_snapshot() ); _Objects_Open( &_Timer_Information, diff --git a/cpukit/rtems/src/timerdelete.c b/cpukit/rtems/src/timerdelete.c index 0849ec5ba6..9c413976c4 100644 --- a/cpukit/rtems/src/timerdelete.c +++ b/cpukit/rtems/src/timerdelete.c @@ -18,12 +18,7 @@ #include "config.h" #endif -#include <rtems/system.h> -#include <rtems/rtems/status.h> -#include <rtems/rtems/support.h> -#include <rtems/score/thread.h> #include <rtems/rtems/timerimpl.h> -#include <rtems/score/watchdogimpl.h> rtems_status_code rtems_timer_delete( rtems_id id @@ -31,15 +26,18 @@ rtems_status_code rtems_timer_delete( { Timer_Control *the_timer; Objects_Locations location; + ISR_lock_Context lock_context; + Per_CPU_Control *cpu; _Objects_Allocator_lock(); - the_timer = _Timer_Get( id, &location ); + the_timer = _Timer_Get( id, &location, &lock_context ); switch ( location ) { case OBJECTS_LOCAL: _Objects_Close( &_Timer_Information, &the_timer->Object ); - _Timer_Cancel( the_timer ); - _Objects_Put( &the_timer->Object ); + cpu = _Timer_Acquire_critical( the_timer, &lock_context ); + _Timer_Cancel( cpu, the_timer ); + _Timer_Release( cpu, &lock_context ); _Timer_Free( the_timer ); _Objects_Allocator_unlock(); return RTEMS_SUCCESSFUL; diff --git a/cpukit/rtems/src/timerfireafter.c b/cpukit/rtems/src/timerfireafter.c index 84cf46bc37..82bd878cec 100644 --- a/cpukit/rtems/src/timerfireafter.c +++ b/cpukit/rtems/src/timerfireafter.c @@ -18,12 +18,7 @@ #include "config.h" #endif -#include <rtems/system.h> -#include <rtems/rtems/status.h> -#include <rtems/rtems/support.h> -#include <rtems/score/thread.h> #include <rtems/rtems/timerimpl.h> -#include <rtems/score/watchdogimpl.h> rtems_status_code rtems_timer_fire_after( rtems_id id, @@ -32,55 +27,12 @@ rtems_status_code rtems_timer_fire_after( void *user_data ) { - Timer_Control *the_timer; - Objects_Locations location; - ISR_Level level; - - if ( ticks == 0 ) - return RTEMS_INVALID_NUMBER; - - if ( !routine ) - return RTEMS_INVALID_ADDRESS; - - the_timer = _Timer_Get( id, &location ); - switch ( location ) { - - case OBJECTS_LOCAL: - _Timer_Cancel( the_timer ); - - _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 ); - _Objects_Put( &the_timer->Object ); - 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; - _Watchdog_Initialize( &the_timer->Ticker, routine, id, user_data ); - _ISR_Enable( level ); - - - _Watchdog_Insert_ticks( &the_timer->Ticker, ticks ); - _Objects_Put( &the_timer->Object ); - return RTEMS_SUCCESSFUL; - -#if defined(RTEMS_MULTIPROCESSING) - case OBJECTS_REMOTE: /* should never return this */ -#endif - case OBJECTS_ERROR: - break; - } - - return RTEMS_INVALID_ID; + return _Timer_Fire_after( + id, + ticks, + routine, + user_data, + TIMER_INTERVAL, + _Timer_Routine_adaptor + ); } diff --git a/cpukit/rtems/src/timerfirewhen.c b/cpukit/rtems/src/timerfirewhen.c index 1acbaf9b8f..eddeb16c4f 100644 --- a/cpukit/rtems/src/timerfirewhen.c +++ b/cpukit/rtems/src/timerfirewhen.c @@ -19,9 +19,6 @@ #endif #include <rtems/rtems/timerimpl.h> -#include <rtems/rtems/clock.h> -#include <rtems/score/todimpl.h> -#include <rtems/score/watchdogimpl.h> rtems_status_code rtems_timer_fire_when( rtems_id id, @@ -30,43 +27,12 @@ rtems_status_code rtems_timer_fire_when( void *user_data ) { - Timer_Control *the_timer; - Objects_Locations location; - rtems_interval seconds; - - if ( !_TOD_Is_set() ) - return RTEMS_NOT_DEFINED; - - if ( !_TOD_Validate( wall_time ) ) - return RTEMS_INVALID_CLOCK; - - if ( !routine ) - return RTEMS_INVALID_ADDRESS; - - seconds = _TOD_To_seconds( wall_time ); - if ( seconds <= _TOD_Seconds_since_epoch() ) - return RTEMS_INVALID_CLOCK; - - the_timer = _Timer_Get( id, &location ); - switch ( location ) { - - case OBJECTS_LOCAL: - _Timer_Cancel( the_timer ); - the_timer->the_class = TIMER_TIME_OF_DAY; - _Watchdog_Initialize( &the_timer->Ticker, routine, id, user_data ); - _Watchdog_Insert_seconds( - &the_timer->Ticker, - seconds - _TOD_Seconds_since_epoch() - ); - _Objects_Put( &the_timer->Object ); - return RTEMS_SUCCESSFUL; - -#if defined(RTEMS_MULTIPROCESSING) - case OBJECTS_REMOTE: /* should never return this */ -#endif - case OBJECTS_ERROR: - break; - } - - return RTEMS_INVALID_ID; + return _Timer_Fire_when( + id, + wall_time, + routine, + user_data, + TIMER_TIME_OF_DAY, + _Timer_Routine_adaptor + ); } diff --git a/cpukit/rtems/src/timergetinfo.c b/cpukit/rtems/src/timergetinfo.c index 17c32e6cf4..a11861c63e 100644 --- a/cpukit/rtems/src/timergetinfo.c +++ b/cpukit/rtems/src/timergetinfo.c @@ -32,19 +32,22 @@ rtems_status_code rtems_timer_get_information( { Timer_Control *the_timer; Objects_Locations location; + ISR_lock_Context lock_context; + Per_CPU_Control *cpu; if ( !the_info ) return RTEMS_INVALID_ADDRESS; - the_timer = _Timer_Get( id, &location ); + the_timer = _Timer_Get( id, &location, &lock_context ); switch ( location ) { case OBJECTS_LOCAL: + cpu = _Timer_Acquire_critical( the_timer, &lock_context ); the_info->the_class = the_timer->the_class; - the_info->initial = the_timer->Ticker.initial; - the_info->start_time = the_timer->Ticker.start_time; - the_info->stop_time = the_timer->Ticker.stop_time; - _Objects_Put( &the_timer->Object ); + the_info->initial = the_timer->initial; + the_info->start_time = the_timer->start_time; + the_info->stop_time = the_timer->stop_time; + _Timer_Release( cpu, &lock_context ); return RTEMS_SUCCESSFUL; #if defined(RTEMS_MULTIPROCESSING) diff --git a/cpukit/rtems/src/timerreset.c b/cpukit/rtems/src/timerreset.c index 7ab172ea4f..72c912baa3 100644 --- a/cpukit/rtems/src/timerreset.c +++ b/cpukit/rtems/src/timerreset.c @@ -44,40 +44,29 @@ rtems_status_code rtems_timer_reset( { Timer_Control *the_timer; Objects_Locations location; - rtems_status_code status = RTEMS_SUCCESSFUL; + ISR_lock_Context lock_context; + Per_CPU_Control *cpu; + rtems_status_code status; - the_timer = _Timer_Get( id, &location ); + the_timer = _Timer_Get( id, &location, &lock_context ); switch ( location ) { case OBJECTS_LOCAL: - if ( the_timer->the_class == TIMER_INTERVAL ) { - _Watchdog_Reset_ticks( &the_timer->Ticker ); - } else if ( the_timer->the_class == TIMER_INTERVAL_ON_TASK ) { - Timer_server_Control *timer_server = _Timer_server; + cpu = _Timer_Acquire_critical( the_timer, &lock_context ); - /* - * 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 ) { - _Objects_Put( &the_timer->Object ); - return RTEMS_INCORRECT_STATE; - } - #endif - (*timer_server->cancel)( timer_server, the_timer ); - (*timer_server->schedule_operation)( timer_server, the_timer ); + if ( _Timer_Is_interval_class( the_timer->the_class ) ) { + _Timer_Cancel( cpu, the_timer ); + _Watchdog_Insert( + &cpu->Watchdog.Header[ PER_CPU_WATCHDOG_RELATIVE ], + &the_timer->Ticker, + cpu->Watchdog.ticks + the_timer->initial + ); + status = RTEMS_SUCCESSFUL; } 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; } - _Objects_Put( &the_timer->Object ); + + _Timer_Release( cpu, &lock_context ); return status; #if defined(RTEMS_MULTIPROCESSING) diff --git a/cpukit/rtems/src/timerserver.c b/cpukit/rtems/src/timerserver.c index 7d757809b8..cf06319434 100644 --- a/cpukit/rtems/src/timerserver.c +++ b/cpukit/rtems/src/timerserver.c @@ -15,7 +15,7 @@ /* COPYRIGHT (c) 1989-2008. * On-Line Applications Research Corporation (OAR). * - * Copyright (c) 2009-2015 embedded brains GmbH. + * Copyright (c) 2009, 2016 embedded brains GmbH. * * The license and distribution terms for this file may be * found in the file LICENSE in this distribution or at @@ -34,193 +34,48 @@ static Timer_server_Control _Timer_server_Default; -static void _Timer_server_Cancel_method( +static void _Timer_server_Acquire( Timer_server_Control *ts, - Timer_Control *timer + ISR_lock_Context *lock_context ) { - if ( timer->the_class == TIMER_INTERVAL_ON_TASK ) { - _Watchdog_Remove( &ts->Interval_watchdogs.Header, &timer->Ticker ); - } else if ( timer->the_class == TIMER_TIME_OF_DAY_ON_TASK ) { - _Watchdog_Remove( &ts->TOD_watchdogs.Header, &timer->Ticker ); - } -} - -static Watchdog_Interval _Timer_server_Get_ticks( void ) -{ - return _Watchdog_Ticks_since_boot; + _ISR_lock_ISR_disable_and_acquire( &ts->Lock, lock_context ); } -static Watchdog_Interval _Timer_server_Get_seconds( void ) -{ - return _TOD_Seconds_since_epoch(); -} - -static void _Timer_server_Update_system_watchdog( - Timer_server_Watchdogs *watchdogs, - Watchdog_Header *system_header -) -{ - ISR_lock_Context lock_context; - - _Watchdog_Acquire( &watchdogs->Header, &lock_context ); - - if ( watchdogs->system_watchdog_helper == NULL ) { - Thread_Control *executing; - uint32_t my_generation; - - executing = _Thread_Executing; - watchdogs->system_watchdog_helper = executing; - - do { - my_generation = watchdogs->generation; - - if ( !_Watchdog_Is_empty( &watchdogs->Header ) ) { - Watchdog_Control *first; - Watchdog_Interval delta; - - first = _Watchdog_First( &watchdogs->Header ); - delta = first->delta_interval; - - if ( - watchdogs->System_watchdog.state == WATCHDOG_INACTIVE - || delta != watchdogs->system_watchdog_delta - ) { - watchdogs->system_watchdog_delta = delta; - _Watchdog_Release( &watchdogs->Header, &lock_context ); - - _Watchdog_Remove( system_header, &watchdogs->System_watchdog ); - watchdogs->System_watchdog.initial = delta; - _Watchdog_Insert( system_header, &watchdogs->System_watchdog ); - - _Watchdog_Acquire( &watchdogs->Header, &lock_context ); - } - } - } while ( watchdogs->generation != my_generation ); - - watchdogs->system_watchdog_helper = NULL; - } - - _Watchdog_Release( &watchdogs->Header, &lock_context ); -} - -static void _Timer_server_Insert_timer( - Timer_server_Watchdogs *watchdogs, - Timer_Control *timer, - Watchdog_Header *system_header, - Watchdog_Interval (*get_ticks)( void ) -) -{ - ISR_lock_Context lock_context; - Watchdog_Interval now; - Watchdog_Interval delta; - - _Watchdog_Acquire( &watchdogs->Header, &lock_context ); - - now = (*get_ticks)(); - delta = now - watchdogs->last_snapshot; - watchdogs->last_snapshot = now; - watchdogs->current_snapshot = now; - - if ( watchdogs->system_watchdog_delta > delta ) { - watchdogs->system_watchdog_delta -= delta; - } else { - watchdogs->system_watchdog_delta = 0; - } - - if ( !_Watchdog_Is_empty( &watchdogs->Header ) ) { - Watchdog_Control *first = _Watchdog_First( &watchdogs->Header ); - - if ( first->delta_interval > delta ) { - first->delta_interval -= delta; - } else { - first->delta_interval = 0; - } - } - - _Watchdog_Insert_locked( - &watchdogs->Header, - &timer->Ticker, - &lock_context - ); - - ++watchdogs->generation; - - _Watchdog_Release( &watchdogs->Header, &lock_context ); - - _Timer_server_Update_system_watchdog( watchdogs, system_header ); -} - -static void _Timer_server_Schedule_operation_method( +static void _Timer_server_Release( Timer_server_Control *ts, - Timer_Control *timer + ISR_lock_Context *lock_context ) { - if ( timer->the_class == TIMER_INTERVAL_ON_TASK ) { - _Timer_server_Insert_timer( - &ts->Interval_watchdogs, - timer, - &_Watchdog_Ticks_header, - _Timer_server_Get_ticks - ); - } else if ( timer->the_class == TIMER_TIME_OF_DAY_ON_TASK ) { - _Timer_server_Insert_timer( - &ts->TOD_watchdogs, - timer, - &_Watchdog_Seconds_header, - _Timer_server_Get_seconds - ); - } + _ISR_lock_Release_and_ISR_enable( &ts->Lock, lock_context ); } -static void _Timer_server_Update_current_snapshot( - Timer_server_Watchdogs *watchdogs, - Watchdog_Interval (*get_ticks)( void ) -) +void _Timer_server_Routine_adaptor( Watchdog_Control *the_watchdog ) { - ISR_lock_Context lock_context; + Timer_Control *the_timer; + ISR_lock_Context lock_context; + Per_CPU_Control *cpu; + Timer_server_Control *ts; + bool wakeup; - _Watchdog_Acquire( &watchdogs->Header, &lock_context ); - watchdogs->current_snapshot = (*get_ticks)(); - watchdogs->system_watchdog_delta = 0; - _Watchdog_Release( &watchdogs->Header, &lock_context ); -} + ts = _Timer_server; + _Assert( ts != NULL ); + the_timer = RTEMS_CONTAINER_OF( the_watchdog, Timer_Control, Ticker ); -static void _Timer_server_Tickle( - Timer_server_Watchdogs *watchdogs, - Watchdog_Header *system_header, - Watchdog_Interval (*get_ticks)( void ), - bool ticks -) -{ - ISR_lock_Context lock_context; - Watchdog_Interval now; - Watchdog_Interval last; + _Timer_server_Acquire( ts, &lock_context ); - _Watchdog_Acquire( &watchdogs->Header, &lock_context ); + _Assert( _Watchdog_Get_state( &the_timer->Ticker ) == WATCHDOG_INACTIVE ); + _Watchdog_Set_state( &the_timer->Ticker, WATCHDOG_PENDING ); + cpu = _Watchdog_Get_CPU( &the_timer->Ticker ); + the_timer->stop_time = _Timer_Get_CPU_ticks( cpu ); + wakeup = _Chain_Is_empty( &ts->Pending ); + _Chain_Append_unprotected( &ts->Pending, &the_timer->Ticker.Node.Chain ); - now = watchdogs->current_snapshot; - last = watchdogs->last_snapshot; - watchdogs->last_snapshot = now; + _Timer_server_Release( ts, &lock_context ); - if ( ticks || now >= last ) { - _Watchdog_Adjust_forward_locked( - &watchdogs->Header, - now - last, - &lock_context - ); - } else { - _Watchdog_Adjust_backward_locked( - &watchdogs->Header, - last - now - ); + if ( wakeup ) { + (void) rtems_event_system_send( ts->server_id, RTEMS_EVENT_SYSTEM_SERVER ); } - - ++watchdogs->generation; - - _Watchdog_Release( &watchdogs->Header, &lock_context ); - - _Timer_server_Update_system_watchdog( watchdogs, system_header ); } /** @@ -239,21 +94,38 @@ static rtems_task _Timer_server_Body( Timer_server_Control *ts = (Timer_server_Control *) arg; while ( true ) { - rtems_event_set events; + ISR_lock_Context lock_context; + rtems_event_set events; - _Timer_server_Tickle( - &ts->Interval_watchdogs, - &_Watchdog_Ticks_header, - _Timer_server_Get_ticks, - true - ); + _Timer_server_Acquire( ts, &lock_context ); - _Timer_server_Tickle( - &ts->TOD_watchdogs, - &_Watchdog_Seconds_header, - _Timer_server_Get_seconds, - false - ); + while ( true ) { + Watchdog_Control *the_watchdog; + Timer_Control *the_timer; + rtems_timer_service_routine_entry routine; + Objects_Id id; + void *user_data; + + the_watchdog = (Watchdog_Control *) _Chain_Get_unprotected( &ts->Pending ); + if ( the_watchdog == NULL ) { + break; + } + + _Assert( _Watchdog_Get_state( the_watchdog ) == WATCHDOG_PENDING ); + _Watchdog_Set_state( the_watchdog, WATCHDOG_INACTIVE ); + the_timer = RTEMS_CONTAINER_OF( the_watchdog, Timer_Control, Ticker ); + routine = the_timer->routine; + id = the_timer->Object.id; + user_data = the_timer->user_data; + + _Timer_server_Release( ts, &lock_context ); + + ( *routine )( id, user_data ); + + _Timer_server_Acquire( ts, &lock_context ); + } + + _Timer_server_Release( ts, &lock_context ); (void) rtems_event_system_receive( RTEMS_EVENT_SYSTEM_SERVER, @@ -264,99 +136,35 @@ static rtems_task _Timer_server_Body( } } -static void _Timer_server_Wakeup( - Objects_Id id, - void *arg -) -{ - Timer_server_Control *ts = arg; - - _Timer_server_Update_current_snapshot( - &ts->Interval_watchdogs, - _Timer_server_Get_ticks - ); - - _Timer_server_Update_current_snapshot( - &ts->TOD_watchdogs, - _Timer_server_Get_seconds - ); - - (void) rtems_event_system_send( id, RTEMS_EVENT_SYSTEM_SERVER ); -} - -static void _Timer_server_Initialize_watchdogs( - Timer_server_Control *ts, - rtems_id id, - Timer_server_Watchdogs *watchdogs, - Watchdog_Interval (*get_ticks)( void ) -) -{ - Watchdog_Interval now; - - now = (*get_ticks)(); - watchdogs->last_snapshot = now; - watchdogs->current_snapshot = now; - - _Watchdog_Header_initialize( &watchdogs->Header ); - _Watchdog_Preinitialize( &watchdogs->System_watchdog ); - _Watchdog_Initialize( - &watchdogs->System_watchdog, - _Timer_server_Wakeup, - id, - ts - ); -} - -/** - * @brief rtems_timer_initiate_server - * - * This directive creates and starts the server for task-based timers. - * It must be invoked before any task-based timers can be initiated. - * - * @param[in] priority is the timer server priority - * @param[in] stack_size is the stack size in bytes - * @param[in] attribute_set is the timer server attributes - * - * @return This method returns RTEMS_SUCCESSFUL if successful and an - * error code otherwise. - */ -rtems_status_code rtems_timer_initiate_server( - uint32_t priority, - uint32_t stack_size, - rtems_attribute attribute_set +static rtems_status_code _Timer_server_Initiate( + rtems_task_priority priority, + size_t stack_size, + rtems_attribute attribute_set ) { - rtems_id id; rtems_status_code status; - rtems_task_priority _priority; - static bool initialized = false; - bool tmpInitialized; - Timer_server_Control *ts = &_Timer_server_Default; + rtems_id id; + Timer_server_Control *ts; + + /* + * Just to make sure this is only called once. + */ + if ( _Timer_server != NULL ) { + return RTEMS_INCORRECT_STATE; + } /* * Make sure the requested priority is valid. The if is * structured so we check it is invalid before looking for * a specific invalid value as the default. */ - _priority = priority; if ( !_RTEMS_tasks_Priority_is_valid( priority ) ) { if ( priority != RTEMS_TIMER_SERVER_DEFAULT_PRIORITY ) return RTEMS_INVALID_PRIORITY; - _priority = PRIORITY_PSEUDO_ISR; + priority = PRIORITY_PSEUDO_ISR; } /* - * Just to make sure this is only called once. - */ - _Once_Lock(); - tmpInitialized = initialized; - initialized = true; - _Once_Unlock(); - - if ( tmpInitialized ) - return RTEMS_INCORRECT_STATE; - - /* * Create the Timer Server with the name the name of "TIME". The attribute * RTEMS_SYSTEM_TASK allows us to set a priority to 0 which will makes it * higher than any other task in the system. It can be viewed as a low @@ -371,19 +179,18 @@ rtems_status_code rtems_timer_initiate_server( * GNAT run-time is violated. */ status = rtems_task_create( - _Objects_Build_name('T','I','M','E'), /* "TIME" */ - _priority, /* create with priority 1 since 0 is illegal */ - stack_size, /* let user specify stack size */ + rtems_build_name('T','I','M','E'), + priority, + stack_size, rtems_configuration_is_smp_enabled() ? RTEMS_DEFAULT_MODES : /* no preempt is not supported for SMP */ RTEMS_NO_PREEMPT, /* no preempt is like an interrupt */ /* user may want floating point but we need */ /* system task specified for 0 priority */ attribute_set | RTEMS_SYSTEM_TASK, - &id /* get the id back */ + &id ); - if (status) { - initialized = false; + if (status != RTEMS_SUCCESSFUL) { return status; } @@ -392,26 +199,10 @@ rtems_status_code rtems_timer_initiate_server( * Timer Server so we do not have to have a critical section. */ - _Timer_server_Initialize_watchdogs( - ts, - id, - &ts->Interval_watchdogs, - _Timer_server_Get_ticks - ); - - _Timer_server_Initialize_watchdogs( - ts, - id, - &ts->TOD_watchdogs, - _Timer_server_Get_seconds - ); - - /* - * Initialize the pointer to the timer server methods so applications that - * do not use the Timer Server do not have to pull it in. - */ - ts->cancel = _Timer_server_Cancel_method; - ts->schedule_operation = _Timer_server_Schedule_operation_method; + ts = &_Timer_server_Default; + _ISR_lock_Initialize( &ts->Lock, "Timer Server" ); + _Chain_Initialize_empty( &ts->Pending ); + ts->server_id = id; /* * The default timer server is now available. @@ -426,19 +217,22 @@ rtems_status_code rtems_timer_initiate_server( _Timer_server_Body, (rtems_task_argument) ts ); + _Assert( status == RTEMS_SUCCESSFUL ); - #if defined(RTEMS_DEBUG) - /* - * One would expect a call to rtems_task_delete() here to clean up - * but there is actually no way (in normal circumstances) that the - * start can fail. The id and starting address are known to be - * be good. If this service fails, something is weirdly wrong on the - * target such as a stray write in an ISR or incorrect memory layout. - */ - if (status) { - initialized = false; - } - #endif + return status; +} + +rtems_status_code rtems_timer_initiate_server( + rtems_task_priority priority, + size_t stack_size, + rtems_attribute attribute_set +) +{ + rtems_status_code status; + + _Once_Lock(); + status = _Timer_server_Initiate( priority, stack_size, attribute_set ); + _Once_Unlock(); return status; } diff --git a/cpukit/rtems/src/timerserverfireafter.c b/cpukit/rtems/src/timerserverfireafter.c index 0636782ae0..ce1fd05848 100644 --- a/cpukit/rtems/src/timerserverfireafter.c +++ b/cpukit/rtems/src/timerserverfireafter.c @@ -18,12 +18,7 @@ #include "config.h" #endif -#include <rtems/system.h> -#include <rtems/rtems/status.h> -#include <rtems/rtems/support.h> -#include <rtems/score/thread.h> #include <rtems/rtems/timerimpl.h> -#include <rtems/score/watchdogimpl.h> rtems_status_code rtems_timer_server_fire_after( rtems_id id, @@ -32,60 +27,19 @@ rtems_status_code rtems_timer_server_fire_after( void *user_data ) { - Timer_Control *the_timer; - Objects_Locations location; - ISR_Level level; - Timer_server_Control *timer_server = _Timer_server; + Timer_server_Control *timer_server; + + 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: - _Timer_Cancel( the_timer ); - - _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 ); - _Objects_Put( &the_timer->Object ); - 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 ); - - _Objects_Put( &the_timer->Object ); - return RTEMS_SUCCESSFUL; - -#if defined(RTEMS_MULTIPROCESSING) - case OBJECTS_REMOTE: /* should never return this */ -#endif - case OBJECTS_ERROR: - break; - } - - return RTEMS_INVALID_ID; + return _Timer_Fire_after( + id, + ticks, + routine, + user_data, + TIMER_INTERVAL_ON_TASK, + _Timer_server_Routine_adaptor + ); } diff --git a/cpukit/rtems/src/timerserverfirewhen.c b/cpukit/rtems/src/timerserverfirewhen.c index 0069af1c3b..f96a470b7c 100644 --- a/cpukit/rtems/src/timerserverfirewhen.c +++ b/cpukit/rtems/src/timerserverfirewhen.c @@ -19,26 +19,6 @@ #endif #include <rtems/rtems/timerimpl.h> -#include <rtems/rtems/clock.h> -#include <rtems/score/todimpl.h> -#include <rtems/score/watchdogimpl.h> - -/* - * rtems_timer_server_fire_when - * - * This directive allows a thread to start a timer which will by - * executed by the Timer Server when it fires. - * - * Input parameters: - * id - timer id - * wall_time - time of day to fire timer - * routine - routine to schedule - * user_data - passed as argument to routine when it is fired - * - * Output parameters: - * RTEMS_SUCCESSFUL - if successful - * error code - if unsuccessful - */ rtems_status_code rtems_timer_server_fire_when( rtems_id id, @@ -47,47 +27,19 @@ rtems_status_code rtems_timer_server_fire_when( void *user_data ) { - Timer_Control *the_timer; - Objects_Locations location; - rtems_interval seconds; - Timer_server_Control *timer_server = _Timer_server; + Timer_server_Control *timer_server; + + timer_server = _Timer_server; if ( !timer_server ) return RTEMS_INCORRECT_STATE; - if ( !_TOD_Is_set() ) - return RTEMS_NOT_DEFINED; - - if ( !routine ) - return RTEMS_INVALID_ADDRESS; - - if ( !_TOD_Validate( wall_time ) ) - return RTEMS_INVALID_CLOCK; - - seconds = _TOD_To_seconds( wall_time ); - if ( seconds <= _TOD_Seconds_since_epoch() ) - return RTEMS_INVALID_CLOCK; - - the_timer = _Timer_Get( id, &location ); - switch ( location ) { - - case OBJECTS_LOCAL: - _Timer_Cancel( the_timer ); - the_timer->the_class = TIMER_TIME_OF_DAY_ON_TASK; - _Watchdog_Initialize( &the_timer->Ticker, routine, id, user_data ); - the_timer->Ticker.initial = seconds - _TOD_Seconds_since_epoch(); - - (*timer_server->schedule_operation)( timer_server, the_timer ); - - _Objects_Put( &the_timer->Object ); - return RTEMS_SUCCESSFUL; - -#if defined(RTEMS_MULTIPROCESSING) - case OBJECTS_REMOTE: /* should never return this */ -#endif - case OBJECTS_ERROR: - break; - } - - return RTEMS_INVALID_ID; + return _Timer_Fire_when( + id, + wall_time, + routine, + user_data, + TIMER_TIME_OF_DAY_ON_TASK, + _Timer_server_Routine_adaptor + ); } diff --git a/cpukit/sapi/src/exinit.c b/cpukit/sapi/src/exinit.c index 7df23161f3..350c774fc6 100644 --- a/cpukit/sapi/src/exinit.c +++ b/cpukit/sapi/src/exinit.c @@ -38,7 +38,6 @@ #include <rtems/score/timecounter.h> #include <rtems/score/threadimpl.h> #include <rtems/score/todimpl.h> -#include <rtems/score/watchdogimpl.h> #include <rtems/score/wkspace.h> const char _Copyright_Notice[] = @@ -87,8 +86,6 @@ static void rtems_initialize_data_structures(void) _API_Mutex_Allocate( &_RTEMS_Allocator_Mutex ); _API_Mutex_Allocate( &_Once_Mutex ); - _Watchdog_Handler_initialization(); - _Thread_Handler_initialization(); _Scheduler_Handler_initialization(); diff --git a/cpukit/score/Makefile.am b/cpukit/score/Makefile.am index 3d3f1c1532..ea440b384e 100644 --- a/cpukit/score/Makefile.am +++ b/cpukit/score/Makefile.am @@ -327,14 +327,13 @@ libscore_a_SOURCES += src/timespecaddto.c src/timespecfromticks.c \ ## TOD_C_FILES libscore_a_SOURCES += src/coretod.c src/coretodset.c \ - src/coretodtickle.c \ src/coretodtickspersec.c \ src/coretodadjust.c libscore_a_SOURCES += src/coretodabsolutetimeout.c ## WATCHDOG_C_FILES -libscore_a_SOURCES += src/watchdog.c src/watchdogadjust.c \ - src/watchdoginsert.c src/watchdogremove.c +libscore_a_SOURCES += src/watchdoginsert.c +libscore_a_SOURCES += src/watchdogremove.c libscore_a_SOURCES += src/watchdogtick.c libscore_a_SOURCES += src/watchdogtickssinceboot.c diff --git a/cpukit/score/include/rtems/score/mrsp.h b/cpukit/score/include/rtems/score/mrsp.h index 08f96ac4ac..cb3de67e26 100644 --- a/cpukit/score/include/rtems/score/mrsp.h +++ b/cpukit/score/include/rtems/score/mrsp.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 2014 embedded brains GmbH. All rights reserved. + * Copyright (c) 2014, 2016 embedded brains GmbH. All rights reserved. * * embedded brains GmbH * Dornierstr. 4 @@ -128,6 +128,11 @@ typedef struct { * MRSP_TIMEOUT. State changes are protected by the MrsP control lock. */ volatile MRSP_Status status; + + /** + * @brief Watchdog for timeouts. + */ + Watchdog_Control Watchdog; } MRSP_Rival; /** diff --git a/cpukit/score/include/rtems/score/mrspimpl.h b/cpukit/score/include/rtems/score/mrspimpl.h index bc9ed4b511..7638fb5975 100644 --- a/cpukit/score/include/rtems/score/mrspimpl.h +++ b/cpukit/score/include/rtems/score/mrspimpl.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 2014-2015 embedded brains GmbH. All rights reserved. + * Copyright (c) 2014, 2016 embedded brains GmbH. All rights reserved. * * embedded brains GmbH * Dornierstr. 4 @@ -159,18 +159,13 @@ RTEMS_INLINE_ROUTINE void _MRSP_Set_ceiling_priority( mrsp->ceiling_priorities[ scheduler_index ] = ceiling_priority; } -RTEMS_INLINE_ROUTINE void _MRSP_Timeout( - Objects_Id id, - void *arg -) +RTEMS_INLINE_ROUTINE void _MRSP_Timeout( Watchdog_Control *watchdog ) { - MRSP_Rival *rival = arg; + MRSP_Rival *rival = RTEMS_CONTAINER_OF( watchdog, MRSP_Rival, Watchdog ); MRSP_Control *mrsp = rival->resource; Thread_Control *thread = rival->thread; ISR_lock_Context lock_context; - (void) id; - _ISR_lock_ISR_disable_and_acquire( &mrsp->Lock, &lock_context ); if ( rival->status == MRSP_WAIT_FOR_OWNERSHIP ) { @@ -209,6 +204,7 @@ RTEMS_INLINE_ROUTINE MRSP_Status _MRSP_Wait_for_ownership( bool initial_life_protection; Per_CPU_Control *cpu_self; ISR_lock_Context giant_lock_context; + ISR_Level level; rival.thread = executing; rival.resource = mrsp; @@ -236,13 +232,11 @@ RTEMS_INLINE_ROUTINE MRSP_Status _MRSP_Wait_for_ownership( _Thread_Raise_priority( executing, ceiling_priority ); if ( timeout > 0 ) { - _Watchdog_Initialize( - &executing->Timer, - _MRSP_Timeout, - 0, - &rival - ); - _Watchdog_Insert_ticks( &executing->Timer, timeout ); + _Watchdog_Preinitialize( &rival.Watchdog, cpu_self ); + _Watchdog_Initialize( &rival.Watchdog, _MRSP_Timeout ); + _ISR_Disable_without_giant( level ); + _Watchdog_Per_CPU_insert_relative( &rival.Watchdog, cpu_self, timeout ); + _ISR_Enable_without_giant( level ); } initial_life_protection = _Thread_Set_life_protection( true ); @@ -258,7 +252,13 @@ RTEMS_INLINE_ROUTINE MRSP_Status _MRSP_Wait_for_ownership( _Thread_Set_life_protection( initial_life_protection ); if ( timeout > 0 ) { - _Watchdog_Remove_ticks( &executing->Timer ); + _ISR_Disable_without_giant( level ); + _Watchdog_Per_CPU_remove( + &rival.Watchdog, + cpu_self, + &cpu_self->Watchdog.Header[ PER_CPU_WATCHDOG_RELATIVE ] + ); + _ISR_Enable_without_giant( level ); if ( status == MRSP_TIMEOUT ) { _MRSP_Restore_priority( executing, initial_priority ); diff --git a/cpukit/score/include/rtems/score/percpu.h b/cpukit/score/include/rtems/score/percpu.h index 39be1e3367..22017889b3 100644 --- a/cpukit/score/include/rtems/score/percpu.h +++ b/cpukit/score/include/rtems/score/percpu.h @@ -23,10 +23,11 @@ #include <rtems/asm.h> #else #include <rtems/score/assert.h> - #include <rtems/score/isrlevel.h> + #include <rtems/score/isrlock.h> #include <rtems/score/smp.h> #include <rtems/score/smplock.h> #include <rtems/score/timestamp.h> + #include <rtems/score/watchdog.h> #endif #ifdef __cplusplus @@ -41,7 +42,7 @@ extern "C" { * processor. */ #if defined( RTEMS_PROFILING ) - #define PER_CPU_CONTROL_SIZE_LOG2 8 + #define PER_CPU_CONTROL_SIZE_LOG2 9 #else #define PER_CPU_CONTROL_SIZE_LOG2 7 #endif @@ -226,6 +227,32 @@ typedef struct { } Per_CPU_Stats; /** + * @brief Per-CPU watchdog header index. + */ +typedef enum { + /** + * @brief Index for relative per-CPU watchdog header. + * + * The reference time point for this header is current ticks value + * during insert. Time is measured in clock ticks. + */ + PER_CPU_WATCHDOG_RELATIVE, + + /** + * @brief Index for absolute per-CPU watchdog header. + * + * The reference time point for this header is the POSIX Epoch. Time is + * measured in nanoseconds since POSIX Epoch. + */ + PER_CPU_WATCHDOG_ABSOLUTE, + + /** + * @brief Count of per-CPU watchdog headers. + */ + PER_CPU_WATCHDOG_COUNT +} Per_CPU_Watchdog_index; + +/** * @brief Per CPU Core Structure * * This structure is used to hold per core state information. @@ -309,6 +336,28 @@ typedef struct Per_CPU_Control { /** This is the time of the last context switch on this CPU. */ Timestamp_Control time_of_last_context_switch; + /** + * @brief Watchdog state for this processor. + */ + struct { + /** + * @brief Protects all watchdog operations on this processor. + */ + ISR_LOCK_MEMBER( Lock ) + + /** + * @brief Watchdog ticks on this processor used for relative watchdogs. + */ + uint64_t ticks; + + /** + * @brief Header for watchdogs. + * + * @see Per_CPU_Watchdog_index. + */ + Watchdog_Header Header[ PER_CPU_WATCHDOG_COUNT ]; + } Watchdog; + #if defined( RTEMS_SMP ) /** * @brief This lock protects some parts of the low-level thread dispatching. diff --git a/cpukit/score/include/rtems/score/schedulerimpl.h b/cpukit/score/include/rtems/score/schedulerimpl.h index cadebfd02f..d50c36a7b9 100644 --- a/cpukit/score/include/rtems/score/schedulerimpl.h +++ b/cpukit/score/include/rtems/score/schedulerimpl.h @@ -452,19 +452,13 @@ RTEMS_INLINE_ROUTINE void _Scheduler_Release_job( * scheduler which support standard RTEMS features, this includes * time-slicing management. */ -RTEMS_INLINE_ROUTINE void _Scheduler_Tick( void ) +RTEMS_INLINE_ROUTINE void _Scheduler_Tick( const Per_CPU_Control *cpu ) { - uint32_t cpu_count = _SMP_Get_processor_count(); - uint32_t cpu_index; + const Scheduler_Control *scheduler = _Scheduler_Get_by_CPU( cpu ); + Thread_Control *executing = cpu->executing; - for ( cpu_index = 0 ; cpu_index < cpu_count ; ++cpu_index ) { - const Per_CPU_Control *cpu = _Per_CPU_Get_by_index( cpu_index ); - const Scheduler_Control *scheduler = _Scheduler_Get_by_CPU( cpu ); - Thread_Control *executing = cpu->executing; - - if ( scheduler != NULL && executing != NULL ) { - ( *scheduler->Operations.tick )( scheduler, executing ); - } + if ( scheduler != NULL && executing != NULL ) { + ( *scheduler->Operations.tick )( scheduler, executing ); } } diff --git a/cpukit/score/include/rtems/score/thread.h b/cpukit/score/include/rtems/score/thread.h index 73776b3ec1..44b706d7ff 100644 --- a/cpukit/score/include/rtems/score/thread.h +++ b/cpukit/score/include/rtems/score/thread.h @@ -347,6 +347,15 @@ typedef struct { } Thread_Wait_information; /** + * @brief Information required to manage a thread timer. + */ +typedef struct { + ISR_LOCK_MEMBER( Lock ) + Watchdog_Header *header; + Watchdog_Control Watchdog; +} Thread_Timer_information; + +/** * The following defines the control block used to manage * each thread proxy. * @@ -400,7 +409,7 @@ typedef struct { /** This field is the blocking information for this proxy. */ Thread_Wait_information Wait; /** This field is the Watchdog used to manage proxy delays and timeouts. */ - Watchdog_Control Timer; + Thread_Timer_information Timer; #if defined(RTEMS_MULTIPROCESSING) /** This field is the received response packet in an MP system. */ MP_packet_Prefix *receive_packet; @@ -728,7 +737,7 @@ struct _Thread_Control { /** This field is the blocking information for this thread. */ Thread_Wait_information Wait; /** This field is the Watchdog used to manage thread delays and timeouts. */ - Watchdog_Control Timer; + Thread_Timer_information Timer; #if defined(RTEMS_MULTIPROCESSING) /** This field is the received response packet in an MP system. */ MP_packet_Prefix *receive_packet; diff --git a/cpukit/score/include/rtems/score/threadimpl.h b/cpukit/score/include/rtems/score/threadimpl.h index 1377543118..ec9851dba0 100644 --- a/cpukit/score/include/rtems/score/threadimpl.h +++ b/cpukit/score/include/rtems/score/threadimpl.h @@ -33,6 +33,7 @@ #include <rtems/score/threadqimpl.h> #include <rtems/score/todimpl.h> #include <rtems/score/freechain.h> +#include <rtems/score/watchdogimpl.h> #include <rtems/config.h> #ifdef __cplusplus @@ -1472,10 +1473,64 @@ RTEMS_INLINE_ROUTINE void _Thread_Wait_set_timeout_code( /** * @brief General purpose thread wait timeout. * - * @param[in] id Unused. - * @param[in] arg The thread. + * @param[in] watchdog The thread timer watchdog. */ -void _Thread_Timeout( Objects_Id id, void *arg ); +void _Thread_Timeout( Watchdog_Control *watchdog ); + +RTEMS_INLINE_ROUTINE void _Thread_Timer_insert_relative( + Thread_Control *the_thread, + Per_CPU_Control *cpu, + Watchdog_Service_routine_entry routine, + Watchdog_Interval ticks +) +{ + ISR_lock_Context lock_context; + + _ISR_lock_ISR_disable_and_acquire( &the_thread->Timer.Lock, &lock_context ); + + the_thread->Timer.header = &cpu->Watchdog.Header[ PER_CPU_WATCHDOG_RELATIVE ]; + the_thread->Timer.Watchdog.routine = routine; + _Watchdog_Per_CPU_insert_relative( &the_thread->Timer.Watchdog, cpu, ticks ); + + _ISR_lock_Release_and_ISR_enable( &the_thread->Timer.Lock, &lock_context ); +} + +RTEMS_INLINE_ROUTINE void _Thread_Timer_insert_absolute( + Thread_Control *the_thread, + Per_CPU_Control *cpu, + Watchdog_Service_routine_entry routine, + uint64_t expire +) +{ + ISR_lock_Context lock_context; + + _ISR_lock_ISR_disable_and_acquire( &the_thread->Timer.Lock, &lock_context ); + + the_thread->Timer.header = &cpu->Watchdog.Header[ PER_CPU_WATCHDOG_ABSOLUTE ]; + the_thread->Timer.Watchdog.routine = routine; + _Watchdog_Per_CPU_insert_absolute( &the_thread->Timer.Watchdog, cpu, expire ); + + _ISR_lock_Release_and_ISR_enable( &the_thread->Timer.Lock, &lock_context ); +} + +RTEMS_INLINE_ROUTINE void _Thread_Timer_remove( Thread_Control *the_thread ) +{ + ISR_lock_Context lock_context; + + _ISR_lock_ISR_disable_and_acquire( &the_thread->Timer.Lock, &lock_context ); + + _Watchdog_Per_CPU_remove( + &the_thread->Timer.Watchdog, +#if defined(RTEMS_SMP) + the_thread->Timer.Watchdog.cpu, +#else + _Per_CPU_Get(), +#endif + the_thread->Timer.header + ); + + _ISR_lock_Release_and_ISR_enable( &the_thread->Timer.Lock, &lock_context ); +} RTEMS_INLINE_ROUTINE void _Thread_Debug_set_real_processor( Thread_Control *the_thread, diff --git a/cpukit/score/include/rtems/score/todimpl.h b/cpukit/score/include/rtems/score/todimpl.h index b61651cdba..b1f8a6d6b6 100644 --- a/cpukit/score/include/rtems/score/todimpl.h +++ b/cpukit/score/include/rtems/score/todimpl.h @@ -132,15 +132,6 @@ extern "C" { */ typedef struct { /** - * @brief Time of day seconds trigger. - * - * This value specifies the nanoseconds since the last time of day second. - * It is updated and evaluated in _TOD_Tickle_ticks(). It is set in - * _TOD_Set_with_timestamp(). - */ - uint32_t seconds_trigger; - - /** * @brief Indicates if the time of day is set. * * This is true if the application has set the current @@ -273,14 +264,6 @@ static inline uint32_t _TOD_Seconds_since_epoch( void ) } /** - * @brief Increments time of day at each clock tick. - * - * This routine increments the ticks field of the current time of - * day at each clock tick. - */ -void _TOD_Tickle_ticks( void ); - -/** * @brief Gets number of ticks in a second. * * This method returns the number of ticks in a second. diff --git a/cpukit/score/include/rtems/score/watchdog.h b/cpukit/score/include/rtems/score/watchdog.h index bad7269051..c582dbd1ae 100644 --- a/cpukit/score/include/rtems/score/watchdog.h +++ b/cpukit/score/include/rtems/score/watchdog.h @@ -20,7 +20,11 @@ #ifndef _RTEMS_SCORE_WATCHDOG_H #define _RTEMS_SCORE_WATCHDOG_H -#include <rtems/score/object.h> +#include <rtems/score/basedefs.h> +#include <rtems/score/chain.h> +#include <rtems/score/rbtree.h> + +struct Per_CPU_Control; #ifdef __cplusplus extern "C" { @@ -39,6 +43,8 @@ extern "C" { */ /**@{*/ +typedef struct Watchdog_Control Watchdog_Control; + /** * @brief Type is used to specify the length of intervals. * @@ -58,10 +64,8 @@ typedef void Watchdog_Service_routine; * * This type define a pointer to a watchdog service routine. */ -typedef Watchdog_Service_routine ( *Watchdog_Service_routine_entry )( - Objects_Id, - void * - ); +typedef Watchdog_Service_routine + ( *Watchdog_Service_routine_entry )( Watchdog_Control * ); /** * @brief The constant for indefinite wait. @@ -72,22 +76,20 @@ typedef Watchdog_Service_routine ( *Watchdog_Service_routine_entry )( #define WATCHDOG_NO_TIMEOUT 0 /** - * @brief Set of the states which a watchdog timer may be at any given time. - * - * This enumerated type is the set of the states in which a - * watchdog timer may be at any given time. + * @brief The watchdog header to manage scheduled watchdogs. */ +typedef struct { + /** + * @brief Red-black tree of scheduled watchdogs sorted by expiration time. + */ + RBTree_Control Watchdogs; -typedef enum { - /** This is the state when the watchdog is off all chains */ - WATCHDOG_INACTIVE, - /** This is the state when the watchdog is off all chains, but we are - * currently searching for the insertion point. + /** + * @brief The scheduled watchdog with the earliest expiration time or NULL in + * case no watchdog is scheduled. */ - WATCHDOG_BEING_INSERTED, - /** This is the state when the watchdog is on a chain, and allowed to fire. */ - WATCHDOG_ACTIVE -} Watchdog_States; + RBTree_Node *first; +} Watchdog_Header; /** * @brief The control block used to manage each watchdog timer. @@ -95,30 +97,35 @@ typedef enum { * The following record defines the control block used * to manage each watchdog timer. */ -typedef struct { - /** This field is a Chain Node structure and allows this to be placed on - * chains for set management. - */ - Chain_Node Node; - /** This field is the state of the watchdog. */ - Watchdog_States state; - /** This field is the initially requested interval. */ - Watchdog_Interval initial; - /** This field is the remaining portion of the interval. */ - Watchdog_Interval delta_interval; - /** This field is the number of system clock ticks when this was scheduled. */ - Watchdog_Interval start_time; - /** This field is the number of system clock ticks when this was suspended. */ - Watchdog_Interval stop_time; - /** This field is the function to invoke. */ - Watchdog_Service_routine_entry routine; - /** This field is the Id to pass as an argument to the routine. */ - Objects_Id id; - /** This field is an untyped pointer to user data that is passed to the - * watchdog handler routine. +struct Watchdog_Control { + /** + * @brief Nodes for the watchdog. */ - void *user_data; -} Watchdog_Control; + union { + /** + * @brief this field is a red-black tree node structure and allows this to + * be placed on a red-black tree used to manage the scheduled watchdogs. + */ + RBTree_Node RBTree; + + /** + * @brief this field is a chain node structure and allows this to be placed + * on a chain used to manage pending watchdogs by the timer server. + */ + Chain_Node Chain; + } Node; + +#if defined(RTEMS_SMP) + /** @brief This field references the processor of this watchdog control. */ + struct Per_CPU_Control *cpu; +#endif + + /** @brief This field is the function to invoke. */ + Watchdog_Service_routine_entry routine; + + /** @brief This field is the expiration time point. */ + uint64_t expire; +}; /** * @brief The watchdog ticks counter. diff --git a/cpukit/score/include/rtems/score/watchdogimpl.h b/cpukit/score/include/rtems/score/watchdogimpl.h index 49ac2a12b1..2b24cc68e5 100644 --- a/cpukit/score/include/rtems/score/watchdogimpl.h +++ b/cpukit/score/include/rtems/score/watchdogimpl.h @@ -21,9 +21,11 @@ #include <rtems/score/watchdog.h> #include <rtems/score/assert.h> -#include <rtems/score/chainimpl.h> #include <rtems/score/isrlock.h> #include <rtems/score/percpu.h> +#include <rtems/score/rbtreeimpl.h> + +#include <sys/timespec.h> #ifdef __cplusplus extern "C" { @@ -35,241 +37,116 @@ extern "C" { */ /** - * @brief Watchdog initializer for static initialization. - * - * @see _Watchdog_Initialize(). - */ -#define WATCHDOG_INITIALIZER( routine, id, user_data ) \ - { \ - { NULL, NULL }, \ - WATCHDOG_INACTIVE, \ - 0, 0, 0, 0, \ - ( routine ), ( id ), ( user_data ) \ - } - -/** - * @brief Iterator item to synchronize concurrent insert, remove and tickle - * operations. + * @brief Watchdog states. */ -typedef struct { +typedef enum { /** - * @brief A node for a Watchdog_Header::Iterators chain. + * @brief The watchdog is scheduled and a black node in the red-black tree. */ - Chain_Node Node; + WATCHDOG_SCHEDULED_BLACK, /** - * @brief The current delta interval of the new watchdog to insert. + * @brief The watchdog is scheduled and a red node in the red-black tree. */ - Watchdog_Interval delta_interval; + WATCHDOG_SCHEDULED_RED, /** - * @brief The current watchdog of the chain on the way to insert the new - * watchdog. + * @brief The watchdog is inactive. */ - Chain_Node *current; -} Watchdog_Iterator; - -/** - * @brief Watchdog header. - */ -typedef struct { - /** - * @brief ISR lock to protect this watchdog chain. - */ - ISR_LOCK_MEMBER( Lock ) + WATCHDOG_INACTIVE, /** - * @brief The chain of active or transient watchdogs. - */ - Chain_Control Watchdogs; - - /** - * @brief Currently active iterators. + * @brief The watchdog is on a chain of pending watchdogs. * - * The iterators are registered in _Watchdog_Insert() and updated in case the - * watchdog chain changes. + * This state is used by the timer server for example. */ - Chain_Control Iterators; -} Watchdog_Header; + WATCHDOG_PENDING +} Watchdog_State; /** - * @brief Watchdog chain which is managed at ticks. + * @brief Watchdog initializer for static initialization. * - * This is the watchdog chain which is managed at ticks. - */ -extern Watchdog_Header _Watchdog_Ticks_header; - -/** - * @brief Watchdog chain which is managed at second boundaries. + * The processor of this watchdog is set to processor with index zero. * - * This is the watchdog chain which is managed at second boundaries. + * @see _Watchdog_Preinitialize(). */ -extern Watchdog_Header _Watchdog_Seconds_header; - -RTEMS_INLINE_ROUTINE void _Watchdog_Acquire( - Watchdog_Header *header, - ISR_lock_Context *lock_context -) -{ - _ISR_lock_ISR_disable_and_acquire( &header->Lock, lock_context ); -} +#if defined(RTEMS_SMP) + #define WATCHDOG_INITIALIZER( routine ) \ + { \ + { { { NULL, NULL, NULL, WATCHDOG_INACTIVE } } }, \ + &_Per_CPU_Information[ 0 ].per_cpu, \ + ( routine ), \ + 0 \ + } +#else + #define WATCHDOG_INITIALIZER( routine ) \ + { \ + { { { NULL, NULL, NULL, WATCHDOG_INACTIVE } } }, \ + ( routine ), \ + 0 \ + } +#endif -RTEMS_INLINE_ROUTINE void _Watchdog_Release( - Watchdog_Header *header, - ISR_lock_Context *lock_context +RTEMS_INLINE_ROUTINE void _Watchdog_Header_initialize( + Watchdog_Header *header ) { - _ISR_lock_Release_and_ISR_enable( &header->Lock, lock_context ); + _RBTree_Initialize_empty( &header->Watchdogs ); + header->first = NULL; } -RTEMS_INLINE_ROUTINE void _Watchdog_Flash( - Watchdog_Header *header, - ISR_lock_Context *lock_context +RTEMS_INLINE_ROUTINE void _Watchdog_Header_destroy( + Watchdog_Header *header ) { - _ISR_lock_Flash( &header->Lock, lock_context ); + /* Do nothing */ + (void) header; } /** - * @brief Initialize the watchdog handler. - * - * This routine initializes the watchdog handler. The watchdog - * synchronization flag is initialized and the watchdog chains are - * initialized and emptied. - */ -void _Watchdog_Handler_initialization( void ); - -/** * @brief Performs a watchdog tick. * * @param cpu The processor for this watchdog tick. */ -void _Watchdog_Tick( Per_CPU_Control *cpu ); - -/** - * @brief Removes @a the_watchdog from the watchdog chain. - * - * This routine removes @a the_watchdog from the watchdog chain on which - * it resides and returns the state @a the_watchdog timer was in. - * - * @param[in] header The watchdog chain. - * @param[in] the_watchdog will be removed - * @retval the state in which @a the_watchdog was in when removed - */ -Watchdog_States _Watchdog_Remove ( - Watchdog_Header *header, - Watchdog_Control *the_watchdog -); - -/** - * @brief Adjusts the header watchdog chain in the backward direction for - * units ticks. - * - * @param[in] header The watchdog chain. - * @param[in] units The units of ticks to adjust. - */ -void _Watchdog_Adjust_backward( - Watchdog_Header *header, - Watchdog_Interval units -); - -/** - * @brief Adjusts the watchdogs in backward direction in a locked context. - * - * The caller must be the owner of the watchdog lock and will be the owner - * after the call. - * - * @param[in] header The watchdog header. - * @param[in] units The units of ticks to adjust. - * - * @see _Watchdog_Adjust_forward(). - */ -void _Watchdog_Adjust_backward_locked( - Watchdog_Header *header, - Watchdog_Interval units -); +void _Watchdog_Tick( struct Per_CPU_Control *cpu ); -/** - * @brief Adjusts the header watchdog chain in the forward direction for units - * ticks. - * - * This may lead to several _Watchdog_Tickle() invocations. - * - * @param[in] header The watchdog chain. - * @param[in] units The units of ticks to adjust. - */ -void _Watchdog_Adjust_forward( - Watchdog_Header *header, - Watchdog_Interval units -); +RTEMS_INLINE_ROUTINE Watchdog_State _Watchdog_Get_state( + const Watchdog_Control *the_watchdog +) +{ + return RB_COLOR( &the_watchdog->Node.RBTree, Node ); +} -/** - * @brief Adjusts the watchdogs in forward direction in a locked context. - * - * The caller must be the owner of the watchdog lock and will be the owner - * after the call. This function may release and acquire the watchdog lock - * internally. - * - * @param[in] header The watchdog header. - * @param[in] units The units of ticks to adjust. - * @param[in] lock_context The lock context. - * - * @see _Watchdog_Adjust_forward(). - */ -void _Watchdog_Adjust_forward_locked( - Watchdog_Header *header, - Watchdog_Interval units, - ISR_lock_Context *lock_context -); +RTEMS_INLINE_ROUTINE void _Watchdog_Set_state( + Watchdog_Control *the_watchdog, + Watchdog_State state +) +{ + RB_COLOR( &the_watchdog->Node.RBTree, Node ) = state; +} -/** - * @brief Inserts @a the_watchdog into the @a header watchdog chain - * for a time of @a units. - * - * This routine inserts @a the_watchdog into the @a header watchdog chain - * for a time of @a units. - * Update the delta interval counters. - * - * @param[in] header is @a the_watchdog list to insert @a the_watchdog on - * @param[in] the_watchdog is the watchdog to insert - */ -void _Watchdog_Insert ( - Watchdog_Header *header, - Watchdog_Control *the_watchdog -); +RTEMS_INLINE_ROUTINE Per_CPU_Control *_Watchdog_Get_CPU( + const Watchdog_Control *the_watchdog +) +{ +#if defined(RTEMS_SMP) + return the_watchdog->cpu; +#else + return _Per_CPU_Get_by_index( 0 ); +#endif +} -/** - * @brief Inserts the watchdog in a locked context. - * - * The caller must be the owner of the watchdog lock and will be the owner - * after the call. This function may release and acquire the watchdog lock - * internally. - * - * @param[in] header The watchdog header. - * @param[in] the_watchdog The watchdog. - * @param[in] lock_context The lock context. - * - * @see _Watchdog_Insert(). - */ -void _Watchdog_Insert_locked( - Watchdog_Header *header, +RTEMS_INLINE_ROUTINE void _Watchdog_Set_CPU( Watchdog_Control *the_watchdog, - ISR_lock_Context *lock_context -); - -/** - * @brief This routine is invoked at appropriate intervals to update - * the @a header watchdog chain. - * - * This routine is invoked at appropriate intervals to update - * the @a header watchdog chain. - * This routine decrements the delta counter in response to a tick. - * - * @param[in] header is the watchdog chain to tickle - */ -void _Watchdog_Tickle ( - Watchdog_Header *header -); + Per_CPU_Control *cpu +) +{ +#if defined(RTEMS_SMP) + the_watchdog->cpu = cpu; +#else + (void) cpu; +#endif +} /** * @brief Pre-initializes a watchdog. @@ -280,228 +157,284 @@ void _Watchdog_Tickle ( * @param[in] the_watchdog The uninitialized watchdog. */ RTEMS_INLINE_ROUTINE void _Watchdog_Preinitialize( - Watchdog_Control *the_watchdog + Watchdog_Control *the_watchdog, + Per_CPU_Control *cpu ) { - the_watchdog->state = WATCHDOG_INACTIVE; + _Watchdog_Set_CPU( the_watchdog, cpu ); + _Watchdog_Set_state( the_watchdog, WATCHDOG_INACTIVE ); + #if defined(RTEMS_DEBUG) the_watchdog->routine = NULL; - the_watchdog->id = 0; - the_watchdog->user_data = NULL; + the_watchdog->expire = 0; #endif } /** - * This routine initializes the specified watchdog. The watchdog is - * made inactive, the watchdog id and handler routine are set to the - * specified values. + * @brief Initializes a watchdog with a new service routine. + * + * The watchdog must be inactive. */ - RTEMS_INLINE_ROUTINE void _Watchdog_Initialize( Watchdog_Control *the_watchdog, - Watchdog_Service_routine_entry routine, - Objects_Id id, - void *user_data + Watchdog_Service_routine_entry routine ) { - _Assert( the_watchdog->state == WATCHDOG_INACTIVE ); - the_watchdog->routine = routine; - the_watchdog->id = id; - the_watchdog->user_data = user_data; + _Assert( _Watchdog_Get_state( the_watchdog ) == WATCHDOG_INACTIVE ); + the_watchdog->routine = routine; } +void _Watchdog_Do_tickle( + Watchdog_Header *header, + uint64_t now, +#if defined(RTEMS_SMP) + ISR_lock_Control *lock, +#endif + ISR_lock_Context *lock_context +); + +#if defined(RTEMS_SMP) + #define _Watchdog_Tickle( header, now, lock, lock_context ) \ + _Watchdog_Do_tickle( header, now, lock, lock_context ) +#else + #define _Watchdog_Tickle( header, now, lock, lock_context ) \ + _Watchdog_Do_tickle( header, now, lock_context ) +#endif + /** - * This routine returns true if the watchdog timer is in the ACTIVE - * state, and false otherwise. + * @brief Inserts a watchdog into the set of scheduled watchdogs according to + * the specified expiration time. + * + * The watchdog must be inactive. */ +void _Watchdog_Insert( + Watchdog_Header *header, + Watchdog_Control *the_watchdog, + uint64_t expire +); -RTEMS_INLINE_ROUTINE bool _Watchdog_Is_active( +/** + * @brief In case the watchdog is scheduled, then it is removed from the set of + * scheduled watchdogs. + * + * The watchdog must be initialized before this call. + */ +void _Watchdog_Remove( + Watchdog_Header *header, Watchdog_Control *the_watchdog -) -{ - - return ( the_watchdog->state == WATCHDOG_ACTIVE ); - -} +); /** - * This routine activates THE_WATCHDOG timer which is already - * on a watchdog chain. + * @brief In case the watchdog is scheduled, then it is removed from the set of + * scheduled watchdogs. + * + * The watchdog must be initialized before this call. + * + * @retval 0 The now time is greater than or equal to the expiration time of + * the watchdog. + * @retval other The difference of the now and expiration time. */ - -RTEMS_INLINE_ROUTINE void _Watchdog_Activate( - Watchdog_Control *the_watchdog +RTEMS_INLINE_ROUTINE uint64_t _Watchdog_Cancel( + Watchdog_Header *header, + Watchdog_Control *the_watchdog, + uint64_t now ) { + uint64_t expire; + uint64_t remaining; - the_watchdog->state = WATCHDOG_ACTIVE; + expire = the_watchdog->expire; -} - -/** - * This routine is invoked at each clock tick to update the ticks - * watchdog chain. - */ - -RTEMS_INLINE_ROUTINE void _Watchdog_Tickle_ticks( void ) -{ + if ( now < expire ) { + remaining = expire - now; + } else { + remaining = 0; + } - _Watchdog_Tickle( &_Watchdog_Ticks_header ); + _Watchdog_Remove( header, the_watchdog ); + return remaining; } -/** - * This routine is invoked at each clock tick to update the seconds - * watchdog chain. - */ - -RTEMS_INLINE_ROUTINE void _Watchdog_Tickle_seconds( void ) +RTEMS_INLINE_ROUTINE bool _Watchdog_Is_scheduled( + const Watchdog_Control *the_watchdog +) { - - _Watchdog_Tickle( &_Watchdog_Seconds_header ); - + return _Watchdog_Get_state( the_watchdog ) < WATCHDOG_INACTIVE; } -/** - * This routine inserts THE_WATCHDOG into the ticks watchdog chain - * for a time of UNITS ticks. The INSERT_MODE indicates whether - * THE_WATCHDOG is to be activated automatically or later, explicitly - * by the caller. - */ - -RTEMS_INLINE_ROUTINE void _Watchdog_Insert_ticks( - Watchdog_Control *the_watchdog, - Watchdog_Interval units +RTEMS_INLINE_ROUTINE void _Watchdog_Next_first( + Watchdog_Header *header, + Watchdog_Control *the_watchdog ) { + RBTree_Node *node = _RBTree_Right( &the_watchdog->Node.RBTree ); - the_watchdog->initial = units; + if ( node != NULL ) { + RBTree_Node *left; - _Watchdog_Insert( &_Watchdog_Ticks_header, the_watchdog ); + while ( ( left = _RBTree_Left( node ) ) != NULL ) { + node = left; + } + header->first = node; + } else { + header->first = _RBTree_Parent( &the_watchdog->Node.RBTree ); + } } /** - * This routine inserts THE_WATCHDOG into the seconds watchdog chain - * for a time of UNITS seconds. The INSERT_MODE indicates whether - * THE_WATCHDOG is to be activated automatically or later, explicitly - * by the caller. + * @brief The bits necessary to store 1000000000 nanoseconds. + * + * The expiration time is an unsigned 64-bit integer. To store absolute + * timeouts we use 30 bits (2**30 == 1073741824) for the nanoseconds and 34 + * bits for the seconds since UNIX Epoch. This leads to a year 2514 problem. */ +#define WATCHDOG_BITS_FOR_1E9_NANOSECONDS 30 -RTEMS_INLINE_ROUTINE void _Watchdog_Insert_seconds( - Watchdog_Control *the_watchdog, - Watchdog_Interval units +RTEMS_INLINE_ROUTINE uint64_t _Watchdog_Ticks_from_seconds( + uint32_t seconds ) { + uint64_t ticks = seconds; - the_watchdog->initial = units; - - _Watchdog_Insert( &_Watchdog_Seconds_header, the_watchdog ); + ticks <<= WATCHDOG_BITS_FOR_1E9_NANOSECONDS; + return ticks; } -RTEMS_INLINE_ROUTINE Watchdog_States _Watchdog_Remove_ticks( - Watchdog_Control *the_watchdog +RTEMS_INLINE_ROUTINE uint64_t _Watchdog_Ticks_from_timespec( + const struct timespec *ts ) { - return _Watchdog_Remove( &_Watchdog_Ticks_header, the_watchdog ); + /* + * The seconds are in time_t which is a signed integer. Thus this cast is + * subject to the year 2038 problem in case time_t is a 32-bit integer. + */ + uint64_t ticks = (uint64_t) ts->tv_sec; + + _Assert( ticks < 0x400000000 ); + _Assert( ts->tv_nsec >= 0 ); + _Assert( ts->tv_nsec < 1000000000 ); + + ticks <<= WATCHDOG_BITS_FOR_1E9_NANOSECONDS; + ticks |= ts->tv_nsec; + + return ticks; } -RTEMS_INLINE_ROUTINE Watchdog_States _Watchdog_Remove_seconds( - Watchdog_Control *the_watchdog +RTEMS_INLINE_ROUTINE void _Watchdog_Per_CPU_acquire_critical( + Per_CPU_Control *cpu, + ISR_lock_Context *lock_context ) { - return _Watchdog_Remove( &_Watchdog_Seconds_header, the_watchdog ); + _ISR_lock_Acquire( &cpu->Watchdog.Lock, lock_context ); } -/** - * This routine resets THE_WATCHDOG timer to its state at INSERT - * time. This routine is valid only on interval watchdog timers - * and is used to make an interval watchdog timer fire "every" so - * many ticks. - */ - -RTEMS_INLINE_ROUTINE void _Watchdog_Reset_ticks( - Watchdog_Control *the_watchdog +RTEMS_INLINE_ROUTINE void _Watchdog_Per_CPU_release_critical( + Per_CPU_Control *cpu, + ISR_lock_Context *lock_context ) { - - _Watchdog_Remove_ticks( the_watchdog ); - - _Watchdog_Insert( &_Watchdog_Ticks_header, the_watchdog ); - + _ISR_lock_Release( &cpu->Watchdog.Lock, lock_context ); } -/** - * This routine returns a pointer to the watchdog timer following - * THE_WATCHDOG on the watchdog chain. - */ - -RTEMS_INLINE_ROUTINE Watchdog_Control *_Watchdog_Next( - Watchdog_Control *the_watchdog +RTEMS_INLINE_ROUTINE void _Watchdog_Per_CPU_insert_relative( + Watchdog_Control *the_watchdog, + Per_CPU_Control *cpu, + uint32_t ticks ) { + ISR_lock_Context lock_context; - return ( (Watchdog_Control *) the_watchdog->Node.next ); + _Watchdog_Set_CPU( the_watchdog, cpu ); + _Watchdog_Per_CPU_acquire_critical( cpu, &lock_context ); + _Watchdog_Insert( + &cpu->Watchdog.Header[ PER_CPU_WATCHDOG_RELATIVE ], + the_watchdog, + cpu->Watchdog.ticks + ticks + ); + _Watchdog_Per_CPU_release_critical( cpu, &lock_context ); } -/** - * This routine returns a pointer to the watchdog timer preceding - * THE_WATCHDOG on the watchdog chain. - */ - -RTEMS_INLINE_ROUTINE Watchdog_Control *_Watchdog_Previous( - Watchdog_Control *the_watchdog +RTEMS_INLINE_ROUTINE void _Watchdog_Per_CPU_insert_absolute( + Watchdog_Control *the_watchdog, + Per_CPU_Control *cpu, + uint64_t expire ) { + ISR_lock_Context lock_context; - return ( (Watchdog_Control *) the_watchdog->Node.previous ); + _Watchdog_Set_CPU( the_watchdog, cpu ); + _Watchdog_Per_CPU_acquire_critical( cpu, &lock_context ); + _Watchdog_Insert( + &cpu->Watchdog.Header[ PER_CPU_WATCHDOG_ABSOLUTE ], + the_watchdog, + expire + ); + _Watchdog_Per_CPU_release_critical( cpu, &lock_context ); } -/** - * This routine returns a pointer to the first watchdog timer - * on the watchdog chain HEADER. - */ - -RTEMS_INLINE_ROUTINE Watchdog_Control *_Watchdog_First( - Watchdog_Header *header +RTEMS_INLINE_ROUTINE void _Watchdog_Per_CPU_remove( + Watchdog_Control *the_watchdog, + Per_CPU_Control *cpu, + Watchdog_Header *header ) { - - return ( (Watchdog_Control *) _Chain_First( &header->Watchdogs ) ); - + ISR_lock_Context lock_context; + + _Watchdog_Per_CPU_acquire_critical( cpu, &lock_context ); + _Watchdog_Remove( + header, + the_watchdog + ); + _Watchdog_Per_CPU_release_critical( cpu, &lock_context ); } -/** - * This routine returns a pointer to the last watchdog timer - * on the watchdog chain HEADER. - */ - -RTEMS_INLINE_ROUTINE Watchdog_Control *_Watchdog_Last( - Watchdog_Header *header +RTEMS_INLINE_ROUTINE void _Watchdog_Per_CPU_remove_relative( + Watchdog_Control *the_watchdog ) { - - return ( (Watchdog_Control *) _Chain_Last( &header->Watchdogs ) ); - + Per_CPU_Control *cpu; + + cpu = _Watchdog_Get_CPU( the_watchdog ); + _Watchdog_Per_CPU_remove( + the_watchdog, + cpu, + &cpu->Watchdog.Header[ PER_CPU_WATCHDOG_RELATIVE ] + ); } -RTEMS_INLINE_ROUTINE bool _Watchdog_Is_empty( - const Watchdog_Header *header +RTEMS_INLINE_ROUTINE void _Watchdog_Per_CPU_remove_absolute( + Watchdog_Control *the_watchdog ) { - return _Chain_Is_empty( &header->Watchdogs ); + Per_CPU_Control *cpu; + + cpu = _Watchdog_Get_CPU( the_watchdog ); + _Watchdog_Per_CPU_remove( + the_watchdog, + cpu, + &cpu->Watchdog.Header[ PER_CPU_WATCHDOG_ABSOLUTE ] + ); } -RTEMS_INLINE_ROUTINE void _Watchdog_Header_initialize( - Watchdog_Header *header +RTEMS_INLINE_ROUTINE void _Watchdog_Per_CPU_tickle_absolute( + Per_CPU_Control *cpu, + uint64_t now ) { - _ISR_lock_Initialize( &header->Lock, "Watchdog" ); - _Chain_Initialize_empty( &header->Watchdogs ); - _Chain_Initialize_empty( &header->Iterators ); + ISR_lock_Context lock_context; + + _ISR_lock_ISR_disable_and_acquire( &cpu->Watchdog.Lock, &lock_context ); + _Watchdog_Tickle( + &cpu->Watchdog.Header[ PER_CPU_WATCHDOG_ABSOLUTE ], + now, + &cpu->Watchdog.Lock, + &lock_context + ); } /** @} */ diff --git a/cpukit/score/src/condition.c b/cpukit/score/src/condition.c index 22c2a9b97c..420681955a 100644 --- a/cpukit/score/src/condition.c +++ b/cpukit/score/src/condition.c @@ -282,7 +282,7 @@ static int _Condition_Wake( struct _Condition_Control *_condition, int count ) next = _Chain_Next( node ); thread = THREAD_CHAIN_NODE_TO_THREAD( node ); - _Watchdog_Remove_ticks( &thread->Timer ); + _Thread_Timer_remove( thread ); _Thread_Unblock( thread ); node = next; diff --git a/cpukit/score/src/coretodset.c b/cpukit/score/src/coretodset.c index 3230179414..b2efc07115 100644 --- a/cpukit/score/src/coretodset.c +++ b/cpukit/score/src/coretodset.c @@ -26,30 +26,26 @@ void _TOD_Set_with_timestamp( const Timestamp_Control *tod_as_timestamp ) { - struct timespec ts; - uint32_t nanoseconds; - Watchdog_Interval seconds_next; - Watchdog_Interval seconds_now; - Watchdog_Header *header; + struct timespec tod_as_timespec; + uint64_t tod_as_ticks; + uint32_t cpu_count; + uint32_t cpu_index; - _Timestamp_To_timespec( tod_as_timestamp, &ts ); - nanoseconds = ts.tv_nsec; - seconds_next = ts.tv_sec; + _Timestamp_To_timespec( tod_as_timestamp, &tod_as_timespec ); _Thread_Disable_dispatch(); - seconds_now = _TOD_Seconds_since_epoch(); + _Timecounter_Set_clock( &tod_as_timespec ); - _Timecounter_Set_clock( &ts ); + tod_as_ticks = _Watchdog_Ticks_from_timespec( &tod_as_timespec ); + cpu_count = _SMP_Get_processor_count(); - header = &_Watchdog_Seconds_header; + for ( cpu_index = 0 ; cpu_index < cpu_count ; ++cpu_index ) { + Per_CPU_Control *cpu = _Per_CPU_Get_by_index( cpu_index ); - if ( seconds_next < seconds_now ) - _Watchdog_Adjust_backward( header, seconds_now - seconds_next ); - else - _Watchdog_Adjust_forward( header, seconds_next - seconds_now ); + _Watchdog_Per_CPU_tickle_absolute( cpu, tod_as_ticks ); + } - _TOD.seconds_trigger = nanoseconds; _TOD.is_set = true; _Thread_Enable_dispatch(); diff --git a/cpukit/score/src/coretodtickle.c b/cpukit/score/src/coretodtickle.c deleted file mode 100644 index 3d7c71e1c1..0000000000 --- a/cpukit/score/src/coretodtickle.c +++ /dev/null @@ -1,36 +0,0 @@ -/** - * @file - * - * @brief Increments time of day at each clock tick - * - * @ingroup ScoreTOD - */ - -/* COPYRIGHT (c) 1989-2014. - * On-Line Applications Research Corporation (OAR). - * - * The license and distribution terms for this file may be - * found in the file LICENSE in this distribution or at - * http://www.rtems.org/license/LICENSE. - */ - -#if HAVE_CONFIG_H -#include "config.h" -#endif - -#include <rtems/score/todimpl.h> -#include <rtems/score/watchdogimpl.h> -#include <rtems/config.h> - -void _TOD_Tickle_ticks( void ) -{ - /* Update the counter of ticks since boot */ - _Watchdog_Ticks_since_boot += 1; - - _TOD.seconds_trigger += rtems_configuration_get_nanoseconds_per_tick(); - if ( _TOD.seconds_trigger >= 1000000000UL ) { - _TOD.seconds_trigger -= 1000000000UL; - _Watchdog_Tickle_seconds(); - } -} - diff --git a/cpukit/score/src/kern_tc.c b/cpukit/score/src/kern_tc.c index e56c292ea3..316a16f05b 100644 --- a/cpukit/score/src/kern_tc.c +++ b/cpukit/score/src/kern_tc.c @@ -1971,6 +1971,7 @@ tc_ticktock(int cnt) return; count = 0; #else /* __rtems__ */ +#include <rtems/score/smp.h> void _Timecounter_Tick(void) { @@ -2021,7 +2022,7 @@ _Timecounter_Tick_simple(uint32_t delta, uint32_t offset, _Timecounter_Release(lock_context); - _Watchdog_Tick(_Per_CPU_Get()); + _Watchdog_Tick(_Per_CPU_Get_snapshot()); } #endif /* __rtems__ */ diff --git a/cpukit/score/src/smp.c b/cpukit/score/src/smp.c index 9d9507d1b9..85256b044c 100644 --- a/cpukit/score/src/smp.c +++ b/cpukit/score/src/smp.c @@ -87,6 +87,7 @@ void _SMP_Handler_initialize( void ) for ( cpu_index = 0 ; cpu_index < cpu_max; ++cpu_index ) { Per_CPU_Control *cpu = _Per_CPU_Get_by_index( cpu_index ); + _ISR_lock_Initialize( &cpu->Watchdog.Lock, "Watchdog" ); _SMP_ticket_lock_Initialize( &cpu->Lock ); _SMP_lock_Stats_initialize( &cpu->Lock_stats, "Per-CPU" ); } diff --git a/cpukit/score/src/threadinitialize.c b/cpukit/score/src/threadinitialize.c index a49406f160..0b5fd3a125 100644 --- a/cpukit/score/src/threadinitialize.c +++ b/cpukit/score/src/threadinitialize.c @@ -160,6 +160,10 @@ bool _Thread_Initialize( the_thread->Start.budget_algorithm = budget_algorithm; the_thread->Start.budget_callout = budget_callout; + _ISR_lock_Initialize( &the_thread->Timer.Lock, "Thread Timer" ); + the_thread->Timer.header = &cpu->Watchdog.Header[ PER_CPU_WATCHDOG_RELATIVE ]; + _Watchdog_Preinitialize( &the_thread->Timer.Watchdog, cpu ); + switch ( budget_algorithm ) { case THREAD_CPU_BUDGET_ALGORITHM_NONE: case THREAD_CPU_BUDGET_ALGORITHM_RESET_TIMESLICE: diff --git a/cpukit/score/src/threadqenqueue.c b/cpukit/score/src/threadqenqueue.c index 960783c74c..07618fc800 100644 --- a/cpukit/score/src/threadqenqueue.c +++ b/cpukit/score/src/threadqenqueue.c @@ -35,7 +35,7 @@ static void _Thread_queue_Unblock( Thread_Control *the_thread ) { - _Watchdog_Remove_ticks( &the_thread->Timer ); + _Thread_Timer_remove( the_thread ); _Thread_Unblock( the_thread ); #if defined(RTEMS_MULTIPROCESSING) @@ -84,8 +84,12 @@ void _Thread_queue_Enqueue_critical( */ if ( timeout != WATCHDOG_NO_TIMEOUT ) { _Thread_Wait_set_timeout_code( the_thread, timeout_code ); - _Watchdog_Initialize( &the_thread->Timer, _Thread_Timeout, 0, the_thread ); - _Watchdog_Insert_ticks( &the_thread->Timer, timeout ); + _Thread_Timer_insert_relative( + the_thread, + cpu_self, + _Thread_Timeout, + timeout + ); } success = _Thread_Wait_flags_try_change( diff --git a/cpukit/score/src/threadrestart.c b/cpukit/score/src/threadrestart.c index 03b1fba8ff..d366f97a0f 100644 --- a/cpukit/score/src/threadrestart.c +++ b/cpukit/score/src/threadrestart.c @@ -84,7 +84,7 @@ static void _Thread_Make_zombie( Thread_Control *the_thread ) _Thread_Set_state( the_thread, STATES_ZOMBIE ); _Thread_queue_Extract_with_proxy( the_thread ); - _Watchdog_Remove_ticks( &the_thread->Timer ); + _Thread_Timer_remove( the_thread ); _ISR_lock_ISR_disable_and_acquire( &zombies->Lock, &lock_context ); _Chain_Append_unprotected( &zombies->Chain, &the_thread->Object.Node ); @@ -191,7 +191,9 @@ static void _Thread_Start_life_change_for_executing( Thread_Control *executing ) { - _Assert( executing->Timer.state == WATCHDOG_INACTIVE ); + _Assert( + _Watchdog_Get_state( &executing->Timer.Watchdog ) == WATCHDOG_INACTIVE + ); _Assert( executing->current_state == STATES_READY || executing->current_state == STATES_SUSPENDED @@ -246,7 +248,9 @@ void _Thread_Life_action_handler( /* Someone deleted us in the mean-time */ _Thread_Start_life_change_for_executing( executing ); } else { - _Assert( executing->Timer.state == WATCHDOG_INACTIVE ); + _Assert( + _Watchdog_Get_state( &executing->Timer.Watchdog ) == WATCHDOG_INACTIVE + ); _Assert( executing->current_state == STATES_READY || executing->current_state == STATES_SUSPENDED @@ -274,7 +278,7 @@ static void _Thread_Start_life_change( _Thread_Set_state( the_thread, STATES_RESTARTING ); _Thread_queue_Extract_with_proxy( the_thread ); - _Watchdog_Remove_ticks( &the_thread->Timer ); + _Thread_Timer_remove( the_thread ); _Thread_Change_priority( the_thread, priority, diff --git a/cpukit/score/src/threadtimeout.c b/cpukit/score/src/threadtimeout.c index 8ecaebde06..59f6bd97f0 100644 --- a/cpukit/score/src/threadtimeout.c +++ b/cpukit/score/src/threadtimeout.c @@ -33,7 +33,7 @@ static void _Thread_Do_timeout( Thread_Control *the_thread ) _Thread_Lock_restore_default( the_thread ); } -void _Thread_Timeout( Objects_Id id, void *arg ) +void _Thread_Timeout( Watchdog_Control *watchdog ) { Thread_Control *the_thread; void *thread_lock; @@ -41,7 +41,7 @@ void _Thread_Timeout( Objects_Id id, void *arg ) Thread_Wait_flags wait_flags; bool unblock; - the_thread = arg; + the_thread = RTEMS_CONTAINER_OF( watchdog, Thread_Control, Timer.Watchdog ); thread_lock = _Thread_Lock_acquire( the_thread, &lock_context ); wait_flags = _Thread_Wait_flags_get( the_thread ); diff --git a/cpukit/score/src/watchdog.c b/cpukit/score/src/watchdog.c deleted file mode 100644 index 8d172fb8f9..0000000000 --- a/cpukit/score/src/watchdog.c +++ /dev/null @@ -1,36 +0,0 @@ -/** - * @file - * - * @brief Watchdog Handler Initialization - * @ingroup ScoreWatchdog - */ - -/* - * Watchdog Handler - * - * - * COPYRIGHT (c) 1989-1999. - * On-Line Applications Research Corporation (OAR). - * - * The license and distribution terms for this file may be - * found in the file LICENSE in this distribution or at - * http://www.rtems.org/license/LICENSE. - */ - -#if HAVE_CONFIG_H -#include "config.h" -#endif - -#include <rtems/score/watchdogimpl.h> - -Watchdog_Header _Watchdog_Ticks_header; - -Watchdog_Header _Watchdog_Seconds_header; - -void _Watchdog_Handler_initialization( void ) -{ - _Watchdog_Ticks_since_boot = 0; - - _Watchdog_Header_initialize( &_Watchdog_Ticks_header ); - _Watchdog_Header_initialize( &_Watchdog_Seconds_header ); -} diff --git a/cpukit/score/src/watchdogadjust.c b/cpukit/score/src/watchdogadjust.c deleted file mode 100644 index 32b5f7990e..0000000000 --- a/cpukit/score/src/watchdogadjust.c +++ /dev/null @@ -1,80 +0,0 @@ -/** - * @file - * - * @brief Watchdog Adjust - * @ingroup ScoreWatchdog - */ - -/* - * COPYRIGHT (c) 1989-1999. - * On-Line Applications Research Corporation (OAR). - * - * The license and distribution terms for this file may be - * found in the file LICENSE in this distribution or at - * http://www.rtems.org/license/LICENSE. - */ - -#if HAVE_CONFIG_H -#include "config.h" -#endif - -#include <rtems/score/watchdogimpl.h> - -void _Watchdog_Adjust_backward_locked( - Watchdog_Header *header, - Watchdog_Interval units -) -{ - if ( !_Watchdog_Is_empty( header ) ) { - _Watchdog_First( header )->delta_interval += units; - } -} - -void _Watchdog_Adjust_backward( - Watchdog_Header *header, - Watchdog_Interval units -) -{ - ISR_lock_Context lock_context; - - _Watchdog_Acquire( header, &lock_context ); - _Watchdog_Adjust_backward_locked( header, units ); - _Watchdog_Release( header, &lock_context ); -} - -void _Watchdog_Adjust_forward_locked( - Watchdog_Header *header, - Watchdog_Interval units, - ISR_lock_Context *lock_context -) -{ - while ( !_Watchdog_Is_empty( header ) && units > 0 ) { - Watchdog_Control *first = _Watchdog_First( header ); - - if ( units < first->delta_interval ) { - first->delta_interval -= units; - break; - } else { - units -= first->delta_interval; - first->delta_interval = 1; - - _Watchdog_Release( header, lock_context ); - - _Watchdog_Tickle( header ); - - _Watchdog_Acquire( header, lock_context ); - } - } -} - -void _Watchdog_Adjust_forward( - Watchdog_Header *header, - Watchdog_Interval units -) -{ - ISR_lock_Context lock_context; - - _Watchdog_Acquire( header, &lock_context ); - _Watchdog_Adjust_forward_locked( header, units, &lock_context ); - _Watchdog_Release( header, &lock_context ); -} diff --git a/cpukit/score/src/watchdoginsert.c b/cpukit/score/src/watchdoginsert.c index db15f55b0d..22fc7a5f76 100644 --- a/cpukit/score/src/watchdoginsert.c +++ b/cpukit/score/src/watchdoginsert.c @@ -1,17 +1,22 @@ /** - * @file + * @file * * @brief Watchdog Insert * @ingroup ScoreWatchdog */ - + /* - * COPYRIGHT (c) 1989-1999. - * On-Line Applications Research Corporation (OAR). + * Copyright (c) 2016 embedded brains GmbH. All rights reserved. + * + * embedded brains GmbH + * Dornierstr. 4 + * 82178 Puchheim + * Germany + * <rtems@embedded-brains.de> * - * The license and distribution terms for this file may be - * found in the file LICENSE in this distribution or at - * http://www.rtems.org/license/LICENSE. + * The license and distribution terms for this file may be + * found in the file LICENSE in this distribution or at + * http://www.rtems.org/license/LICENSE. */ #if HAVE_CONFIG_H @@ -20,106 +25,41 @@ #include <rtems/score/watchdogimpl.h> -static void _Watchdog_Insert_fixup( - Watchdog_Header *header, - Watchdog_Control *the_watchdog, - Watchdog_Interval delta, - Watchdog_Control *next_watchdog, - Watchdog_Interval delta_next -) -{ - const Chain_Node *iterator_tail; - Chain_Node *iterator_node; - - next_watchdog->delta_interval = delta_next - delta; - - iterator_node = _Chain_First( &header->Iterators ); - iterator_tail = _Chain_Immutable_tail( &header->Iterators ); - - while ( iterator_node != iterator_tail ) { - Watchdog_Iterator *iterator; - - iterator = (Watchdog_Iterator *) iterator_node; - - if ( iterator->current == &next_watchdog->Node ) { - iterator->current = &the_watchdog->Node; - } - - iterator_node = _Chain_Next( iterator_node ); - } -} - -void _Watchdog_Insert_locked( +void _Watchdog_Insert( Watchdog_Header *header, Watchdog_Control *the_watchdog, - ISR_lock_Context *lock_context + uint64_t expire ) { - if ( the_watchdog->state == WATCHDOG_INACTIVE ) { - Watchdog_Iterator iterator; - Chain_Node *current; - Chain_Node *next; - Watchdog_Interval delta; - - the_watchdog->state = WATCHDOG_BEING_INSERTED; - - _Chain_Append_unprotected( &header->Iterators, &iterator.Node ); - - delta = the_watchdog->initial; - current = _Chain_Head( &header->Watchdogs ); + RBTree_Node **link; + RBTree_Node *parent; + RBTree_Node *old_first; + RBTree_Node *new_first; - while ( - ( next = _Chain_Next( current ) ) != _Chain_Tail( &header->Watchdogs ) - ) { - Watchdog_Control *next_watchdog; - Watchdog_Interval delta_next; + _Assert( _Watchdog_Get_state( the_watchdog ) == WATCHDOG_INACTIVE ); - next_watchdog = (Watchdog_Control *) next; - delta_next = next_watchdog->delta_interval; + link = _RBTree_Root_reference( &header->Watchdogs ); + parent = NULL; + old_first = header->first; + new_first = &the_watchdog->Node.RBTree; - if ( delta < delta_next ) { - _Watchdog_Insert_fixup( - header, - the_watchdog, - delta, - next_watchdog, - delta_next - ); - break; - } + the_watchdog->expire = expire; - iterator.delta_interval = delta - delta_next; - iterator.current = next; + while ( *link != NULL ) { + Watchdog_Control *parent_watchdog; - _Watchdog_Flash( header, lock_context ); + parent = *link; + parent_watchdog = (Watchdog_Control *) parent; - if ( the_watchdog->state != WATCHDOG_BEING_INSERTED ) { - goto abort_insert; - } - - delta = iterator.delta_interval; - current = iterator.current; + if ( expire < parent_watchdog->expire ) { + link = _RBTree_Left_reference( parent ); + } else { + link = _RBTree_Right_reference( parent ); + new_first = old_first; } - - the_watchdog->delta_interval = delta; - the_watchdog->start_time = _Watchdog_Ticks_since_boot; - _Watchdog_Activate( the_watchdog ); - _Chain_Insert_unprotected( current, &the_watchdog->Node ); - -abort_insert: - - _Chain_Extract_unprotected( &iterator.Node ); } -} - -void _Watchdog_Insert( - Watchdog_Header *header, - Watchdog_Control *the_watchdog -) -{ - ISR_lock_Context lock_context; - _Watchdog_Acquire( header, &lock_context ); - _Watchdog_Insert_locked( header, the_watchdog, &lock_context ); - _Watchdog_Release( header, &lock_context ); + header->first = new_first; + _RBTree_Add_child( &the_watchdog->Node.RBTree, parent, link ); + _RBTree_Insert_color( &header->Watchdogs, &the_watchdog->Node.RBTree ); } diff --git a/cpukit/score/src/watchdogremove.c b/cpukit/score/src/watchdogremove.c index 2aa72a4e75..2605a67fa4 100644 --- a/cpukit/score/src/watchdogremove.c +++ b/cpukit/score/src/watchdogremove.c @@ -1,17 +1,22 @@ /** * @file * - * @brief Remove Watchdog from List + * @brief Remove Watchdog * @ingroup ScoreWatchdog */ /* - * COPYRIGHT (c) 1989-1999. - * On-Line Applications Research Corporation (OAR). + * Copyright (c) 2016 embedded brains GmbH. All rights reserved. * - * The license and distribution terms for this file may be - * found in the file LICENSE in this distribution or at - * http://www.rtems.org/license/LICENSE. + * embedded brains GmbH + * Dornierstr. 4 + * 82178 Puchheim + * Germany + * <rtems@embedded-brains.de> + * + * The license and distribution terms for this file may be + * found in the file LICENSE in this distribution or at + * http://www.rtems.org/license/LICENSE. */ #if HAVE_CONFIG_H @@ -19,161 +24,18 @@ #endif #include <rtems/score/watchdogimpl.h> -#include <rtems/score/assert.h> - -static void _Watchdog_Remove_it( - Watchdog_Header *header, - Watchdog_Control *the_watchdog -) -{ - Chain_Node *next; - Watchdog_Interval delta; - const Chain_Node *iterator_tail; - Chain_Node *iterator_node; - - _Assert( the_watchdog->state == WATCHDOG_ACTIVE ); - - the_watchdog->state = WATCHDOG_INACTIVE; - the_watchdog->stop_time = _Watchdog_Ticks_since_boot; - - next = _Chain_Next( &the_watchdog->Node ); - delta = the_watchdog->delta_interval; - - if ( next != _Chain_Tail( &header->Watchdogs ) ) { - Watchdog_Control *next_watchdog; - - next_watchdog = (Watchdog_Control *) next; - next_watchdog->delta_interval += delta; - } - - _Chain_Extract_unprotected( &the_watchdog->Node ); - - iterator_node = _Chain_First( &header->Iterators ); - iterator_tail = _Chain_Immutable_tail( &header->Iterators ); - - while ( iterator_node != iterator_tail ) { - Watchdog_Iterator *iterator; - - iterator = (Watchdog_Iterator *) iterator_node; - - if ( iterator->current == next ) { - iterator->delta_interval += delta; - } - - if ( iterator->current == &the_watchdog->Node ) { - Chain_Node *previous = _Chain_Previous( &the_watchdog->Node ); - - iterator->current = previous; - - if ( previous != _Chain_Head( &header->Watchdogs ) ) { - Watchdog_Control *previous_watchdog; - - previous_watchdog = (Watchdog_Control *) previous; - iterator->delta_interval += previous_watchdog->delta_interval; - } - } - - iterator_node = _Chain_Next( iterator_node ); - } -} -Watchdog_States _Watchdog_Remove( +void _Watchdog_Remove( Watchdog_Header *header, Watchdog_Control *the_watchdog ) { - ISR_lock_Context lock_context; - Watchdog_States previous_state; - Watchdog_Interval now; - - _Watchdog_Acquire( header, &lock_context ); - previous_state = the_watchdog->state; - switch ( previous_state ) { - case WATCHDOG_INACTIVE: - break; - - case WATCHDOG_BEING_INSERTED: - - /* - * It is not actually on the chain so just change the state and - * the Insert operation we interrupted will be aborted. - */ - the_watchdog->state = WATCHDOG_INACTIVE; - now = _Watchdog_Ticks_since_boot; - the_watchdog->start_time = now; - the_watchdog->stop_time = now; - break; - - case WATCHDOG_ACTIVE: - _Watchdog_Remove_it( header, the_watchdog ); - break; - } - - _Watchdog_Release( header, &lock_context ); - return( previous_state ); -} - -void _Watchdog_Tickle( - Watchdog_Header *header -) -{ - ISR_lock_Context lock_context; - - _Watchdog_Acquire( header, &lock_context ); - - if ( !_Watchdog_Is_empty( header ) ) { - Watchdog_Control *first; - Watchdog_Interval delta; - - first = _Watchdog_First( header ); - delta = first->delta_interval; - - /* - * Although it is forbidden to insert watchdogs with a delta interval of - * zero it is possible to observe watchdogs with a delta interval of zero - * at this point. For example lets have a watchdog chain of one watchdog - * with a delta interval of one and insert a new one with an initial value - * of one. At the start of the insert procedure it will advance one step - * and reduce its delta interval by one yielding zero. Now a tick happens. - * This will remove the watchdog on the chain and update the insert - * iterator. Now the insert operation continues and will insert the new - * watchdog with a delta interval of zero. - */ - if ( delta > 0 ) { - --delta; - first->delta_interval = delta; + if ( _Watchdog_Is_scheduled( the_watchdog ) ) { + if ( header->first == &the_watchdog->Node.RBTree ) { + _Watchdog_Next_first( header, the_watchdog ); } - while ( delta == 0 ) { - bool run; - Watchdog_Service_routine_entry routine; - Objects_Id id; - void *user_data; - - run = ( first->state == WATCHDOG_ACTIVE ); - - _Watchdog_Remove_it( header, first ); - - routine = first->routine; - id = first->id; - user_data = first->user_data; - - _Watchdog_Release( header, &lock_context ); - - if ( run ) { - (*routine)( id, user_data ); - } - - _Watchdog_Acquire( header, &lock_context ); - - if ( _Watchdog_Is_empty( header ) ) { - break; - } - - first = _Watchdog_First( header ); - delta = first->delta_interval; - } + _RBTree_Extract( &header->Watchdogs, &the_watchdog->Node.RBTree ); + _Watchdog_Set_state( the_watchdog, WATCHDOG_INACTIVE ); } - - _Watchdog_Release( header, &lock_context ); } diff --git a/cpukit/score/src/watchdogtick.c b/cpukit/score/src/watchdogtick.c index e89c088350..ab7eadcf1d 100644 --- a/cpukit/score/src/watchdogtick.c +++ b/cpukit/score/src/watchdogtick.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2015 embedded brains GmbH. All rights reserved. + * Copyright (c) 2015, 2016 embedded brains GmbH. All rights reserved. * * embedded brains GmbH * Dornierstr. 4 @@ -12,25 +12,81 @@ * http://www.rtems.org/license/LICENSE. */ -#include <rtems/score/assert.h> +#if HAVE_CONFIG_H +#include "config.h" +#endif + +#include <rtems/score/watchdogimpl.h> #include <rtems/score/schedulerimpl.h> #include <rtems/score/threaddispatch.h> -#include <rtems/score/todimpl.h> -#include <rtems/score/watchdogimpl.h> +#include <rtems/score/timecounter.h> -#if HAVE_CONFIG_H -#include "config.h" +void _Watchdog_Do_tickle( + Watchdog_Header *header, + uint64_t now, +#ifdef RTEMS_SMP + ISR_lock_Control *lock, #endif + ISR_lock_Context *lock_context +) +{ + while ( true ) { + Watchdog_Control *the_watchdog; + + the_watchdog = (Watchdog_Control *) header->first; + + if ( the_watchdog == NULL ) { + break; + } + + if ( the_watchdog->expire <= now ) { + Watchdog_Service_routine_entry routine; + + _Watchdog_Next_first( header, the_watchdog ); + _RBTree_Extract( &header->Watchdogs, &the_watchdog->Node.RBTree ); + _Watchdog_Set_state( the_watchdog, WATCHDOG_INACTIVE ); + routine = the_watchdog->routine; + + _ISR_lock_Release_and_ISR_enable( lock, lock_context ); + ( *routine )( the_watchdog ); + _ISR_lock_ISR_disable_and_acquire( lock, lock_context ); + } else { + break; + } + } + + _ISR_lock_Release_and_ISR_enable( lock, lock_context ); +} void _Watchdog_Tick( Per_CPU_Control *cpu ) { - _Assert( !_Thread_Dispatch_is_enabled() ); + ISR_lock_Context lock_context; + uint64_t ticks; + struct timespec now; if ( _Per_CPU_Is_boot_processor( cpu ) ) { - _TOD_Tickle_ticks(); + ++_Watchdog_Ticks_since_boot; + } - _Watchdog_Tickle_ticks(); + _ISR_lock_ISR_disable_and_acquire( &cpu->Watchdog.Lock, &lock_context ); - _Scheduler_Tick(); - } + ticks = cpu->Watchdog.ticks; + _Assert( ticks < UINT64_MAX ); + ++ticks; + cpu->Watchdog.ticks = ticks; + + _Watchdog_Tickle( + &cpu->Watchdog.Header[ PER_CPU_WATCHDOG_RELATIVE ], + ticks, + &cpu->Watchdog.Lock, + &lock_context + ); + + _Timecounter_Getnanotime( &now ); + _Watchdog_Per_CPU_tickle_absolute( + cpu, + _Watchdog_Ticks_from_timespec( &now ) + ); + + _Scheduler_Tick( cpu ); } diff --git a/testsuites/psxtests/psx04/init.c b/testsuites/psxtests/psx04/init.c index ff3bb96e13..945da76a17 100644 --- a/testsuites/psxtests/psx04/init.c +++ b/testsuites/psxtests/psx04/init.c @@ -281,7 +281,12 @@ void *POSIX_Init( puts( "Init: Wait 4 seconds for alarm" ); remaining = sleep( 4 ); printf( "Init: %d seconds left in sleep\n", remaining ); - rtems_test_assert( remaining == 2 ); + + /* + * sleep() uses nanosleep() internally which discards the nanoseconds part, + * e.g. 1.99s -> 1s + */ + rtems_test_assert( remaining == 1 || remaining == 2 ); /* test SIG_SETMASK case and returning oset of pthread_sigmask */ diff --git a/testsuites/smptests/Makefile.am b/testsuites/smptests/Makefile.am index 92f45286e5..610f3137c4 100644 --- a/testsuites/smptests/Makefile.am +++ b/testsuites/smptests/Makefile.am @@ -14,6 +14,7 @@ SUBDIRS += smpatomic01 SUBDIRS += smpcache01 SUBDIRS += smpcapture01 SUBDIRS += smpcapture02 +SUBDIRS += smpclock01 SUBDIRS += smpfatal01 SUBDIRS += smpfatal02 SUBDIRS += smpfatal03 diff --git a/testsuites/smptests/configure.ac b/testsuites/smptests/configure.ac index 27e8f9c95a..a89b796afe 100644 --- a/testsuites/smptests/configure.ac +++ b/testsuites/smptests/configure.ac @@ -69,6 +69,7 @@ smpatomic01/Makefile smpcache01/Makefile smpcapture01/Makefile smpcapture02/Makefile +smpclock01/Makefile smpfatal01/Makefile smpfatal02/Makefile smpfatal03/Makefile diff --git a/testsuites/smptests/smpclock01/Makefile.am b/testsuites/smptests/smpclock01/Makefile.am new file mode 100644 index 0000000000..49e274b833 --- /dev/null +++ b/testsuites/smptests/smpclock01/Makefile.am @@ -0,0 +1,20 @@ +rtems_tests_PROGRAMS = smpclock01 +smpclock01_SOURCES = init.c +smpclock01_SOURCES += ../../support/src/spin.c + +dist_rtems_tests_DATA = smpclock01.scn smpclock01.doc + +include $(RTEMS_ROOT)/make/custom/@RTEMS_BSP@.cfg +include $(top_srcdir)/../automake/compile.am +include $(top_srcdir)/../automake/leaf.am + +AM_CPPFLAGS += -I$(top_srcdir)/../support/include + +LINK_OBJS = $(smpclock01_OBJECTS) +LINK_LIBS = $(smpclock01_LDLIBS) + +smpclock01$(EXEEXT): $(smpclock01_OBJECTS) $(smpclock01_DEPENDENCIES) + @rm -f smpclock01$(EXEEXT) + $(make-exe) + +include $(top_srcdir)/../automake/local.am diff --git a/testsuites/smptests/smpclock01/init.c b/testsuites/smptests/smpclock01/init.c new file mode 100644 index 0000000000..36016ef680 --- /dev/null +++ b/testsuites/smptests/smpclock01/init.c @@ -0,0 +1,206 @@ +/* + * Copyright (c) 2016 embedded brains GmbH. All rights reserved. + * + * embedded brains GmbH + * Dornierstr. 4 + * 82178 Puchheim + * Germany + * <rtems@embedded-brains.de> + * + * The license and distribution terms for this file may be + * found in the file LICENSE in this distribution or at + * http://www.rtems.org/license/LICENSE. + */ + +#ifdef HAVE_CONFIG_H + #include "config.h" +#endif + +#include "tmacros.h" + +#include <rtems.h> +#include <rtems/libcsupport.h> +#include <rtems/score/percpu.h> +#include <rtems/score/smpbarrier.h> + +#include <test_support.h> + +#define CPU_COUNT 2 + +#define SCHEDULER_A rtems_build_name(' ', ' ', ' ', 'A') + +#define SCHEDULER_B rtems_build_name(' ', ' ', ' ', 'B') + +const char rtems_test_name[] = "SMPCLOCK 1"; + +typedef struct { + SMP_barrier_Control barrier; + SMP_barrier_State delay_barrier_state; + SMP_barrier_State timer_barrier_state; +} test_context; + +static test_context test_instance = { + .barrier = SMP_BARRIER_CONTROL_INITIALIZER, + .delay_barrier_state = SMP_BARRIER_STATE_INITIALIZER, + .timer_barrier_state = SMP_BARRIER_STATE_INITIALIZER +}; + +static void wait(test_context *ctx, SMP_barrier_State *bs) +{ + _SMP_barrier_Wait(&ctx->barrier, bs, CPU_COUNT); +} + +static void timer_isr(rtems_id id, void *arg) +{ + test_context *ctx = arg; + + /* (B) */ + wait(ctx, &ctx->timer_barrier_state); +} + +static void timer_task(rtems_task_argument arg) +{ + test_context *ctx = (test_context *) arg; + rtems_status_code sc; + rtems_id timer_id; + + rtems_test_assert(rtems_get_current_processor() == 1); + + sc = rtems_timer_create(SCHEDULER_B, &timer_id); + rtems_test_assert(sc == RTEMS_SUCCESSFUL); + + /* (A) */ + wait(ctx, &ctx->timer_barrier_state); + + sc = rtems_timer_fire_after(timer_id, 1, timer_isr, ctx); + rtems_test_assert(sc == RTEMS_SUCCESSFUL); + + sc = rtems_task_wake_after(1); + rtems_test_assert(sc == RTEMS_SUCCESSFUL); + + sc = rtems_timer_delete(timer_id); + rtems_test_assert(sc == RTEMS_SUCCESSFUL); + + /* (C) */ + wait(ctx, &ctx->timer_barrier_state); + + while (true) { + /* Wait for deletion */ + } +} + +static void delay_clock_tick(test_context *ctx) +{ + rtems_interrupt_level level; + const Per_CPU_Control *cpu_self = _Per_CPU_Get_by_index(0); + const Per_CPU_Control *cpu_other = _Per_CPU_Get_by_index(1); + uint64_t ticks; + + rtems_test_assert(rtems_get_current_processor() == 0); + + rtems_test_spin_until_next_tick(); + ticks = cpu_self->Watchdog.ticks; + + rtems_interrupt_local_disable(level); + + /* (A) */ + wait(ctx, &ctx->delay_barrier_state); + + /* (B) */ + wait(ctx, &ctx->delay_barrier_state); + + rtems_test_assert(cpu_self->Watchdog.ticks == ticks); + rtems_test_assert(cpu_other->Watchdog.ticks == ticks + 1); + + rtems_interrupt_local_enable(level); + + rtems_test_assert(cpu_self->Watchdog.ticks == ticks + 1); + rtems_test_assert(cpu_other->Watchdog.ticks == ticks + 1); + + /* (C) */ + wait(ctx, &ctx->delay_barrier_state); +} + +static void test(void) +{ + test_context *ctx = &test_instance; + rtems_status_code sc; + rtems_id scheduler_b_id; + rtems_id task_id; + + sc = rtems_scheduler_ident(SCHEDULER_B, &scheduler_b_id); + rtems_test_assert(sc == RTEMS_SUCCESSFUL); + + sc = rtems_task_create( + SCHEDULER_B, + 1, + RTEMS_MINIMUM_STACK_SIZE, + RTEMS_DEFAULT_MODES, + RTEMS_DEFAULT_ATTRIBUTES, + &task_id + ); + rtems_test_assert(sc == RTEMS_SUCCESSFUL); + + sc = rtems_task_set_scheduler(task_id, scheduler_b_id); + rtems_test_assert(sc == RTEMS_SUCCESSFUL); + + sc = rtems_task_start(task_id, timer_task, (rtems_task_argument) ctx); + rtems_test_assert(sc == RTEMS_SUCCESSFUL); + + delay_clock_tick(ctx); + + sc = rtems_task_delete(task_id); + rtems_test_assert(sc == RTEMS_SUCCESSFUL); +} + +static void Init(rtems_task_argument arg) +{ + rtems_resource_snapshot snapshot; + + TEST_BEGIN(); + + rtems_resource_snapshot_take(&snapshot); + + if (rtems_get_processor_count() == CPU_COUNT) { + test(); + } + + rtems_test_assert(rtems_resource_snapshot_check(&snapshot)); + + TEST_END(); + rtems_test_exit(0); +} + +#define CONFIGURE_APPLICATION_NEEDS_CLOCK_DRIVER +#define CONFIGURE_APPLICATION_NEEDS_CONSOLE_DRIVER + +#define CONFIGURE_SMP_APPLICATION + +#define CONFIGURE_SMP_MAXIMUM_PROCESSORS CPU_COUNT + +#define CONFIGURE_SCHEDULER_SIMPLE_SMP + +#include <rtems/scheduler.h> + +RTEMS_SCHEDULER_CONTEXT_SIMPLE_SMP(a); +RTEMS_SCHEDULER_CONTEXT_SIMPLE_SMP(b); + +#define CONFIGURE_SCHEDULER_CONTROLS \ + RTEMS_SCHEDULER_CONTROL_SIMPLE_SMP(a, SCHEDULER_A), \ + RTEMS_SCHEDULER_CONTROL_SIMPLE_SMP(b, SCHEDULER_B) + +#define CONFIGURE_SMP_SCHEDULER_ASSIGNMENTS \ + RTEMS_SCHEDULER_ASSIGN(0, RTEMS_SCHEDULER_ASSIGN_PROCESSOR_MANDATORY), \ + RTEMS_SCHEDULER_ASSIGN(1, RTEMS_SCHEDULER_ASSIGN_PROCESSOR_OPTIONAL) + +#define CONFIGURE_MAXIMUM_TASKS CPU_COUNT + +#define CONFIGURE_MAXIMUM_TIMERS 1 + +#define CONFIGURE_INITIAL_EXTENSIONS RTEMS_TEST_INITIAL_EXTENSION + +#define CONFIGURE_RTEMS_INIT_TASKS_TABLE + +#define CONFIGURE_INIT + +#include <rtems/confdefs.h> diff --git a/testsuites/smptests/smpclock01/smpclock01.doc b/testsuites/smptests/smpclock01/smpclock01.doc new file mode 100644 index 0000000000..130644a60d --- /dev/null +++ b/testsuites/smptests/smpclock01/smpclock01.doc @@ -0,0 +1,11 @@ +This file describes the directives and concepts tested by this test set. + +test set name: smpclock01 + +directives: + + - Clock driver interrupt + +concepts: + + - Ensures that the clock interrupt is distributed to all online processors. diff --git a/testsuites/smptests/smpclock01/smpclock01.scn b/testsuites/smptests/smpclock01/smpclock01.scn new file mode 100644 index 0000000000..192ed83471 --- /dev/null +++ b/testsuites/smptests/smpclock01/smpclock01.scn @@ -0,0 +1,2 @@ +*** BEGIN OF TEST SMPCLOCK 1 *** +*** END OF TEST SMPCLOCK 1 *** diff --git a/testsuites/smptests/smpwakeafter01/smpwakeafter01.scn b/testsuites/smptests/smpwakeafter01/smpwakeafter01.scn index 9bbb558421..7fa203d813 100644 --- a/testsuites/smptests/smpwakeafter01/smpwakeafter01.scn +++ b/testsuites/smptests/smpwakeafter01/smpwakeafter01.scn @@ -9,36 +9,196 @@ 3 seconds remaining 2 seconds remaining 1 seconds remaining -counts[0][0] = 15479 -counts[0][1] = 17039 -counts[0][2] = 12389 -counts[0][3] = 8077 -counts[0][4] = 3 -counts[0][5] = 2431 -counts[0][6] = 2630 -counts[0][7] = 2128 -counts[1][0] = 15461 -counts[1][1] = 16813 -counts[1][2] = 12248 -counts[1][3] = 7483 -counts[1][4] = 5499 -counts[1][5] = 3170 -counts[1][6] = 2549 -counts[1][7] = 1748 -counts[2][0] = 71 -counts[2][1] = 17068 -counts[2][2] = 7661 -counts[2][3] = 8190 -counts[2][4] = 5513 -counts[2][5] = 3864 -counts[2][6] = 1454 -counts[2][7] = 1993 -counts[3][0] = 14511 -counts[3][1] = 16115 -counts[3][2] = 12561 -counts[3][3] = 7281 -counts[3][4] = 5507 -counts[3][5] = 3828 -counts[3][6] = 2687 -counts[3][7] = 1278 +counts[0][0] = 10013 +counts[0][1] = 5007 +counts[0][2] = 3339 +counts[0][3] = 2004 +counts[0][4] = 1432 +counts[0][5] = 912 +counts[0][6] = 771 +counts[0][7] = 590 +counts[1][0] = 10027 +counts[1][1] = 5015 +counts[1][2] = 3344 +counts[1][3] = 2007 +counts[1][4] = 1434 +counts[1][5] = 913 +counts[1][6] = 773 +counts[1][7] = 591 +counts[2][0] = 10041 +counts[2][1] = 5022 +counts[2][2] = 3349 +counts[2][3] = 2010 +counts[2][4] = 1436 +counts[2][5] = 914 +counts[2][6] = 774 +counts[2][7] = 592 +counts[3][0] = 10055 +counts[3][1] = 5029 +counts[3][2] = 3353 +counts[3][3] = 2013 +counts[3][4] = 1438 +counts[3][5] = 915 +counts[3][6] = 775 +counts[3][7] = 593 +counts[4][0] = 10070 +counts[4][1] = 5036 +counts[4][2] = 3358 +counts[4][3] = 2015 +counts[4][4] = 1440 +counts[4][5] = 917 +counts[4][6] = 776 +counts[4][7] = 594 +counts[5][0] = 10084 +counts[5][1] = 5043 +counts[5][2] = 3363 +counts[5][3] = 2018 +counts[5][4] = 1442 +counts[5][5] = 918 +counts[5][6] = 777 +counts[5][7] = 594 +counts[6][0] = 10098 +counts[6][1] = 5050 +counts[6][2] = 3368 +counts[6][3] = 2021 +counts[6][4] = 1444 +counts[6][5] = 919 +counts[6][6] = 778 +counts[6][7] = 595 +counts[7][0] = 10113 +counts[7][1] = 5058 +counts[7][2] = 3373 +counts[7][3] = 2024 +counts[7][4] = 1446 +counts[7][5] = 921 +counts[7][6] = 779 +counts[7][7] = 596 +counts[8][0] = 10127 +counts[8][1] = 5065 +counts[8][2] = 3377 +counts[8][3] = 2027 +counts[8][4] = 1448 +counts[8][5] = 922 +counts[8][6] = 780 +counts[8][7] = 597 +counts[9][0] = 10142 +counts[9][1] = 5072 +counts[9][2] = 3382 +counts[9][3] = 2030 +counts[9][4] = 1450 +counts[9][5] = 923 +counts[9][6] = 781 +counts[9][7] = 598 +counts[10][0] = 10156 +counts[10][1] = 5079 +counts[10][2] = 3387 +counts[10][3] = 2033 +counts[10][4] = 1452 +counts[10][5] = 925 +counts[10][6] = 783 +counts[10][7] = 599 +counts[11][0] = 10170 +counts[11][1] = 5086 +counts[11][2] = 3392 +counts[11][3] = 2036 +counts[11][4] = 1454 +counts[11][5] = 926 +counts[11][6] = 784 +counts[11][7] = 599 +counts[12][0] = 10185 +counts[12][1] = 5094 +counts[12][2] = 3397 +counts[12][3] = 2039 +counts[12][4] = 1457 +counts[12][5] = 927 +counts[12][6] = 785 +counts[12][7] = 600 +counts[13][0] = 10200 +counts[13][1] = 5101 +counts[13][2] = 3402 +counts[13][3] = 2042 +counts[13][4] = 1459 +counts[13][5] = 929 +counts[13][6] = 786 +counts[13][7] = 601 +counts[14][0] = 10215 +counts[14][1] = 5109 +counts[14][2] = 3407 +counts[14][3] = 2045 +counts[14][4] = 1461 +counts[14][5] = 930 +counts[14][6] = 787 +counts[14][7] = 602 +counts[15][0] = 10230 +counts[15][1] = 5116 +counts[15][2] = 3412 +counts[15][3] = 2048 +counts[15][4] = 1463 +counts[15][5] = 931 +counts[15][6] = 788 +counts[15][7] = 603 +counts[16][0] = 10245 +counts[16][1] = 5124 +counts[16][2] = 3417 +counts[16][3] = 2051 +counts[16][4] = 1465 +counts[16][5] = 933 +counts[16][6] = 789 +counts[16][7] = 604 +counts[17][0] = 10260 +counts[17][1] = 5131 +counts[17][2] = 3422 +counts[17][3] = 2054 +counts[17][4] = 1467 +counts[17][5] = 934 +counts[17][6] = 791 +counts[17][7] = 605 +counts[18][0] = 10275 +counts[18][1] = 5139 +counts[18][2] = 3427 +counts[18][3] = 2057 +counts[18][4] = 1469 +counts[18][5] = 935 +counts[18][6] = 792 +counts[18][7] = 606 +counts[19][0] = 10290 +counts[19][1] = 5146 +counts[19][2] = 3432 +counts[19][3] = 2060 +counts[19][4] = 1472 +counts[19][5] = 937 +counts[19][6] = 793 +counts[19][7] = 607 +counts[20][0] = 10305 +counts[20][1] = 5154 +counts[20][2] = 3437 +counts[20][3] = 2063 +counts[20][4] = 1474 +counts[20][5] = 938 +counts[20][6] = 794 +counts[20][7] = 607 +counts[21][0] = 10320 +counts[21][1] = 5161 +counts[21][2] = 3442 +counts[21][3] = 2066 +counts[21][4] = 1476 +counts[21][5] = 940 +counts[21][6] = 795 +counts[21][7] = 608 +counts[22][0] = 10335 +counts[22][1] = 5169 +counts[22][2] = 3447 +counts[22][3] = 2069 +counts[22][4] = 1478 +counts[22][5] = 941 +counts[22][6] = 796 +counts[22][7] = 609 +counts[23][0] = 10350 +counts[23][1] = 5176 +counts[23][2] = 3452 +counts[23][3] = 2072 +counts[23][4] = 1480 +counts[23][5] = 942 +counts[23][6] = 798 +counts[23][7] = 610 *** END OF TEST SMPWAKEAFTER 1 *** diff --git a/testsuites/sptests/Makefile.am b/testsuites/sptests/Makefile.am index c5210a5ab9..43f3d82794 100644 --- a/testsuites/sptests/Makefile.am +++ b/testsuites/sptests/Makefile.am @@ -25,7 +25,7 @@ _SUBDIRS = \ spintrcritical05 spintrcritical06 spintrcritical07 spintrcritical08 \ spintrcritical09 spintrcritical10 spintrcritical11 spintrcritical12 \ spintrcritical13 spintrcritical14 spintrcritical15 spintrcritical16 \ - spintrcritical17 spintrcritical18 spmkdir spmountmgr01 spheapprot \ + spintrcritical18 spmkdir spmountmgr01 spheapprot \ sppagesize spsem01 spsem02 spsimplesched01 spsimplesched02 \ spsimplesched03 spnsext01 spedfsched01 spedfsched02 spedfsched03 \ spcbssched01 spcbssched02 spcbssched03 spqreslib sptimespec01 \ @@ -77,6 +77,7 @@ _SUBDIRS += speventsystem01 _SUBDIRS += spinternalerror01 _SUBDIRS += spinternalerror02 _SUBDIRS += sptimer_err01 sptimer_err02 +_SUBDIRS += sptimerserver01 _SUBDIRS += spclock_err02 if HAS_CPUSET diff --git a/testsuites/sptests/configure.ac b/testsuites/sptests/configure.ac index e46f6fa5a5..eeebc91171 100644 --- a/testsuites/sptests/configure.ac +++ b/testsuites/sptests/configure.ac @@ -46,6 +46,7 @@ AM_CONDITIONAL(HAS_SMP,test "$rtems_cv_RTEMS_SMP" = "yes") # Explicitly list all Makefiles here AC_CONFIG_FILES([Makefile +sptimerserver01/Makefile spsysinit01/Makefile splinkersets01/Makefile spstdthreads01/Makefile @@ -216,7 +217,6 @@ spintrcritical13/Makefile spintrcritical14/Makefile spintrcritical15/Makefile spintrcritical16/Makefile -spintrcritical17/Makefile spheapprot/Makefile spmkdir/Makefile spmountmgr01/Makefile diff --git a/testsuites/sptests/sp31/task1.c b/testsuites/sptests/sp31/task1.c index f4e526a027..c3f0ae13fc 100644 --- a/testsuites/sptests/sp31/task1.c +++ b/testsuites/sptests/sp31/task1.c @@ -40,14 +40,6 @@ static rtems_timer_service_routine Do_nothing( /* Do nothing */ } -static Watchdog_Interval schedule_time( void ) -{ - const Watchdog_Control *watchdog = - &_Timer_server->Interval_watchdogs.System_watchdog; - - return watchdog->initial + watchdog->start_time; -} - rtems_task Task_1( rtems_task_argument argument ) @@ -119,10 +111,6 @@ rtems_task Task_1( "Timer 1 scheduled for %" PRIdWatchdog_Interval " ticks since boot\n", info.start_time + info.initial ); - printf( - "Timer Server scheduled for %" PRIdWatchdog_Interval " ticks since boot\n", - schedule_time() - ); puts( "TA1 - rtems_task_wake_after - 1 second" ); status = rtems_task_wake_after( 1 * rtems_clock_get_ticks_per_second() ); @@ -139,11 +127,6 @@ rtems_task Task_1( "Timer 1 scheduled for %" PRIdWatchdog_Interval " ticks since boot\n", info.start_time + info.initial ); - printf( - "Timer Server scheduled for %" PRIdWatchdog_Interval " ticks since boot\n", - schedule_time() - ); - rtems_test_assert( (info.start_time + info.initial) == schedule_time() ); puts( "TA1 - rtems_task_wake_after - 1 second" ); status = rtems_task_wake_after( 1 * rtems_clock_get_ticks_per_second() ); @@ -160,11 +143,6 @@ rtems_task Task_1( "Timer 1 scheduled for %" PRIdWatchdog_Interval " ticks since boot\n", info.start_time + info.initial ); - printf( - "Timer Server scheduled for %" PRIdWatchdog_Interval " ticks since boot\n", - schedule_time() - ); - rtems_test_assert( (info.start_time + info.initial) == schedule_time() ); puts( "TA1 - rtems_timer_cancel - timer 1" ); status = rtems_timer_cancel( tmid ); diff --git a/testsuites/sptests/spintrcritical08/init.c b/testsuites/sptests/spintrcritical08/init.c index f375cd49f3..3610e65b96 100644 --- a/testsuites/sptests/spintrcritical08/init.c +++ b/testsuites/sptests/spintrcritical08/init.c @@ -46,23 +46,21 @@ static rtems_timer_service_routine test_release_from_isr( void *arg ) { - Watchdog_Header *header = &_Watchdog_Ticks_header; + Per_CPU_Control *cpu = _Per_CPU_Get(); + Watchdog_Header *header = &cpu->Watchdog.Header[ PER_CPU_WATCHDOG_RELATIVE ]; + Watchdog_Control *watchdog = (Watchdog_Control *) header->first; - if ( !_Watchdog_Is_empty( header ) ) { - Watchdog_Control *watchdog = _Watchdog_First( header ); + if ( + watchdog != NULL + && watchdog->expire == cpu->Watchdog.ticks + && watchdog->routine == _Rate_monotonic_Timeout + ) { + _Watchdog_Per_CPU_remove_relative( watchdog ); - if ( - watchdog->delta_interval == 0 - && watchdog->routine == _Rate_monotonic_Timeout - ) { - Watchdog_States state = _Watchdog_Remove_ticks( watchdog ); + (*watchdog->routine)( watchdog ); - rtems_test_assert( state == WATCHDOG_ACTIVE ); - (*watchdog->routine)( watchdog->id, watchdog->user_data ); - - if ( getState() == RATE_MONOTONIC_EXPIRED_WHILE_BLOCKING ) { - case_hit = true; - } + if ( getState() == RATE_MONOTONIC_EXPIRED_WHILE_BLOCKING ) { + case_hit = true; } } } diff --git a/testsuites/sptests/spintrcritical09/init.c b/testsuites/sptests/spintrcritical09/init.c index cc119e88c1..44eccc7821 100644 --- a/testsuites/sptests/spintrcritical09/init.c +++ b/testsuites/sptests/spintrcritical09/init.c @@ -15,6 +15,7 @@ #include <intrcritical.h> #include <rtems/score/threadimpl.h> +#include <rtems/score/threadimpl.h> #include <rtems/score/watchdogimpl.h> const char rtems_test_name[] = "SPINTRCRITICAL 9"; @@ -37,23 +38,21 @@ static rtems_timer_service_routine test_release_from_isr( void *arg ) { - Watchdog_Header *header = &_Watchdog_Ticks_header; - - if ( !_Watchdog_Is_empty( header ) ) { - Watchdog_Control *watchdog = _Watchdog_First( header ); + Per_CPU_Control *cpu_self = _Per_CPU_Get(); + Watchdog_Header *header = &cpu_self->Watchdog.Header[ PER_CPU_WATCHDOG_RELATIVE ]; + Watchdog_Control *watchdog = (Watchdog_Control *) header->first; - if ( - watchdog->delta_interval == 0 - && watchdog->routine == _Thread_Timeout - ) { - Watchdog_States state = _Watchdog_Remove_ticks( watchdog ); + if ( + watchdog != NULL + && watchdog->expire == cpu_self->Watchdog.ticks + && watchdog->routine == _Thread_Timeout + ) { + _Watchdog_Per_CPU_remove( watchdog, cpu_self, header ); - rtems_test_assert( state == WATCHDOG_ACTIVE ); - (*watchdog->routine)( watchdog->id, watchdog->user_data ); + (*watchdog->routine)( watchdog ); - if ( is_interrupt_timeout() ) { - case_hit = true; - } + if ( is_interrupt_timeout() ) { + case_hit = true; } } } diff --git a/testsuites/sptests/spintrcritical10/init.c b/testsuites/sptests/spintrcritical10/init.c index e4a2a940a6..25be23a852 100644 --- a/testsuites/sptests/spintrcritical10/init.c +++ b/testsuites/sptests/spintrcritical10/init.c @@ -78,7 +78,7 @@ static void any_satisfy_before_timeout(rtems_id timer, void *arg) ); rtems_test_assert(thread->Wait.return_code == RTEMS_SUCCESSFUL); - _Thread_Timeout(0, thread); + _Thread_Timeout(&thread->Timer.Watchdog); rtems_test_assert( *(rtems_event_set *) thread->Wait.return_argument == GREEN @@ -175,7 +175,7 @@ static void all_satisfy_before_timeout(rtems_id timer, void *arg) ); rtems_test_assert(thread->Wait.return_code == RTEMS_SUCCESSFUL); - _Thread_Timeout(0, thread); + _Thread_Timeout(&thread->Timer.Watchdog); rtems_test_assert( *(rtems_event_set *) thread->Wait.return_argument == EVENTS @@ -251,7 +251,7 @@ static void timeout_before_satisfied(rtems_id timer, void *arg) ); rtems_test_assert(thread->Wait.return_code == RTEMS_SUCCESSFUL); - _Thread_Timeout(0, thread); + _Thread_Timeout(&thread->Timer.Watchdog); rtems_test_assert( *(rtems_event_set *) thread->Wait.return_argument == DEADBEEF diff --git a/testsuites/sptests/spintrcritical16/init.c b/testsuites/sptests/spintrcritical16/init.c index a094b419b3..3657c0607f 100644 --- a/testsuites/sptests/spintrcritical16/init.c +++ b/testsuites/sptests/spintrcritical16/init.c @@ -43,7 +43,7 @@ static rtems_timer_service_routine test_release_from_isr( } if ( Main_TCB->Wait.queue != NULL ) { - _Thread_Timeout( 0, Main_TCB ); + _Thread_Timeout( &Main_TCB->Timer.Watchdog ); } } diff --git a/testsuites/sptests/spintrcritical17/Makefile.am b/testsuites/sptests/spintrcritical17/Makefile.am deleted file mode 100644 index 20b372cf48..0000000000 --- a/testsuites/sptests/spintrcritical17/Makefile.am +++ /dev/null @@ -1,25 +0,0 @@ - -rtems_tests_PROGRAMS = spintrcritical17 -spintrcritical17_SOURCES = init.c \ - ../spintrcritical_support/intrcritical.c -spintrcritical17_SOURCES += ../spintrcritical_support/intrcritical.h - -dist_rtems_tests_DATA = spintrcritical17.scn -dist_rtems_tests_DATA += spintrcritical17.doc - -include $(RTEMS_ROOT)/make/custom/@RTEMS_BSP@.cfg -include $(top_srcdir)/../automake/compile.am -include $(top_srcdir)/../automake/leaf.am - - -AM_CPPFLAGS += -I$(top_srcdir)/../support/include -AM_CPPFLAGS += -I$(top_srcdir)/spintrcritical_support - -LINK_OBJS = $(spintrcritical17_OBJECTS) -LINK_LIBS = $(spintrcritical17_LDLIBS) - -spintrcritical17$(EXEEXT): $(spintrcritical17_OBJECTS) $(spintrcritical17_DEPENDENCIES) - @rm -f spintrcritical17$(EXEEXT) - $(make-exe) - -include $(top_srcdir)/../automake/local.am diff --git a/testsuites/sptests/spintrcritical17/init.c b/testsuites/sptests/spintrcritical17/init.c deleted file mode 100644 index 238493e71a..0000000000 --- a/testsuites/sptests/spintrcritical17/init.c +++ /dev/null @@ -1,118 +0,0 @@ -/* - * Copyright (c) 2009-2014 embedded brains GmbH. - * - * embedded brains GmbH - * Dornierstr. 4 - * 82178 Puchheim - * Germany - * <rtems@embedded-brains.de> - * - * The license and distribution terms for this file may be - * found in the file LICENSE in this distribution or at - * http://www.rtems.org/license/LICENSE. - */ - -#ifdef HAVE_CONFIG_H -#include "config.h" -#endif - -#include <tmacros.h> -#include <intrcritical.h> - -#include <rtems/rtems/timerimpl.h> - -const char rtems_test_name[] = "SPINTRCRITICAL 17"; - -typedef struct { - rtems_id timer1; - rtems_id timer2; - bool done; -} test_context; - -static test_context ctx_instance; - -static void never(rtems_id timer_id, void *arg) -{ - rtems_test_assert(0); -} - -static void fire(rtems_id timer_id, void *arg) -{ - /* The arg is NULL */ - test_context *ctx = &ctx_instance; - rtems_status_code sc; - - if (!ctx->done) { - ctx->done = - _Timer_server->Interval_watchdogs.system_watchdog_helper != NULL; - - if (ctx->done) { - sc = rtems_timer_server_fire_after(ctx->timer2, 100, never, NULL); - rtems_test_assert(sc == RTEMS_SUCCESSFUL); - } - } -} - -static bool test_body(void *arg) -{ - test_context *ctx = arg; - rtems_status_code sc; - - sc = rtems_timer_reset(ctx->timer1); - rtems_test_assert(sc == RTEMS_SUCCESSFUL); - - return ctx->done; -} - -static void Init(rtems_task_argument ignored) -{ - test_context *ctx = &ctx_instance; - rtems_status_code sc; - - TEST_BEGIN(); - - sc = rtems_timer_create( - rtems_build_name('T', 'I', 'M', '1'), - &ctx->timer1 - ); - rtems_test_assert(sc == RTEMS_SUCCESSFUL); - - sc = rtems_timer_create( - rtems_build_name('T', 'I', 'M', '2'), - &ctx->timer2 - ); - rtems_test_assert(sc == RTEMS_SUCCESSFUL); - - sc = rtems_timer_initiate_server( - RTEMS_MINIMUM_PRIORITY, - RTEMS_MINIMUM_STACK_SIZE, - RTEMS_DEFAULT_ATTRIBUTES - ); - rtems_test_assert(sc == RTEMS_SUCCESSFUL); - - sc = rtems_timer_server_fire_after(ctx->timer1, 1000, never, NULL); - rtems_test_assert(sc == RTEMS_SUCCESSFUL); - - interrupt_critical_section_test(test_body, ctx, fire); - rtems_test_assert(ctx->done); - - TEST_END(); - rtems_test_exit(0); -} - -#define CONFIGURE_APPLICATION_NEEDS_CONSOLE_DRIVER -#define CONFIGURE_APPLICATION_NEEDS_CLOCK_DRIVER - -#define CONFIGURE_MICROSECONDS_PER_TICK 1000 - -#define CONFIGURE_MAXIMUM_TASKS 2 -#define CONFIGURE_MAXIMUM_TIMERS 3 -#define CONFIGURE_MAXIMUM_USER_EXTENSIONS 1 - -#define CONFIGURE_INITIAL_EXTENSIONS RTEMS_TEST_INITIAL_EXTENSION - -#define CONFIGURE_RTEMS_INIT_TASKS_TABLE - -#define CONFIGURE_INIT - -#include <rtems/confdefs.h> diff --git a/testsuites/sptests/spintrcritical17/spintrcritical17.doc b/testsuites/sptests/spintrcritical17/spintrcritical17.doc deleted file mode 100644 index 809a9669d6..0000000000 --- a/testsuites/sptests/spintrcritical17/spintrcritical17.doc +++ /dev/null @@ -1,18 +0,0 @@ -# Copyright (c) 2009-2015 embedded brains GmbH. -# -# The license and distribution terms for this file may be -# found in the file LICENSE in this distribution or at -# http://www.rtems.org/license/LICENSE. -# - -This file describes the directives and concepts tested by this test set. - -test set name: spintrcritical17 - -directives: - - _Timer_server_Update_system_watchdog - -concepts: - -+ Test critical sections which are only accessible through an interrupt. diff --git a/testsuites/sptests/spintrcritical17/spintrcritical17.scn b/testsuites/sptests/spintrcritical17/spintrcritical17.scn deleted file mode 100644 index 14566dfb3d..0000000000 --- a/testsuites/sptests/spintrcritical17/spintrcritical17.scn +++ /dev/null @@ -1,2 +0,0 @@ -*** TEST INTERRUPT CRITICAL SECTION 17 *** -*** END OF INTERRUPT CRITICAL SECTION 17 *** diff --git a/testsuites/sptests/spintrcritical20/init.c b/testsuites/sptests/spintrcritical20/init.c index 7e52211742..85c1645b5c 100644 --- a/testsuites/sptests/spintrcritical20/init.c +++ b/testsuites/sptests/spintrcritical20/init.c @@ -91,7 +91,7 @@ static bool test_body(void *arg) ctx->thread_queue_was_null = true; } - _Thread_Timeout(0, ctx->semaphore_task_tcb); + _Thread_Timeout(&ctx->semaphore_task_tcb->Timer.Watchdog); switch (ctx->semaphore_task_tcb->Wait.return_code) { case CORE_SEMAPHORE_STATUS_SUCCESSFUL: diff --git a/testsuites/sptests/spsize/size.c b/testsuites/sptests/spsize/size.c index e9470e384d..e19ca99606 100644 --- a/testsuites/sptests/spsize/size.c +++ b/testsuites/sptests/spsize/size.c @@ -391,8 +391,6 @@ uninitialized = /*userext.h*/ (sizeof _User_extensions_List) + /*watchdog.h*/ (sizeof _Watchdog_Ticks_since_boot) + - (sizeof _Watchdog_Ticks_header) + - (sizeof _Watchdog_Seconds_header) + /*wkspace.h*/ (sizeof _Workspace_Area); diff --git a/testsuites/sptests/sptimecounter01/init.c b/testsuites/sptests/sptimecounter01/init.c index 7b31064f54..d87ffec460 100644 --- a/testsuites/sptests/sptimecounter01/init.c +++ b/testsuites/sptests/sptimecounter01/init.c @@ -24,7 +24,6 @@ #include <rtems/score/timecounterimpl.h> #include <rtems/score/todimpl.h> -#include <rtems/score/watchdogimpl.h> #include <rtems/timecounter.h> #include <rtems/bsd.h> @@ -57,8 +56,6 @@ void boot_card(const char *cmdline) rtems_test_begink(); - _Watchdog_Handler_initialization(); - assert(time(NULL) == TOD_SECONDS_1970_THROUGH_1988); rtems_bsd_bintime(&bt); diff --git a/testsuites/sptests/sptimerserver01/Makefile.am b/testsuites/sptests/sptimerserver01/Makefile.am new file mode 100644 index 0000000000..2e5048d4e3 --- /dev/null +++ b/testsuites/sptests/sptimerserver01/Makefile.am @@ -0,0 +1,19 @@ +rtems_tests_PROGRAMS = sptimerserver01 +sptimerserver01_SOURCES = init.c + +dist_rtems_tests_DATA = sptimerserver01.scn sptimerserver01.doc + +include $(RTEMS_ROOT)/make/custom/@RTEMS_BSP@.cfg +include $(top_srcdir)/../automake/compile.am +include $(top_srcdir)/../automake/leaf.am + +AM_CPPFLAGS += -I$(top_srcdir)/../support/include + +LINK_OBJS = $(sptimerserver01_OBJECTS) +LINK_LIBS = $(sptimerserver01_LDLIBS) + +sptimerserver01$(EXEEXT): $(sptimerserver01_OBJECTS) $(sptimerserver01_DEPENDENCIES) + @rm -f sptimerserver01$(EXEEXT) + $(make-exe) + +include $(top_srcdir)/../automake/local.am diff --git a/testsuites/sptests/sptimerserver01/init.c b/testsuites/sptests/sptimerserver01/init.c new file mode 100644 index 0000000000..88f1fb3cf3 --- /dev/null +++ b/testsuites/sptests/sptimerserver01/init.c @@ -0,0 +1,129 @@ +/* + * Copyright (c) 2016 embedded brains GmbH. All rights reserved. + * + * embedded brains GmbH + * Dornierstr. 4 + * 82178 Puchheim + * Germany + * <rtems@embedded-brains.de> + * + * The license and distribution terms for this file may be + * found in the file LICENSE in this distribution or at + * http://www.rtems.org/license/LICENSE. + */ + +#ifdef HAVE_CONFIG_H + #include "config.h" +#endif + +#include "tmacros.h" + +const char rtems_test_name[] = "SPTIMERSERVER 1"; + +#define TIMER_COUNT 2 + +typedef struct { + rtems_id timer[TIMER_COUNT]; + rtems_id master; +} test_context; + +static test_context ctx_instance; + +static const rtems_time_of_day start = { + .year = 2016, + .month = 3, + .day = 1, + .hour = 12, + .minute = 5, + .second = 17 +}; + +static void cancel(rtems_id id, void *arg) +{ + test_context *ctx = arg; + rtems_status_code sc; + + sc = rtems_timer_cancel(ctx->timer[1]); + rtems_test_assert(sc == RTEMS_SUCCESSFUL); + + sc = rtems_event_transient_send(ctx->master); + rtems_test_assert(sc == RTEMS_SUCCESSFUL); +} + +static void never(rtems_id id, void *arg) +{ + rtems_test_assert(0); +} + +static void test(void) +{ + test_context *ctx = &ctx_instance; + rtems_status_code sc; + size_t i; + rtems_time_of_day later; + + ctx->master = rtems_task_self(); + + sc = rtems_timer_initiate_server( + RTEMS_MINIMUM_PRIORITY, + RTEMS_MINIMUM_STACK_SIZE, + RTEMS_DEFAULT_ATTRIBUTES + ); + rtems_test_assert(sc == RTEMS_SUCCESSFUL); + + for (i = 0; i < TIMER_COUNT; ++i) { + sc = rtems_timer_create( + rtems_build_name('T', 'M', 'R', '0' + i), + &ctx->timer[i] + ); + rtems_test_assert(sc == RTEMS_SUCCESSFUL); + } + + sc = rtems_timer_server_fire_after(ctx->timer[0], 10, cancel, ctx); + rtems_test_assert(sc == RTEMS_SUCCESSFUL); + + sc = rtems_timer_server_fire_after(ctx->timer[1], 10, never, NULL); + rtems_test_assert(sc == RTEMS_SUCCESSFUL); + + sc = rtems_event_transient_receive(RTEMS_WAIT, RTEMS_NO_TIMEOUT); + rtems_test_assert(sc == RTEMS_SUCCESSFUL); + + sc = rtems_clock_set(&start); + rtems_test_assert(sc == RTEMS_SUCCESSFUL); + + later = start; + ++later.second; + + sc = rtems_timer_server_fire_when(ctx->timer[0], &later, cancel, ctx); + rtems_test_assert(sc == RTEMS_SUCCESSFUL); + + sc = rtems_timer_server_fire_when(ctx->timer[1], &later, never, NULL); + rtems_test_assert(sc == RTEMS_SUCCESSFUL); + + sc = rtems_event_transient_receive(RTEMS_WAIT, RTEMS_NO_TIMEOUT); + rtems_test_assert(sc == RTEMS_SUCCESSFUL); +} + +static void Init(rtems_task_argument arg) +{ + TEST_BEGIN(); + + test(); + + TEST_END(); + rtems_test_exit(0); +} + +#define CONFIGURE_APPLICATION_NEEDS_CLOCK_DRIVER +#define CONFIGURE_APPLICATION_NEEDS_CONSOLE_DRIVER + +#define CONFIGURE_MAXIMUM_TASKS 2 +#define CONFIGURE_MAXIMUM_TIMERS TIMER_COUNT + +#define CONFIGURE_INITIAL_EXTENSIONS RTEMS_TEST_INITIAL_EXTENSION + +#define CONFIGURE_RTEMS_INIT_TASKS_TABLE + +#define CONFIGURE_INIT + +#include <rtems/confdefs.h> diff --git a/testsuites/sptests/sptimerserver01/sptimerserver01.doc b/testsuites/sptests/sptimerserver01/sptimerserver01.doc new file mode 100644 index 0000000000..c0dc4ef578 --- /dev/null +++ b/testsuites/sptests/sptimerserver01/sptimerserver01.doc @@ -0,0 +1,12 @@ +This file describes the directives and concepts tested by this test set. + +test set name: sptimerserver01 + +directives: + + - rtems_timer_cancel() + +concepts: + + - Ensure that pending timer server timers are cancelled via + rtems_timer_cancel(). diff --git a/testsuites/sptests/sptimerserver01/sptimerserver01.scn b/testsuites/sptests/sptimerserver01/sptimerserver01.scn new file mode 100644 index 0000000000..315f030c94 --- /dev/null +++ b/testsuites/sptests/sptimerserver01/sptimerserver01.scn @@ -0,0 +1,2 @@ +*** BEGIN OF TEST SPTIMERSERVER 1 *** +*** END OF TEST SPTIMERSERVER 1 *** diff --git a/testsuites/sptests/spwatchdog/init.c b/testsuites/sptests/spwatchdog/init.c index 025295b45b..3b08fb57e5 100644 --- a/testsuites/sptests/spwatchdog/init.c +++ b/testsuites/sptests/spwatchdog/init.c @@ -26,241 +26,192 @@ const char rtems_test_name[] = "SPWATCHDOG"; -static void test_watchdog_routine( Objects_Id id, void *arg ) -{ - (void) id; - (void) arg; - - rtems_test_assert( 0 ); -} +typedef struct { + Watchdog_Control Base; + int counter; +} test_watchdog; -static void init_watchdogs( - Watchdog_Header *header, - Watchdog_Control watchdogs[4] -) +static void test_watchdog_routine( Watchdog_Control *base ) { - Watchdog_Control *a = &watchdogs[0]; - Watchdog_Control *b = &watchdogs[1]; - Watchdog_Control *c = &watchdogs[2]; - Watchdog_Control *d = &watchdogs[3]; - - _Watchdog_Header_initialize( header ); - rtems_test_assert( _Watchdog_Is_empty( header ) ); - rtems_test_assert( _Chain_Is_empty( &header->Iterators ) ); - - _Watchdog_Preinitialize( c ); - c->initial = 6; - _Watchdog_Insert( header, c ); - rtems_test_assert( c->delta_interval == 6 ); - - rtems_test_assert( !_Watchdog_Is_empty( header ) ); - rtems_test_assert( _Chain_Is_empty( &header->Iterators ) ); - - _Watchdog_Preinitialize( a ); - a->initial = 2; - _Watchdog_Insert( header, a ); - rtems_test_assert( a->delta_interval == 2 ); - rtems_test_assert( c->delta_interval == 4 ); - - _Watchdog_Preinitialize( b ); - b->initial = 4; - _Watchdog_Insert( header, b ); - rtems_test_assert( a->delta_interval == 2 ); - rtems_test_assert( b->delta_interval == 2 ); - rtems_test_assert( c->delta_interval == 2 ); - - _Watchdog_Preinitialize( d ); -} + test_watchdog *watchdog = (test_watchdog *) base; -static void destroy_watchdogs( - Watchdog_Header *header -) -{ - _ISR_lock_Destroy( &header->Lock ); + ++watchdog->counter; } -static void add_iterator( - Watchdog_Header *header, - Watchdog_Iterator *i, - Watchdog_Control *w -) +static void test_watchdog_static_init( void ) { - _Chain_Append_unprotected( &header->Iterators, &i->Node ); - i->delta_interval = 2; - i->current = &w->Node; -} + static Watchdog_Control a = WATCHDOG_INITIALIZER( + test_watchdog_routine + ); + Watchdog_Control b; -static void test_watchdog_insert_and_remove( void ) -{ - Watchdog_Header header; - Watchdog_Control watchdogs[4]; - Watchdog_Control *a = &watchdogs[0]; - Watchdog_Control *b = &watchdogs[1]; - Watchdog_Control *c = &watchdogs[2]; - Watchdog_Control *d = &watchdogs[3]; - Watchdog_Iterator i; - - init_watchdogs( &header, watchdogs ); - add_iterator( &header, &i, c ); - - /* Remove next watchdog of iterator */ - _Watchdog_Remove( &header, c ); - rtems_test_assert( i.delta_interval == 4 ); - rtems_test_assert( i.current == &b->Node ); - - /* Remove watchdog before the current watchdog of iterator */ - _Watchdog_Remove( &header, a ); - rtems_test_assert( i.delta_interval == 6 ); - rtems_test_assert( i.current == &b->Node ); - - /* Remove current (= last) watchdog of iterator */ - _Watchdog_Remove( &header, b ); - rtems_test_assert( i.delta_interval == 6 ); - rtems_test_assert( i.current == _Chain_Head( &header.Watchdogs ) ); - - /* Insert first watchdog */ - a->initial = 1; - _Watchdog_Insert( &header, a ); - rtems_test_assert( i.delta_interval == 6 ); - rtems_test_assert( i.current == _Chain_Head( &header.Watchdogs ) ); - - destroy_watchdogs( &header ); - init_watchdogs( &header, watchdogs ); - add_iterator( &header, &i, b ); - - /* Insert right before current watchdog of iterator */ - d->initial = 3; - _Watchdog_Insert( &header, d ); - rtems_test_assert( i.delta_interval == 2 ); - rtems_test_assert( i.current == &d->Node ); - - destroy_watchdogs( &header ); - init_watchdogs( &header, watchdogs ); - add_iterator( &header, &i, b ); - - /* Insert right after current watchdog of iterator */ - d->initial = 5; - _Watchdog_Insert( &header, d ); - rtems_test_assert( i.delta_interval == 2 ); - rtems_test_assert( i.current == &b->Node ); - - destroy_watchdogs( &header ); + memset( &b, 0, sizeof( b ) ); + _Watchdog_Preinitialize( &b, _Per_CPU_Get_by_index( 0 ) ); + _Watchdog_Initialize( + &b, + test_watchdog_routine + ); + + rtems_test_assert( memcmp( &a, &b, sizeof( a ) ) == 0 ); } -static void init_watchdogs_remove_second_and_insert_first( - Watchdog_Header *header, - Watchdog_Control watchdogs[3] -) +static bool test_watchdog_is_inactive( test_watchdog *watchdog ) { - Watchdog_Control *a = &watchdogs[0]; - Watchdog_Control *b = &watchdogs[1]; - Watchdog_Control *c = &watchdogs[2]; - - _Watchdog_Preinitialize( a ); - _Watchdog_Preinitialize( b ); - _Watchdog_Preinitialize( c ); - - _Watchdog_Header_initialize( header ); - - a->initial = 6; - _Watchdog_Insert( header, a ); - rtems_test_assert( a->delta_interval == 6 ); - - b->initial = 8; - _Watchdog_Insert( header, b ); - rtems_test_assert( a->delta_interval == 6 ); - rtems_test_assert( b->delta_interval == 2 ); + return _Watchdog_Get_state( &watchdog->Base ) == WATCHDOG_INACTIVE; } -static void test_watchdog_remove_second_and_insert_first( void ) +static void test_watchdog_init( test_watchdog *watchdog, int counter ) { - Watchdog_Header header; - Watchdog_Control watchdogs[3]; - Watchdog_Control *a = &watchdogs[0]; - Watchdog_Control *b = &watchdogs[1]; - Watchdog_Control *c = &watchdogs[2]; - Watchdog_Iterator i; - - init_watchdogs_remove_second_and_insert_first( &header, watchdogs ); - add_iterator( &header, &i, b ); - - _Watchdog_Remove( &header, b ); - rtems_test_assert( i.delta_interval == 8 ); - rtems_test_assert( i.current == &a->Node ); - - c->initial = 4; - _Watchdog_Insert( &header, c ); - rtems_test_assert( a->delta_interval == 2 ); - rtems_test_assert( c->delta_interval == 4 ); - rtems_test_assert( i.delta_interval == 8 ); - rtems_test_assert( i.current == &c->Node ); - - destroy_watchdogs( &header ); + _Watchdog_Preinitialize( &watchdog->Base, _Per_CPU_Get_snapshot() ); + _Watchdog_Initialize( &watchdog->Base, test_watchdog_routine ); + rtems_test_assert( test_watchdog_is_inactive( watchdog ) ) ; + watchdog->counter = counter; } -static void init_watchdogs_insert_with_iterator( - Watchdog_Header *header, - Watchdog_Control watchdogs[2] -) +static uint64_t test_watchdog_tick( Watchdog_Header *header, uint64_t now ) { - Watchdog_Control *a = &watchdogs[0]; - Watchdog_Control *b = &watchdogs[1]; + ISR_LOCK_DEFINE( , lock, "Test" ) + ISR_lock_Context lock_context; - _Watchdog_Preinitialize( a ); - _Watchdog_Preinitialize( b ); + _ISR_lock_ISR_disable_and_acquire( &lock, &lock_context ); + ++now; + _Watchdog_Tickle( header, now, &lock, &lock_context ); + _ISR_lock_Destroy( &lock ); - _Watchdog_Header_initialize( header ); - - a->initial = 6; - _Watchdog_Insert( header, a ); - rtems_test_assert( a->delta_interval == 6 ); + return now; } -static void test_watchdog_insert_with_iterator( void ) +static void test_watchdog_operations( void ) { Watchdog_Header header; - Watchdog_Control watchdogs[2]; - Watchdog_Control *a = &watchdogs[0]; - Watchdog_Control *b = &watchdogs[1]; - Watchdog_Iterator i; - - init_watchdogs_insert_with_iterator( &header, watchdogs ); - add_iterator( &header, &i, a ); - - b->initial = 4; - _Watchdog_Insert( &header, b ); - rtems_test_assert( a->delta_interval == 2 ); - rtems_test_assert( b->delta_interval == 4 ); - rtems_test_assert( i.delta_interval == 2 ); - rtems_test_assert( i.current == &b->Node ); - - destroy_watchdogs( &header ); -} - -static void test_watchdog_static_init( void ) -{ - #if defined(RTEMS_USE_16_BIT_OBJECT) - #define JUNK_ID 0x1234 - #else - #define JUNK_ID 0x12345678 - #endif - - static Watchdog_Control a = WATCHDOG_INITIALIZER( - test_watchdog_routine, - JUNK_ID, - (void *) 0xdeadbeef - ); - Watchdog_Control b; - - memset( &b, 0, sizeof( b ) ); - _Watchdog_Initialize( - &b, - test_watchdog_routine, - JUNK_ID, - (void *) 0xdeadbeef - ); - - rtems_test_assert( memcmp( &a, &b, sizeof( a ) ) == 0 ); + uint64_t now; + test_watchdog a; + test_watchdog b; + test_watchdog c; + + _Watchdog_Header_initialize( &header ); + rtems_test_assert( _RBTree_Is_empty( &header.Watchdogs ) ); + rtems_test_assert( header.first == NULL ); + + test_watchdog_init( &a, 10 ); + test_watchdog_init( &b, 20 ); + test_watchdog_init( &c, 30 ); + + now = 0; + now = test_watchdog_tick( &header, now ); + + _Watchdog_Insert( &header, &a.Base, now + 1 ); + rtems_test_assert( header.first == &a.Base.Node.RBTree ); + rtems_test_assert( !test_watchdog_is_inactive( &a ) ) ; + rtems_test_assert( a.Base.expire == 2 ); + rtems_test_assert( a.counter == 10 ); + + _Watchdog_Remove( &header, &a.Base ); + rtems_test_assert( header.first == NULL ); + rtems_test_assert( test_watchdog_is_inactive( &a ) ) ; + rtems_test_assert( a.Base.expire == 2 ); + rtems_test_assert( a.counter == 10 ); + + _Watchdog_Remove( &header, &a.Base ); + rtems_test_assert( header.first == NULL ); + rtems_test_assert( test_watchdog_is_inactive( &a ) ) ; + rtems_test_assert( a.Base.expire == 2 ); + rtems_test_assert( a.counter == 10 ); + + _Watchdog_Insert( &header, &a.Base, now + 1 ); + rtems_test_assert( header.first == &a.Base.Node.RBTree ); + rtems_test_assert( !test_watchdog_is_inactive( &a ) ) ; + rtems_test_assert( a.Base.expire == 2 ); + rtems_test_assert( a.counter == 10 ); + + _Watchdog_Insert( &header, &b.Base, now + 1 ); + rtems_test_assert( header.first == &a.Base.Node.RBTree ); + rtems_test_assert( !test_watchdog_is_inactive( &b ) ) ; + rtems_test_assert( b.Base.expire == 2 ); + rtems_test_assert( b.counter == 20 ); + + _Watchdog_Insert( &header, &c.Base, now + 2 ); + rtems_test_assert( header.first == &a.Base.Node.RBTree ); + rtems_test_assert( !test_watchdog_is_inactive( &c ) ) ; + rtems_test_assert( c.Base.expire == 3 ); + rtems_test_assert( c.counter == 30 ); + + _Watchdog_Remove( &header, &a.Base ); + rtems_test_assert( header.first == &b.Base.Node.RBTree ); + rtems_test_assert( test_watchdog_is_inactive( &a ) ) ; + rtems_test_assert( a.Base.expire == 2 ); + rtems_test_assert( a.counter == 10 ); + + _Watchdog_Remove( &header, &b.Base ); + rtems_test_assert( header.first == &c.Base.Node.RBTree ); + rtems_test_assert( test_watchdog_is_inactive( &b ) ) ; + rtems_test_assert( b.Base.expire == 2 ); + rtems_test_assert( b.counter == 20 ); + + _Watchdog_Remove( &header, &c.Base ); + rtems_test_assert( header.first == NULL ); + rtems_test_assert( test_watchdog_is_inactive( &c ) ) ; + rtems_test_assert( c.Base.expire == 3 ); + rtems_test_assert( c.counter == 30 ); + + _Watchdog_Insert( &header, &a.Base, now + 2 ); + rtems_test_assert( header.first == &a.Base.Node.RBTree ); + rtems_test_assert( !test_watchdog_is_inactive( &a ) ) ; + rtems_test_assert( a.Base.expire == 3 ); + rtems_test_assert( a.counter == 10 ); + + _Watchdog_Insert( &header, &b.Base, now + 2 ); + rtems_test_assert( header.first == &a.Base.Node.RBTree ); + rtems_test_assert( !test_watchdog_is_inactive( &b ) ) ; + rtems_test_assert( b.Base.expire == 3 ); + rtems_test_assert( b.counter == 20 ); + + _Watchdog_Insert( &header, &c.Base, now + 3 ); + rtems_test_assert( header.first == &a.Base.Node.RBTree ); + rtems_test_assert( !test_watchdog_is_inactive( &c ) ) ; + rtems_test_assert( c.Base.expire == 4 ); + rtems_test_assert( c.counter == 30 ); + + now = test_watchdog_tick( &header, now ); + rtems_test_assert( !_RBTree_Is_empty( &header.Watchdogs ) ); + rtems_test_assert( header.first == &a.Base.Node.RBTree ); + rtems_test_assert( !test_watchdog_is_inactive( &a ) ) ; + rtems_test_assert( a.Base.expire == 3 ); + rtems_test_assert( a.counter == 10 ); + rtems_test_assert( !test_watchdog_is_inactive( &b ) ) ; + rtems_test_assert( b.Base.expire == 3 ); + rtems_test_assert( b.counter == 20 ); + rtems_test_assert( !test_watchdog_is_inactive( &c ) ) ; + rtems_test_assert( c.Base.expire == 4 ); + rtems_test_assert( c.counter == 30 ); + + now = test_watchdog_tick( &header, now ); + rtems_test_assert( !_RBTree_Is_empty( &header.Watchdogs ) ); + rtems_test_assert( header.first == &c.Base.Node.RBTree ); + rtems_test_assert( test_watchdog_is_inactive( &a ) ) ; + rtems_test_assert( a.Base.expire == 3 ); + rtems_test_assert( a.counter == 11 ); + rtems_test_assert( test_watchdog_is_inactive( &b ) ) ; + rtems_test_assert( b.Base.expire == 3 ); + rtems_test_assert( b.counter == 21 ); + rtems_test_assert( !test_watchdog_is_inactive( &c ) ) ; + rtems_test_assert( c.Base.expire == 4 ); + rtems_test_assert( c.counter == 30 ); + + now = test_watchdog_tick( &header, now ); + rtems_test_assert( _RBTree_Is_empty( &header.Watchdogs ) ); + rtems_test_assert( header.first == NULL ); + rtems_test_assert( test_watchdog_is_inactive( &a ) ) ; + rtems_test_assert( a.Base.expire == 3 ); + rtems_test_assert( a.counter == 11 ); + rtems_test_assert( test_watchdog_is_inactive( &b ) ) ; + rtems_test_assert( b.Base.expire == 3 ); + rtems_test_assert( b.counter == 21 ); + rtems_test_assert( test_watchdog_is_inactive( &c ) ) ; + rtems_test_assert( c.Base.expire == 4 ); + rtems_test_assert( c.counter == 31 ); + + _Watchdog_Header_destroy( &header ); } rtems_task Init( @@ -272,10 +223,8 @@ rtems_task Init( TEST_BEGIN(); + test_watchdog_operations(); test_watchdog_static_init(); - test_watchdog_insert_and_remove(); - test_watchdog_remove_second_and_insert_first(); - test_watchdog_insert_with_iterator(); build_time( &time, 12, 31, 1988, 9, 0, 0, 0 ); diff --git a/testsuites/tmtests/tmtimer01/tmtimer01.scn b/testsuites/tmtests/tmtimer01/tmtimer01.scn index ea882d415f..db3ca01d27 100644 --- a/testsuites/tmtests/tmtimer01/tmtimer01.scn +++ b/testsuites/tmtests/tmtimer01/tmtimer01.scn @@ -1,137 +1,137 @@ <TMTimer01 timerCount="65504"> <Sample> - <ActiveTimers>0</ActiveTimers><First unit="ns">6397</First><Middle unit="ns">3290</Middle><Last unit="ns">1527</Last> + <ActiveTimers>0</ActiveTimers><First unit="ns">8812</First><Middle unit="ns">1412</Middle><Last unit="ns">917</Last> </Sample> <Sample> - <ActiveTimers>2</ActiveTimers><First unit="ns">1986</First><Middle unit="ns">1550</Middle><Last unit="ns">1314</Last> + <ActiveTimers>2</ActiveTimers><First unit="ns">1602</First><Middle unit="ns">1010</Middle><Last unit="ns">1367</Last> </Sample> <Sample> - <ActiveTimers>4</ActiveTimers><First unit="ns">1551</First><Middle unit="ns">2134</Middle><Last unit="ns">3072</Last> + <ActiveTimers>4</ActiveTimers><First unit="ns">1524</First><Middle unit="ns">1089</Middle><Last unit="ns">1086</Last> </Sample> <Sample> - <ActiveTimers>7</ActiveTimers><First unit="ns">2545</First><Middle unit="ns">3511</Middle><Last unit="ns">3404</Last> + <ActiveTimers>7</ActiveTimers><First unit="ns">1791</First><Middle unit="ns">1121</Middle><Last unit="ns">1838</Last> </Sample> <Sample> - <ActiveTimers>10</ActiveTimers><First unit="ns">1595</First><Middle unit="ns">2363</Middle><Last unit="ns">4287</Last> + <ActiveTimers>10</ActiveTimers><First unit="ns">1488</First><Middle unit="ns">1016</Middle><Last unit="ns">2134</Last> </Sample> <Sample> - <ActiveTimers>14</ActiveTimers><First unit="ns">1473</First><Middle unit="ns">2740</Middle><Last unit="ns">6069</Last> + <ActiveTimers>14</ActiveTimers><First unit="ns">1527</First><Middle unit="ns">1698</Middle><Last unit="ns">3186</Last> </Sample> <Sample> - <ActiveTimers>19</ActiveTimers><First unit="ns">1566</First><Middle unit="ns">3195</Middle><Last unit="ns">5993</Last> + <ActiveTimers>19</ActiveTimers><First unit="ns">2078</First><Middle unit="ns">1665</Middle><Last unit="ns">3397</Last> </Sample> <Sample> - <ActiveTimers>25</ActiveTimers><First unit="ns">1251</First><Middle unit="ns">2718</Middle><Last unit="ns">7307</Last> + <ActiveTimers>25</ActiveTimers><First unit="ns">1519</First><Middle unit="ns">2368</Middle><Last unit="ns">4464</Last> </Sample> <Sample> - <ActiveTimers>32</ActiveTimers><First unit="ns">2302</First><Middle unit="ns">5690</Middle><Last unit="ns">10269</Last> + <ActiveTimers>32</ActiveTimers><First unit="ns">1243</First><Middle unit="ns">2623</Middle><Last unit="ns">3549</Last> </Sample> <Sample> - <ActiveTimers>41</ActiveTimers><First unit="ns">1522</First><Middle unit="ns">8221</Middle><Last unit="ns">13424</Last> + <ActiveTimers>41</ActiveTimers><First unit="ns">2368</First><Middle unit="ns">2578</Middle><Last unit="ns">4105</Last> </Sample> <Sample> - <ActiveTimers>52</ActiveTimers><First unit="ns">1799</First><Middle unit="ns">8455</Middle><Last unit="ns">14820</Last> + <ActiveTimers>52</ActiveTimers><First unit="ns">2322</First><Middle unit="ns">2563</Middle><Last unit="ns">4126</Last> </Sample> <Sample> - <ActiveTimers>66</ActiveTimers><First unit="ns">1062</First><Middle unit="ns">12480</Middle><Last unit="ns">16590</Last> + <ActiveTimers>66</ActiveTimers><First unit="ns">2499</First><Middle unit="ns">1855</Middle><Last unit="ns">4919</Last> </Sample> <Sample> - <ActiveTimers>83</ActiveTimers><First unit="ns">1384</First><Middle unit="ns">11710</Middle><Last unit="ns">21854</Last> + <ActiveTimers>83</ActiveTimers><First unit="ns">1689</First><Middle unit="ns">3128</Middle><Last unit="ns">5894</Last> </Sample> <Sample> - <ActiveTimers>104</ActiveTimers><First unit="ns">1666</First><Middle unit="ns">15200</Middle><Last unit="ns">30951</Last> + <ActiveTimers>104</ActiveTimers><First unit="ns">2301</First><Middle unit="ns">2647</Middle><Last unit="ns">4595</Last> </Sample> <Sample> - <ActiveTimers>130</ActiveTimers><First unit="ns">1345</First><Middle unit="ns">17154</Middle><Last unit="ns">37942</Last> + <ActiveTimers>130</ActiveTimers><First unit="ns">2880</First><Middle unit="ns">3183</Middle><Last unit="ns">6222</Last> </Sample> <Sample> - <ActiveTimers>162</ActiveTimers><First unit="ns">1369</First><Middle unit="ns">22381</Middle><Last unit="ns">46929</Last> + <ActiveTimers>162</ActiveTimers><First unit="ns">2597</First><Middle unit="ns">2376</Middle><Last unit="ns">7118</Last> </Sample> <Sample> - <ActiveTimers>201</ActiveTimers><First unit="ns">2271</First><Middle unit="ns">35625</Middle><Last unit="ns">59972</Last> + <ActiveTimers>201</ActiveTimers><First unit="ns">3519</First><Middle unit="ns">3466</Middle><Last unit="ns">6673</Last> </Sample> <Sample> - <ActiveTimers>249</ActiveTimers><First unit="ns">1279</First><Middle unit="ns">37271</Middle><Last unit="ns">69662</Last> + <ActiveTimers>249</ActiveTimers><First unit="ns">2829</First><Middle unit="ns">3177</Middle><Last unit="ns">7784</Last> </Sample> <Sample> - <ActiveTimers>308</ActiveTimers><First unit="ns">864</First><Middle unit="ns">44580</Middle><Last unit="ns">87633</Last> + <ActiveTimers>308</ActiveTimers><First unit="ns">2614</First><Middle unit="ns">3396</Middle><Last unit="ns">7338</Last> </Sample> <Sample> - <ActiveTimers>381</ActiveTimers><First unit="ns">1078</First><Middle unit="ns">53821</Middle><Last unit="ns">106376</Last> + <ActiveTimers>381</ActiveTimers><First unit="ns">3454</First><Middle unit="ns">4888</Middle><Last unit="ns">9114</Last> </Sample> <Sample> - <ActiveTimers>470</ActiveTimers><First unit="ns">913</First><Middle unit="ns">67021</Middle><Last unit="ns">133201</Last> + <ActiveTimers>470</ActiveTimers><First unit="ns">3397</First><Middle unit="ns">2443</Middle><Last unit="ns">7689</Last> </Sample> <Sample> - <ActiveTimers>580</ActiveTimers><First unit="ns">1870</First><Middle unit="ns">79863</Middle><Last unit="ns">169394</Last> + <ActiveTimers>580</ActiveTimers><First unit="ns">2233</First><Middle unit="ns">4410</Middle><Last unit="ns">9355</Last> </Sample> <Sample> - <ActiveTimers>715</ActiveTimers><First unit="ns">1732</First><Middle unit="ns">99965</Middle><Last unit="ns">208901</Last> + <ActiveTimers>715</ActiveTimers><First unit="ns">3787</First><Middle unit="ns">5891</Middle><Last unit="ns">6833</Last> </Sample> <Sample> - <ActiveTimers>881</ActiveTimers><First unit="ns">1503</First><Middle unit="ns">138820</Middle><Last unit="ns">259314</Last> + <ActiveTimers>881</ActiveTimers><First unit="ns">3839</First><Middle unit="ns">5089</Middle><Last unit="ns">9232</Last> </Sample> <Sample> - <ActiveTimers>1085</ActiveTimers><First unit="ns">1096</First><Middle unit="ns">166404</Middle><Last unit="ns">337461</Last> + <ActiveTimers>1085</ActiveTimers><First unit="ns">2838</First><Middle unit="ns">2739</Middle><Last unit="ns">11575</Last> </Sample> <Sample> - <ActiveTimers>1336</ActiveTimers><First unit="ns">1383</First><Middle unit="ns">209434</Middle><Last unit="ns">445806</Last> + <ActiveTimers>1336</ActiveTimers><First unit="ns">3256</First><Middle unit="ns">5011</Middle><Last unit="ns">9684</Last> </Sample> <Sample> - <ActiveTimers>1645</ActiveTimers><First unit="ns">1787</First><Middle unit="ns">253904</Middle><Last unit="ns">533644</Last> + <ActiveTimers>1645</ActiveTimers><First unit="ns">2293</First><Middle unit="ns">5262</Middle><Last unit="ns">10183</Last> </Sample> <Sample> - <ActiveTimers>2025</ActiveTimers><First unit="ns">2082</First><Middle unit="ns">327384</Middle><Last unit="ns">657141</Last> + <ActiveTimers>2025</ActiveTimers><First unit="ns">4436</First><Middle unit="ns">5934</Middle><Last unit="ns">8804</Last> </Sample> <Sample> - <ActiveTimers>2492</ActiveTimers><First unit="ns">1843</First><Middle unit="ns">417457</Middle><Last unit="ns">814380</Last> + <ActiveTimers>2492</ActiveTimers><First unit="ns">4506</First><Middle unit="ns">7284</Middle><Last unit="ns">10389</Last> </Sample> <Sample> - <ActiveTimers>3067</ActiveTimers><First unit="ns">1980</First><Middle unit="ns">493511</Middle><Last unit="ns">977427</Last> + <ActiveTimers>3067</ActiveTimers><First unit="ns">3832</First><Middle unit="ns">4990</Middle><Last unit="ns">9536</Last> </Sample> <Sample> - <ActiveTimers>3774</ActiveTimers><First unit="ns">2695</First><Middle unit="ns">622065</Middle><Last unit="ns">1237577</Last> + <ActiveTimers>3774</ActiveTimers><First unit="ns">5088</First><Middle unit="ns">4888</Middle><Last unit="ns">9633</Last> </Sample> <Sample> - <ActiveTimers>4644</ActiveTimers><First unit="ns">1463</First><Middle unit="ns">827565</Middle><Last unit="ns">1565553</Last> + <ActiveTimers>4644</ActiveTimers><First unit="ns">5590</First><Middle unit="ns">5749</Middle><Last unit="ns">8975</Last> </Sample> <Sample> - <ActiveTimers>5714</ActiveTimers><First unit="ns">1866</First><Middle unit="ns">1053458</Middle><Last unit="ns">1914932</Last> + <ActiveTimers>5714</ActiveTimers><First unit="ns">4854</First><Middle unit="ns">6813</Middle><Last unit="ns">11603</Last> </Sample> <Sample> - <ActiveTimers>7030</ActiveTimers><First unit="ns">3481</First><Middle unit="ns">1266198</Middle><Last unit="ns">2450199</Last> + <ActiveTimers>7030</ActiveTimers><First unit="ns">6139</First><Middle unit="ns">6132</Middle><Last unit="ns">12630</Last> </Sample> <Sample> - <ActiveTimers>8649</ActiveTimers><First unit="ns">2773</First><Middle unit="ns">1558351</Middle><Last unit="ns">2967472</Last> + <ActiveTimers>8649</ActiveTimers><First unit="ns">6877</First><Middle unit="ns">3852</Middle><Last unit="ns">10973</Last> </Sample> <Sample> - <ActiveTimers>10640</ActiveTimers><First unit="ns">2086</First><Middle unit="ns">2003884</Middle><Last unit="ns">3766161</Last> + <ActiveTimers>10640</ActiveTimers><First unit="ns">6532</First><Middle unit="ns">6097</Middle><Last unit="ns">11725</Last> </Sample> <Sample> - <ActiveTimers>13089</ActiveTimers><First unit="ns">3911</First><Middle unit="ns">2501427</Middle><Last unit="ns">4619553</Last> + <ActiveTimers>13089</ActiveTimers><First unit="ns">5284</First><Middle unit="ns">5392</Middle><Last unit="ns">13246</Last> </Sample> <Sample> - <ActiveTimers>16101</ActiveTimers><First unit="ns">3276</First><Middle unit="ns">3189159</Middle><Last unit="ns">5886373</Last> + <ActiveTimers>16101</ActiveTimers><First unit="ns">7077</First><Middle unit="ns">7572</Middle><Last unit="ns">14820</Last> </Sample> <Sample> - <ActiveTimers>19806</ActiveTimers><First unit="ns">3801</First><Middle unit="ns">4005049</Middle><Last unit="ns">7394938</Last> + <ActiveTimers>19806</ActiveTimers><First unit="ns">7132</First><Middle unit="ns">8335</Middle><Last unit="ns">11668</Last> </Sample> <Sample> - <ActiveTimers>24363</ActiveTimers><First unit="ns">3088</First><Middle unit="ns">4977788</Middle><Last unit="ns">9138839</Last> + <ActiveTimers>24363</ActiveTimers><First unit="ns">8676</First><Middle unit="ns">7919</Middle><Last unit="ns">13937</Last> </Sample> <Sample> - <ActiveTimers>29968</ActiveTimers><First unit="ns">4089</First><Middle unit="ns">6133462</Middle><Last unit="ns">11361012</Last> + <ActiveTimers>29968</ActiveTimers><First unit="ns">5970</First><Middle unit="ns">10978</Middle><Last unit="ns">16035</Last> </Sample> <Sample> - <ActiveTimers>36862</ActiveTimers><First unit="ns">2059</First><Middle unit="ns">7870138</Middle><Last unit="ns">14319206</Last> + <ActiveTimers>36862</ActiveTimers><First unit="ns">8804</First><Middle unit="ns">8767</Middle><Last unit="ns">13089</Last> </Sample> <Sample> - <ActiveTimers>45342</ActiveTimers><First unit="ns">2224</First><Middle unit="ns">9917100</Middle><Last unit="ns">17754441</Last> + <ActiveTimers>45342</ActiveTimers><First unit="ns">8608</First><Middle unit="ns">10305</Middle><Last unit="ns">15709</Last> </Sample> <Sample> - <ActiveTimers>55772</ActiveTimers><First unit="ns">1979</First><Middle unit="ns">11815557</Middle><Last unit="ns">21907509</Last> + <ActiveTimers>55772</ActiveTimers><First unit="ns">8949</First><Middle unit="ns">10031</Middle><Last unit="ns">16262</Last> </Sample> <Sample> - <ActiveTimers>65503</ActiveTimers><First unit="ns">2404</First><Middle unit="ns">13694591</Middle><Last unit="ns">26215885</Last> + <ActiveTimers>65503</ActiveTimers><First unit="ns">9199</First><Middle unit="ns">10309</Middle><Last unit="ns">19090</Last> </Sample> </TMTimer01> |