From 03b900d3ed120ea919ea3eded7edbece3488cff3 Mon Sep 17 00:00:00 2001 From: Sebastian Huber Date: Thu, 18 Feb 2016 08:36:26 +0100 Subject: score: Replace watchdog handler implementation Use a red-black tree instead of delta chains. Close #2344. Update #2554. Update #2555. Close #2606. --- cpukit/posix/src/alarm.c | 96 +++++++++++--------- cpukit/posix/src/nanosleep.c | 5 +- cpukit/posix/src/pthread.c | 31 ++++--- cpukit/posix/src/pthreadcreate.c | 6 +- cpukit/posix/src/pthreadsetschedparam.c | 14 ++- cpukit/posix/src/timercreate.c | 3 +- cpukit/posix/src/timerdelete.c | 12 ++- cpukit/posix/src/timergetoverrun.c | 7 +- cpukit/posix/src/timergettime.c | 29 +++--- cpukit/posix/src/timerinserthelper.c | 66 -------------- cpukit/posix/src/timersettime.c | 152 +++++++++++++++++++++---------- cpukit/posix/src/timertsr.c | 89 ------------------ cpukit/posix/src/ualarm.c | 155 ++++++++++++++++++-------------- 13 files changed, 317 insertions(+), 348 deletions(-) delete mode 100644 cpukit/posix/src/timerinserthelper.c delete mode 100644 cpukit/posix/src/timertsr.c (limited to 'cpukit/posix/src') 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 +#include -#include -#include -#include #include #include -/* - * _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 - -#include -#include -#include -#include -#include -#include - -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 #include +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 -#include -#include - -#include -#include -#include - -/* - * 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 #include -#include -#include -#include #include #include +#include -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; } -- cgit v1.2.3