mirror of
https://gitlab.rtems.org/rtems/rtos/rtems.git
synced 2026-11-08 00:40:21 +08:00
score: Replace watchdog handler implementation
Use a red-black tree instead of delta chains. Close #2344. Update #2554. Update #2555. Close #2606.
This commit is contained in:
1 parent
90d8567d34
commit
03b900d3ed
92 files changed
+2445
-2670
No files matched your search
@@ -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
|
||||
|
||||
@@ -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.
|
||||
|
||||
@@ -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. */
|
||||
|
||||
@@ -21,6 +21,7 @@
|
||||
|
||||
#include <rtems/posix/timer.h>
|
||||
#include <rtems/score/objectimpl.h>
|
||||
#include <rtems/score/watchdogimpl.h>
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
@@ -50,24 +51,6 @@ extern "C" {
|
||||
#error "POSIX_TIMER_RELATIVE == TIMER_ABSTIME"
|
||||
#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( &_POSIX_Timer_Information, (Objects_Id) id, location );
|
||||
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
|
||||
)
|
||||
{
|
||||
_Watchdog_Per_CPU_release_critical( cpu, lock_context );
|
||||
_ISR_lock_ISR_enable( lock_context );
|
||||
}
|
||||
|
||||
#ifdef __cplusplus
|
||||
|
||||
+49
-41
@@ -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
|
||||
)
|
||||
{
|
||||
#if defined(RTEMS_DEBUG)
|
||||
int status;
|
||||
#define KILL_STATUS status =
|
||||
#else
|
||||
#define KILL_STATUS (void)
|
||||
#endif
|
||||
ISR_LOCK_DEFINE( static, _POSIX_signals_Alarm_lock, "POSIX Alarm" )
|
||||
|
||||
KILL_STATUS kill( getpid(), SIGALRM );
|
||||
static void _POSIX_signals_Alarm_TSR( Watchdog_Control *the_watchdog )
|
||||
{
|
||||
int status;
|
||||
|
||||
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;
|
||||
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_timer = &_POSIX_signals_Alarm_timer;
|
||||
the_watchdog = &_POSIX_signals_Alarm_watchdog;
|
||||
ticks_per_second = TOD_TICKS_PER_SECOND;
|
||||
ticks = seconds * ticks_per_second;
|
||||
|
||||
_Thread_Disable_dispatch();
|
||||
_ISR_lock_ISR_disable_and_acquire(
|
||||
&_POSIX_signals_Alarm_lock,
|
||||
&lock_context
|
||||
);
|
||||
|
||||
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.
|
||||
*/
|
||||
cpu = _Watchdog_Get_CPU( the_watchdog );
|
||||
_Watchdog_Per_CPU_acquire_critical( cpu, &lock_context2 );
|
||||
now = cpu->Watchdog.ticks;
|
||||
|
||||
remaining = the_timer->initial -
|
||||
((the_timer->stop_time - the_timer->start_time) / TOD_TICKS_PER_SECOND);
|
||||
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 );
|
||||
_Watchdog_Per_CPU_release_critical( cpu, &lock_context2 );
|
||||
_ISR_lock_Release_and_ISR_enable(
|
||||
&_POSIX_signals_Alarm_lock,
|
||||
&lock_context
|
||||
);
|
||||
|
||||
_Thread_Enable_dispatch();
|
||||
|
||||
return remaining;
|
||||
return ( remaining + ticks_per_second - 1 ) / ticks_per_second;
|
||||
}
|
||||
@@ -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
|
||||
|
||||
+18
-13
@@ -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 );
|
||||
|
||||
|
||||
@@ -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();
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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();
|
||||
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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 */
|
||||
cpu = _POSIX_Timer_Acquire_critical( ptimer, &lock_context );
|
||||
now = cpu->Watchdog.ticks;
|
||||
|
||||
left =
|
||||
(ptimer->Timer.start_time + ptimer->Timer.initial) - /* expire */
|
||||
_Watchdog_Ticks_since_boot; /* now */
|
||||
if ( now < ptimer->Timer.expire ) {
|
||||
remaining = (uint32_t) ( ptimer->Timer.expire - now );
|
||||
} else {
|
||||
remaining = 0;
|
||||
}
|
||||
|
||||
_Timespec_From_ticks( left, &value->it_value );
|
||||
_Timespec_From_ticks( remaining, &value->it_value );
|
||||
value->it_interval = ptimer->timer_data.it_interval;
|
||||
|
||||
value->it_interval = ptimer->timer_data.it_interval;
|
||||
|
||||
_Objects_Put( &ptimer->Object );
|
||||
_POSIX_Timer_Release( cpu, &lock_context );
|
||||
return 0;
|
||||
|
||||
#if defined(RTEMS_MULTIPROCESSING)
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
+104
-42
@@ -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 );
|
||||
/* 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 );
|
||||
|
||||
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;
|
||||
/*
|
||||
* 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:
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
+85
-60
@@ -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
|
||||
);
|
||||
static uint32_t _POSIX_signals_Ualarm_interval;
|
||||
|
||||
/*
|
||||
* _POSIX_signals_Ualarm_TSR
|
||||
*/
|
||||
|
||||
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;
|
||||
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_timer = &_POSIX_signals_Ualarm_timer;
|
||||
the_watchdog = &_POSIX_signals_Ualarm_watchdog;
|
||||
ticks_initial = _POSIX_signals_Ualarm_us_to_ticks( useconds );
|
||||
ticks_interval = _POSIX_signals_Ualarm_us_to_ticks( interval );
|
||||
|
||||
_Thread_Disable_dispatch();
|
||||
_ISR_lock_ISR_disable_and_acquire(
|
||||
&_POSIX_signals_Ualarm_lock,
|
||||
&lock_context
|
||||
);
|
||||
|
||||
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.
|
||||
*/
|
||||
cpu = _Watchdog_Get_CPU( the_watchdog );
|
||||
_Watchdog_Per_CPU_acquire_critical( cpu, &lock_context2 );
|
||||
now = cpu->Watchdog.ticks;
|
||||
|
||||
ticks = the_timer->initial;
|
||||
ticks -= (the_timer->stop_time - the_timer->start_time);
|
||||
/* remaining is now in ticks */
|
||||
remaining = (useconds_t) _Watchdog_Cancel(
|
||||
&cpu->Watchdog.Header[ PER_CPU_WATCHDOG_RELATIVE ],
|
||||
the_watchdog,
|
||||
now
|
||||
);
|
||||
|
||||
_Timespec_From_ticks( ticks, &tp );
|
||||
remaining = tp.tv_sec * TOD_MICROSECONDS_PER_SECOND;
|
||||
remaining += tp.tv_nsec / 1000;
|
||||
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;
|
||||
_Watchdog_Per_CPU_release_critical( cpu, &lock_context2 );
|
||||
_ISR_lock_Release_and_ISR_enable(
|
||||
&_POSIX_signals_Ualarm_lock,
|
||||
&lock_context
|
||||
);
|
||||
|
||||
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 ) );
|
||||
}
|
||||
|
||||
_Thread_Enable_dispatch();
|
||||
remaining *= rtems_configuration_get_microseconds_per_tick();
|
||||
|
||||
return remaining;
|
||||
}
|
||||
@@ -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
|
||||
* 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(
|
||||
rtems_id id,
|
||||
void *ignored
|
||||
);
|
||||
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
|
||||
);
|
||||
|
||||
|
||||
@@ -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 in use as an interval
|
||||
* timer which will fire in the clock tick ISR.
|
||||
*/
|
||||
TIMER_INTERVAL,
|
||||
|
||||
/**
|
||||
* 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,
|
||||
|
||||
/**
|
||||
* 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,
|
||||
|
||||
/**
|
||||
* 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_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_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_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_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 =
|
||||
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
|
||||
);
|
||||
|
||||
/**
|
||||
|
||||
File diff suppressed because it is too large.
Load diff
@@ -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 );
|
||||
}
|
||||
|
||||
|
||||
@@ -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 );
|
||||
|
||||
@@ -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 );
|
||||
|
||||
@@ -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 );
|
||||
|
||||
|
||||
@@ -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 );
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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 ) {
|
||||
the_period = RTEMS_CONTAINER_OF( watchdog, Rate_monotonic_Control, Timer );
|
||||
the_thread = the_period->owner;
|
||||
|
||||
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 );
|
||||
_Thread_Disable_dispatch();
|
||||
|
||||
_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;
|
||||
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();
|
||||
}
|
||||
@@ -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;
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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)
|
||||
|
||||
+156
-23
File diff suppressed because it is too large.
Load diff
@@ -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;
|
||||
|
||||
@@ -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
|
||||
);
|
||||
}
|
||||
@@ -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
|
||||
);
|
||||
}
|
||||
@@ -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)
|
||||
|
||||
@@ -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)
|
||||
|
||||
+95
-301
File diff suppressed because it is too large.
Load diff
@@ -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
|
||||
);
|
||||
}
|
||||
@@ -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
|
||||
);
|
||||
}
|
||||
@@ -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();
|
||||
|
||||
@@ -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
|
||||
|
||||
|
||||
@@ -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;
|
||||
|
||||
/**
|
||||
|
||||
@@ -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 );
|
||||
|
||||
@@ -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
|
||||
@@ -225,6 +226,32 @@ typedef struct {
|
||||
#endif /* defined( RTEMS_PROFILING ) */
|
||||
} 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
|
||||
*
|
||||
@@ -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.
|
||||
|
||||
@@ -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 );
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -346,6 +346,15 @@ typedef struct {
|
||||
Thread_queue_Heads *spare_heads;
|
||||
} 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;
|
||||
|
||||
@@ -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,
|
||||
|
||||
@@ -131,15 +131,6 @@ extern "C" {
|
||||
* @brief TOD control.
|
||||
*/
|
||||
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.
|
||||
*
|
||||
@@ -272,14 +263,6 @@ static inline uint32_t _TOD_Seconds_since_epoch( void )
|
||||
return (uint32_t) _Timecounter_Time_second;
|
||||
}
|
||||
|
||||
/**
|
||||
* @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.
|
||||
*
|
||||
|
||||
@@ -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 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.
|
||||
typedef struct {
|
||||
/**
|
||||
* @brief Red-black tree of scheduled watchdogs sorted by expiration time.
|
||||
*/
|
||||
WATCHDOG_BEING_INSERTED,
|
||||
/** This is the state when the watchdog is on a chain, and allowed to fire. */
|
||||
WATCHDOG_ACTIVE
|
||||
} Watchdog_States;
|
||||
RBTree_Control Watchdogs;
|
||||
|
||||
/**
|
||||
* @brief The scheduled watchdog with the earliest expiration time or NULL in
|
||||
* case no watchdog is scheduled.
|
||||
*/
|
||||
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.
|
||||
struct Watchdog_Control {
|
||||
/**
|
||||
* @brief Nodes for the watchdog.
|
||||
*/
|
||||
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.
|
||||
*/
|
||||
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.
|
||||
|
||||
File diff suppressed because it is too large.
Load diff
@@ -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;
|
||||
|
||||
@@ -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();
|
||||
|
||||
@@ -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();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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__ */
|
||||
|
||||
|
||||
@@ -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" );
|
||||
}
|
||||
|
||||
@@ -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:
|
||||
|
||||
@@ -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(
|
||||
|
||||
@@ -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,
|
||||
|
||||
@@ -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 );
|
||||
|
||||
@@ -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 );
|
||||
}
|
||||
@@ -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 );
|
||||
}
|
||||
@@ -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.
|
||||
*
|
||||
* 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
|
||||
@@ -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(
|
||||
Watchdog_Header *header,
|
||||
Watchdog_Control *the_watchdog,
|
||||
ISR_lock_Context *lock_context
|
||||
)
|
||||
{
|
||||
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 );
|
||||
|
||||
while (
|
||||
( next = _Chain_Next( current ) ) != _Chain_Tail( &header->Watchdogs )
|
||||
) {
|
||||
Watchdog_Control *next_watchdog;
|
||||
Watchdog_Interval delta_next;
|
||||
|
||||
next_watchdog = (Watchdog_Control *) next;
|
||||
delta_next = next_watchdog->delta_interval;
|
||||
|
||||
if ( delta < delta_next ) {
|
||||
_Watchdog_Insert_fixup(
|
||||
header,
|
||||
the_watchdog,
|
||||
delta,
|
||||
next_watchdog,
|
||||
delta_next
|
||||
);
|
||||
break;
|
||||
}
|
||||
|
||||
iterator.delta_interval = delta - delta_next;
|
||||
iterator.current = next;
|
||||
|
||||
_Watchdog_Flash( header, lock_context );
|
||||
|
||||
if ( the_watchdog->state != WATCHDOG_BEING_INSERTED ) {
|
||||
goto abort_insert;
|
||||
}
|
||||
|
||||
delta = iterator.delta_interval;
|
||||
current = iterator.current;
|
||||
}
|
||||
|
||||
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
|
||||
Watchdog_Control *the_watchdog,
|
||||
uint64_t expire
|
||||
)
|
||||
{
|
||||
ISR_lock_Context lock_context;
|
||||
RBTree_Node **link;
|
||||
RBTree_Node *parent;
|
||||
RBTree_Node *old_first;
|
||||
RBTree_Node *new_first;
|
||||
|
||||
_Watchdog_Acquire( header, &lock_context );
|
||||
_Watchdog_Insert_locked( header, the_watchdog, &lock_context );
|
||||
_Watchdog_Release( header, &lock_context );
|
||||
_Assert( _Watchdog_Get_state( the_watchdog ) == WATCHDOG_INACTIVE );
|
||||
|
||||
link = _RBTree_Root_reference( &header->Watchdogs );
|
||||
parent = NULL;
|
||||
old_first = header->first;
|
||||
new_first = &the_watchdog->Node.RBTree;
|
||||
|
||||
the_watchdog->expire = expire;
|
||||
|
||||
while ( *link != NULL ) {
|
||||
Watchdog_Control *parent_watchdog;
|
||||
|
||||
parent = *link;
|
||||
parent_watchdog = (Watchdog_Control *) parent;
|
||||
|
||||
if ( expire < parent_watchdog->expire ) {
|
||||
link = _RBTree_Left_reference( parent );
|
||||
} else {
|
||||
link = _RBTree_Right_reference( parent );
|
||||
new_first = old_first;
|
||||
}
|
||||
}
|
||||
|
||||
header->first = new_first;
|
||||
_RBTree_Add_child( &the_watchdog->Node.RBTree, parent, link );
|
||||
_RBTree_Insert_color( &header->Watchdogs, &the_watchdog->Node.RBTree );
|
||||
}
|
||||
@@ -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 );
|
||||
}
|
||||
@@ -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>
|
||||
#include <rtems/score/schedulerimpl.h>
|
||||
#include <rtems/score/threaddispatch.h>
|
||||
#include <rtems/score/todimpl.h>
|
||||
#include <rtems/score/watchdogimpl.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/timecounter.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_Tickle_ticks();
|
||||
|
||||
_Scheduler_Tick();
|
||||
++_Watchdog_Ticks_since_boot;
|
||||
}
|
||||
|
||||
_ISR_lock_ISR_disable_and_acquire( &cpu->Watchdog.Lock, &lock_context );
|
||||
|
||||
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 );
|
||||
}
|
||||
@@ -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 */
|
||||
|
||||
|
||||
@@ -14,6 +14,7 @@ SUBDIRS += smpatomic01
|
||||
SUBDIRS += smpcache01
|
||||
SUBDIRS += smpcapture01
|
||||
SUBDIRS += smpcapture02
|
||||
SUBDIRS += smpclock01
|
||||
SUBDIRS += smpfatal01
|
||||
SUBDIRS += smpfatal02
|
||||
SUBDIRS += smpfatal03
|
||||
|
||||
@@ -69,6 +69,7 @@ smpatomic01/Makefile
|
||||
smpcache01/Makefile
|
||||
smpcapture01/Makefile
|
||||
smpcapture02/Makefile
|
||||
smpclock01/Makefile
|
||||
smpfatal01/Makefile
|
||||
smpfatal02/Makefile
|
||||
smpfatal03/Makefile
|
||||
|
||||
@@ -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
|
||||
File diff suppressed because it is too large.
Load diff
@@ -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.
|
||||
@@ -0,0 +1,2 @@
|
||||
*** BEGIN OF TEST SMPCLOCK 1 ***
|
||||
*** END OF TEST SMPCLOCK 1 ***
|
||||
File diff suppressed because it is too large.
Load diff
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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 );
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -14,6 +14,7 @@
|
||||
#include <tmacros.h>
|
||||
#include <intrcritical.h>
|
||||
|
||||
#include <rtems/score/threadimpl.h>
|
||||
#include <rtems/score/threadimpl.h>
|
||||
#include <rtems/score/watchdogimpl.h>
|
||||
|
||||
@@ -37,23 +38,21 @@ static rtems_timer_service_routine test_release_from_isr(
|
||||
void *arg
|
||||
)
|
||||
{
|
||||
Watchdog_Header *header = &_Watchdog_Ticks_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_Is_empty( header ) ) {
|
||||
Watchdog_Control *watchdog = _Watchdog_First( header );
|
||||
if (
|
||||
watchdog != NULL
|
||||
&& watchdog->expire == cpu_self->Watchdog.ticks
|
||||
&& watchdog->routine == _Thread_Timeout
|
||||
) {
|
||||
_Watchdog_Per_CPU_remove( watchdog, cpu_self, header );
|
||||
|
||||
if (
|
||||
watchdog->delta_interval == 0
|
||||
&& watchdog->routine == _Thread_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 ( is_interrupt_timeout() ) {
|
||||
case_hit = true;
|
||||
}
|
||||
if ( is_interrupt_timeout() ) {
|
||||
case_hit = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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 );
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -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
|
||||
@@ -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>
|
||||
@@ -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.
|
||||
@@ -1,2 +0,0 @@
|
||||
*** TEST INTERRUPT CRITICAL SECTION 17 ***
|
||||
*** END OF INTERRUPT CRITICAL SECTION 17 ***
|
||||
@@ -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:
|
||||
|
||||
@@ -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);
|
||||
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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
|
||||
@@ -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>
|
||||
@@ -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().
|
||||
@@ -0,0 +1,2 @@
|
||||
*** BEGIN OF TEST SPTIMERSERVER 1 ***
|
||||
*** END OF TEST SPTIMERSERVER 1 ***
|
||||
File diff suppressed because it is too large.
Load diff
@@ -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>
|
||||
Reference in new issue
Block a user